Index: head/bin/dd/dd.c =================================================================== --- head/bin/dd/dd.c (revision 335394) +++ head/bin/dd/dd.c (revision 335395) @@ -1,609 +1,609 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Keith Muller of the University of California, San Diego and Lance * Visser of Convex Computer Corporation. * * 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. */ #if 0 #ifndef lint static char const copyright[] = "@(#) Copyright (c) 1991, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dd.h" #include "extern.h" static void dd_close(void); static void dd_in(void); static void getfdtype(IO *); static void setup(void); IO in, out; /* input/output state */ STAT st; /* statistics */ void (*cfunc)(void); /* conversion function */ uintmax_t cpy_cnt; /* # of blocks to copy */ static off_t pending = 0; /* pending seek if sparse */ u_int ddflags = 0; /* conversion options */ size_t cbsz; /* conversion block size */ uintmax_t files_cnt = 1; /* # of files to copy */ const u_char *ctab; /* conversion table */ char fill_char; /* Character to fill with if defined */ size_t speed = 0; /* maximum speed, in bytes per second */ volatile sig_atomic_t need_summary; int main(int argc __unused, char *argv[]) { (void)setlocale(LC_CTYPE, ""); jcl(argv); setup(); caph_cache_catpages(); - if (cap_enter() == -1 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "unable to enter capability mode"); (void)signal(SIGINFO, siginfo_handler); (void)signal(SIGINT, terminate); atexit(summary); while (files_cnt--) dd_in(); dd_close(); /* * Some devices such as cfi(4) may perform significant amounts * of work when a write descriptor is closed. Close the out * descriptor explicitly so that the summary handler (called * from an atexit() hook) includes this work. */ close(out.fd); exit(0); } static int parity(u_char c) { int i; i = c ^ (c >> 1) ^ (c >> 2) ^ (c >> 3) ^ (c >> 4) ^ (c >> 5) ^ (c >> 6) ^ (c >> 7); return (i & 1); } static void setup(void) { u_int cnt; cap_rights_t rights; unsigned long cmds[] = { FIODTYPE, MTIOCTOP }; if (in.name == NULL) { in.name = "stdin"; in.fd = STDIN_FILENO; } else { in.fd = open(in.name, O_RDONLY, 0); if (in.fd == -1) err(1, "%s", in.name); } getfdtype(&in); cap_rights_init(&rights, CAP_READ, CAP_SEEK); if (cap_rights_limit(in.fd, &rights) == -1 && errno != ENOSYS) err(1, "unable to limit capability rights"); if (files_cnt > 1 && !(in.flags & ISTAPE)) errx(1, "files is not supported for non-tape devices"); cap_rights_set(&rights, CAP_FTRUNCATE, CAP_IOCTL, CAP_WRITE); if (out.name == NULL) { /* No way to check for read access here. */ out.fd = STDOUT_FILENO; out.name = "stdout"; } else { #define OFLAGS \ (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC)) out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE); /* * May not have read access, so try again with write only. * Without read we may have a problem if output also does * not support seeks. */ if (out.fd == -1) { out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE); out.flags |= NOREAD; cap_rights_clear(&rights, CAP_READ); } if (out.fd == -1) err(1, "%s", out.name); } getfdtype(&out); if (cap_rights_limit(out.fd, &rights) == -1 && errno != ENOSYS) err(1, "unable to limit capability rights"); if (cap_ioctls_limit(out.fd, cmds, nitems(cmds)) == -1 && errno != ENOSYS) err(1, "unable to limit capability rights"); if (in.fd != STDIN_FILENO && out.fd != STDIN_FILENO) { if (caph_limit_stdin() == -1) err(1, "unable to limit capability rights"); } if (in.fd != STDOUT_FILENO && out.fd != STDOUT_FILENO) { if (caph_limit_stdout() == -1) err(1, "unable to limit capability rights"); } if (in.fd != STDERR_FILENO && out.fd != STDERR_FILENO) { if (caph_limit_stderr() == -1) err(1, "unable to limit capability rights"); } /* * Allocate space for the input and output buffers. If not doing * record oriented I/O, only need a single buffer. */ if (!(ddflags & (C_BLOCK | C_UNBLOCK))) { if ((in.db = malloc((size_t)out.dbsz + in.dbsz - 1)) == NULL) err(1, "input buffer"); out.db = in.db; } else if ((in.db = malloc(MAX((size_t)in.dbsz, cbsz) + cbsz)) == NULL || (out.db = malloc(out.dbsz + cbsz)) == NULL) err(1, "output buffer"); /* dbp is the first free position in each buffer. */ in.dbp = in.db; out.dbp = out.db; /* Position the input/output streams. */ if (in.offset) pos_in(); if (out.offset) pos_out(); /* * Truncate the output file. If it fails on a type of output file * that it should _not_ fail on, error out. */ if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK) && out.flags & ISTRUNC) if (ftruncate(out.fd, out.offset * out.dbsz) == -1) err(1, "truncating %s", out.name); if (ddflags & (C_LCASE | C_UCASE | C_ASCII | C_EBCDIC | C_PARITY)) { if (ctab != NULL) { for (cnt = 0; cnt <= 0377; ++cnt) casetab[cnt] = ctab[cnt]; } else { for (cnt = 0; cnt <= 0377; ++cnt) casetab[cnt] = cnt; } if ((ddflags & C_PARITY) && !(ddflags & C_ASCII)) { /* * If the input is not EBCDIC, and we do parity * processing, strip input parity. */ for (cnt = 200; cnt <= 0377; ++cnt) casetab[cnt] = casetab[cnt & 0x7f]; } if (ddflags & C_LCASE) { for (cnt = 0; cnt <= 0377; ++cnt) casetab[cnt] = tolower(casetab[cnt]); } else if (ddflags & C_UCASE) { for (cnt = 0; cnt <= 0377; ++cnt) casetab[cnt] = toupper(casetab[cnt]); } if ((ddflags & C_PARITY)) { /* * This should strictly speaking be a no-op, but I * wonder what funny LANG settings could get us. */ for (cnt = 0; cnt <= 0377; ++cnt) casetab[cnt] = casetab[cnt] & 0x7f; } if ((ddflags & C_PARSET)) { for (cnt = 0; cnt <= 0377; ++cnt) casetab[cnt] = casetab[cnt] | 0x80; } if ((ddflags & C_PAREVEN)) { for (cnt = 0; cnt <= 0377; ++cnt) if (parity(casetab[cnt])) casetab[cnt] = casetab[cnt] | 0x80; } if ((ddflags & C_PARODD)) { for (cnt = 0; cnt <= 0377; ++cnt) if (!parity(casetab[cnt])) casetab[cnt] = casetab[cnt] | 0x80; } ctab = casetab; } if (clock_gettime(CLOCK_MONOTONIC, &st.start)) err(1, "clock_gettime"); } static void getfdtype(IO *io) { struct stat sb; int type; if (fstat(io->fd, &sb) == -1) err(1, "%s", io->name); if (S_ISREG(sb.st_mode)) io->flags |= ISTRUNC; if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) { if (ioctl(io->fd, FIODTYPE, &type) == -1) { err(1, "%s", io->name); } else { if (type & D_TAPE) io->flags |= ISTAPE; else if (type & (D_DISK | D_MEM)) io->flags |= ISSEEK; if (S_ISCHR(sb.st_mode) && (type & D_TAPE) == 0) io->flags |= ISCHR; } return; } errno = 0; if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) io->flags |= ISPIPE; else io->flags |= ISSEEK; } /* * Limit the speed by adding a delay before every block read. * The delay (t_usleep) is equal to the time computed from block * size and the specified speed limit (t_target) minus the time * spent on actual read and write operations (t_io). */ static void speed_limit(void) { static double t_prev, t_usleep; double t_now, t_io, t_target; t_now = secs_elapsed(); t_io = t_now - t_prev - t_usleep; t_target = (double)in.dbsz / (double)speed; t_usleep = t_target - t_io; if (t_usleep > 0) usleep(t_usleep * 1000000); else t_usleep = 0; t_prev = t_now; } static void swapbytes(void *v, size_t len) { unsigned char *p = v; unsigned char t; while (len > 1) { t = p[0]; p[0] = p[1]; p[1] = t; p += 2; len -= 2; } } static void dd_in(void) { ssize_t n; for (;;) { switch (cpy_cnt) { case -1: /* count=0 was specified */ return; case 0: break; default: if (st.in_full + st.in_part >= (uintmax_t)cpy_cnt) return; break; } if (speed > 0) speed_limit(); /* * Zero the buffer first if sync; if doing block operations, * use spaces. */ if (ddflags & C_SYNC) { if (ddflags & C_FILL) memset(in.dbp, fill_char, in.dbsz); else if (ddflags & (C_BLOCK | C_UNBLOCK)) memset(in.dbp, ' ', in.dbsz); else memset(in.dbp, 0, in.dbsz); } n = read(in.fd, in.dbp, in.dbsz); if (n == 0) { in.dbrcnt = 0; return; } /* Read error. */ if (n == -1) { /* * If noerror not specified, die. POSIX requires that * the warning message be followed by an I/O display. */ if (!(ddflags & C_NOERROR)) err(1, "%s", in.name); warn("%s", in.name); summary(); /* * If it's a seekable file descriptor, seek past the * error. If your OS doesn't do the right thing for * raw disks this section should be modified to re-read * in sector size chunks. */ if (in.flags & ISSEEK && lseek(in.fd, (off_t)in.dbsz, SEEK_CUR)) warn("%s", in.name); /* If sync not specified, omit block and continue. */ if (!(ddflags & C_SYNC)) continue; /* Read errors count as full blocks. */ in.dbcnt += in.dbrcnt = in.dbsz; ++st.in_full; /* Handle full input blocks. */ } else if ((size_t)n == (size_t)in.dbsz) { in.dbcnt += in.dbrcnt = n; ++st.in_full; /* Handle partial input blocks. */ } else { /* If sync, use the entire block. */ if (ddflags & C_SYNC) in.dbcnt += in.dbrcnt = in.dbsz; else in.dbcnt += in.dbrcnt = n; ++st.in_part; } /* * POSIX states that if bs is set and no other conversions * than noerror, notrunc or sync are specified, the block * is output without buffering as it is read. */ if ((ddflags & ~(C_NOERROR | C_NOTRUNC | C_SYNC)) == C_BS) { out.dbcnt = in.dbcnt; dd_out(1); in.dbcnt = 0; continue; } if (ddflags & C_SWAB) { if ((n = in.dbrcnt) & 1) { ++st.swab; --n; } swapbytes(in.dbp, (size_t)n); } in.dbp += in.dbrcnt; (*cfunc)(); if (need_summary) { summary(); } } } /* * Clean up any remaining I/O and flush output. If necessary, the output file * is truncated. */ static void dd_close(void) { if (cfunc == def) def_close(); else if (cfunc == block) block_close(); else if (cfunc == unblock) unblock_close(); if (ddflags & C_OSYNC && out.dbcnt && out.dbcnt < out.dbsz) { if (ddflags & C_FILL) memset(out.dbp, fill_char, out.dbsz - out.dbcnt); else if (ddflags & (C_BLOCK | C_UNBLOCK)) memset(out.dbp, ' ', out.dbsz - out.dbcnt); else memset(out.dbp, 0, out.dbsz - out.dbcnt); out.dbcnt = out.dbsz; } if (out.dbcnt || pending) dd_out(1); /* * If the file ends with a hole, ftruncate it to extend its size * up to the end of the hole (without having to write any data). */ if (out.seek_offset > 0 && (out.flags & ISTRUNC)) { if (ftruncate(out.fd, out.seek_offset) == -1) err(1, "truncating %s", out.name); } } void dd_out(int force) { u_char *outp; size_t cnt, i, n; ssize_t nw; static int warned; int sparse; /* * Write one or more blocks out. The common case is writing a full * output block in a single write; increment the full block stats. * Otherwise, we're into partial block writes. If a partial write, * and it's a character device, just warn. If a tape device, quit. * * The partial writes represent two cases. 1: Where the input block * was less than expected so the output block was less than expected. * 2: Where the input block was the right size but we were forced to * write the block in multiple chunks. The original versions of dd(1) * never wrote a block in more than a single write, so the latter case * never happened. * * One special case is if we're forced to do the write -- in that case * we play games with the buffer size, and it's usually a partial write. */ outp = out.db; /* * If force, first try to write all pending data, else try to write * just one block. Subsequently always write data one full block at * a time at most. */ for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { cnt = n; do { sparse = 0; if (ddflags & C_SPARSE) { sparse = 1; /* Is buffer sparse? */ for (i = 0; i < cnt; i++) if (outp[i] != 0) { sparse = 0; break; } } if (sparse && !force) { pending += cnt; nw = cnt; } else { if (pending != 0) { /* * Seek past hole. Note that we need to record the * reached offset, because we might have no more data * to write, in which case we'll need to call * ftruncate to extend the file size. */ out.seek_offset = lseek(out.fd, pending, SEEK_CUR); if (out.seek_offset == -1) err(2, "%s: seek error creating sparse file", out.name); pending = 0; } if (cnt) { nw = write(out.fd, outp, cnt); out.seek_offset = 0; } else { return; } } if (nw <= 0) { if (nw == 0) errx(1, "%s: end of device", out.name); if (errno != EINTR) err(1, "%s", out.name); nw = 0; } outp += nw; st.bytes += nw; if ((size_t)nw == n && n == (size_t)out.dbsz) ++st.out_full; else ++st.out_part; if ((size_t) nw != cnt) { if (out.flags & ISTAPE) errx(1, "%s: short write on tape device", out.name); if (out.flags & ISCHR && !warned) { warned = 1; warnx("%s: short write on character device", out.name); } } cnt -= nw; } while (cnt != 0); if ((out.dbcnt -= n) < out.dbsz) break; } /* Reassemble the output block. */ if (out.dbcnt) (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt); out.dbp = out.db + out.dbcnt; } Index: head/bin/echo/echo.c =================================================================== --- head/bin/echo/echo.c (revision 335394) +++ head/bin/echo/echo.c (revision 335395) @@ -1,144 +1,144 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * 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. 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. */ #if 0 #ifndef lint static char const copyright[] = "@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)echo.c 8.1 (Berkeley) 5/31/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include /* * Report an error and exit. * Use it instead of err(3) to avoid linking-in stdio. */ static __dead2 void errexit(const char *prog, const char *reason) { char *errstr = strerror(errno); write(STDERR_FILENO, prog, strlen(prog)); write(STDERR_FILENO, ": ", 2); write(STDERR_FILENO, reason, strlen(reason)); write(STDERR_FILENO, ": ", 2); write(STDERR_FILENO, errstr, strlen(errstr)); write(STDERR_FILENO, "\n", 1); exit(1); } int main(int argc, char *argv[]) { int nflag; /* if not set, output a trailing newline. */ int veclen; /* number of writev arguments. */ struct iovec *iov, *vp; /* Elements to write, current element. */ char space[] = " "; char newline[] = "\n"; char *progname = argv[0]; - if (caph_limit_stdio() < 0 || (cap_enter() < 0 && errno != ENOSYS)) + if (caph_limit_stdio() < 0 || caph_enter() < 0) err(1, "capsicum"); /* This utility may NOT do getopt(3) option parsing. */ if (*++argv && !strcmp(*argv, "-n")) { ++argv; --argc; nflag = 1; } else nflag = 0; veclen = (argc >= 2) ? (argc - 2) * 2 + 1 : 0; if ((vp = iov = malloc((veclen + 1) * sizeof(struct iovec))) == NULL) errexit(progname, "malloc"); while (argv[0] != NULL) { size_t len; len = strlen(argv[0]); /* * If the next argument is NULL then this is this * the last argument, therefore we need to check * for a trailing \c. */ if (argv[1] == NULL) { /* is there room for a '\c' and is there one? */ if (len >= 2 && argv[0][len - 2] == '\\' && argv[0][len - 1] == 'c') { /* chop it and set the no-newline flag. */ len -= 2; nflag = 1; } } vp->iov_base = *argv; vp++->iov_len = len; if (*++argv) { vp->iov_base = space; vp++->iov_len = 1; } } if (!nflag) { veclen++; vp->iov_base = newline; vp++->iov_len = 1; } /* assert(veclen == (vp - iov)); */ while (veclen) { int nwrite; nwrite = (veclen > IOV_MAX) ? IOV_MAX : veclen; if (writev(STDOUT_FILENO, iov, nwrite) == -1) errexit(progname, "write"); iov += nwrite; veclen -= nwrite; } return 0; } Index: head/bin/sleep/sleep.c =================================================================== --- head/bin/sleep/sleep.c (revision 335394) +++ head/bin/sleep/sleep.c (revision 335395) @@ -1,113 +1,113 @@ /*- * Copyright (c) 1988, 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. */ #if 0 #ifndef lint static char const copyright[] = "@(#) Copyright (c) 1988, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)sleep.c 8.3 (Berkeley) 4/2/94"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include static void usage(void); static volatile sig_atomic_t report_requested; static void report_request(int signo __unused) { report_requested = 1; } int main(int argc, char *argv[]) { struct timespec time_to_sleep; double d; time_t original; char buf[2]; - if (caph_limit_stdio() < 0 || (cap_enter() < 0 && errno != ENOSYS)) + if (caph_limit_stdio() < 0 || caph_enter() < 0) err(1, "capsicum"); if (argc != 2) usage(); if (sscanf(argv[1], "%lf%1s", &d, buf) != 1) usage(); if (d > INT_MAX) usage(); if (d <= 0) return (0); original = time_to_sleep.tv_sec = (time_t)d; time_to_sleep.tv_nsec = 1e9 * (d - time_to_sleep.tv_sec); signal(SIGINFO, report_request); /* * Note: [EINTR] is supposed to happen only when a signal was handled * but the kernel also returns it when a ptrace-based debugger * attaches. This is a bug but it is hard to fix. */ while (nanosleep(&time_to_sleep, &time_to_sleep) != 0) { if (report_requested) { /* Reporting does not bother with nanoseconds. */ warnx("about %d second(s) left out of the original %d", (int)time_to_sleep.tv_sec, (int)original); report_requested = 0; } else if (errno != EINTR) err(1, "nanosleep"); } return (0); } static void usage(void) { fprintf(stderr, "usage: sleep seconds\n"); exit(1); } Index: head/bin/uuidgen/uuidgen.c =================================================================== --- head/bin/uuidgen/uuidgen.c (revision 335394) +++ head/bin/uuidgen/uuidgen.c (revision 335395) @@ -1,124 +1,124 @@ /* * Copyright (c) 2002 Marcel Moolenaar * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include static void usage(void) { (void)fprintf(stderr, "usage: uuidgen [-1] [-n count] [-o filename]\n"); exit(1); } int main(int argc, char *argv[]) { FILE *fp; uuid_t *store, *uuid; char *p; int ch, count, i, iterate, status; count = -1; /* no count yet */ fp = stdout; /* default output file */ iterate = 0; /* not one at a time */ while ((ch = getopt(argc, argv, "1n:o:")) != -1) switch (ch) { case '1': iterate = 1; break; case 'n': if (count > 0) usage(); count = strtol(optarg, &p, 10); if (*p != 0 || count < 1) usage(); break; case 'o': if (fp != stdout) errx(1, "multiple output files not allowed"); fp = fopen(optarg, "w"); if (fp == NULL) err(1, "fopen"); break; default: usage(); } argv += optind; argc -= optind; if (argc) usage(); caph_cache_catpages(); if (caph_limit_stdio() < 0) err(1, "Unable to limit stdio"); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "Unable to enter capability mode"); if (count == -1) count = 1; store = (uuid_t*)malloc(sizeof(uuid_t) * count); if (store == NULL) err(1, "malloc()"); if (!iterate) { /* Get them all in a single batch */ if (uuidgen(store, count) != 0) err(1, "uuidgen()"); } else { uuid = store; for (i = 0; i < count; i++) { if (uuidgen(uuid++, 1) != 0) err(1, "uuidgen()"); } } uuid = store; while (count--) { uuid_to_string(uuid++, &p, &status); if (status != uuid_s_ok) err(1, "cannot stringify a UUID"); fprintf(fp, "%s\n", p); free(p); } free(store); if (fp != stdout) fclose(fp); return (0); } Index: head/contrib/dma/dma-mbox-create.c =================================================================== --- head/contrib/dma/dma-mbox-create.c (revision 335394) +++ head/contrib/dma/dma-mbox-create.c (revision 335395) @@ -1,191 +1,191 @@ /* * Copyright (c) 2010-2014, Simon Schubert <2@0x2c.org>. * Copyright (c) 2008 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project * by Simon Schubert <2@0x2c.org>. * * 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. */ /* * This binary is setuid root. Use extreme caution when touching * user-supplied information. Keep the root window as small as possible. */ #ifdef __FreeBSD__ #define USE_CAPSICUM 1 #endif #include #if USE_CAPSICUM #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "dma.h" static void logfail(int exitcode, const char *fmt, ...) { int oerrno = errno; va_list ap; char outs[1024]; 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, errno ? "%s: %m" : "%s", outs); else syslog(LOG_ERR, errno ? "%m" : "unknown error"); exit(exitcode); } /* * Create a mbox in /var/mail for a given user, or make sure * the permissions are correct for dma. */ int main(int argc, char **argv) { #if USE_CAPSICUM cap_rights_t rights; #endif const char *user; struct passwd *pw; struct group *gr; uid_t user_uid; gid_t mail_gid; int f, maildirfd; /* * Open log fd now for capability sandbox. */ openlog("dma-mbox-create", LOG_NDELAY, LOG_MAIL); errno = 0; gr = getgrnam(DMA_GROUP); if (!gr) logfail(EX_CONFIG, "cannot find dma group `%s'", DMA_GROUP); mail_gid = gr->gr_gid; if (setgid(mail_gid) != 0) logfail(EX_NOPERM, "cannot set gid to %d (%s)", mail_gid, DMA_GROUP); if (getegid() != mail_gid) logfail(EX_NOPERM, "cannot set gid to %d (%s), still at %d", mail_gid, DMA_GROUP, getegid()); /* * We take exactly one argument: the username. */ if (argc != 2) { errno = 0; logfail(EX_USAGE, "no arguments"); } user = argv[1]; syslog(LOG_NOTICE, "creating mbox for `%s'", user); /* the username may not contain a pathname separator */ if (strchr(user, '/')) { errno = 0; logfail(EX_DATAERR, "path separator in username `%s'", user); exit(1); } /* verify the user exists */ errno = 0; pw = getpwnam(user); if (!pw) logfail(EX_NOUSER, "cannot find user `%s'", user); maildirfd = open(_PATH_MAILDIR, O_RDONLY); if (maildirfd < 0) logfail(EX_NOINPUT, "cannot open maildir %s", _PATH_MAILDIR); /* * Cache NLS data, for strerror, for err(3), before entering capability * mode. */ caph_cache_catpages(); /* * Cache local time before entering Capsicum capability sandbox. */ caph_cache_tzdata(); #if USE_CAPSICUM cap_rights_init(&rights, CAP_CREATE, CAP_FCHMOD, CAP_FCHOWN, CAP_LOOKUP, CAP_READ); if (cap_rights_limit(maildirfd, &rights) < 0 && errno != ENOSYS) err(EX_OSERR, "can't limit maildirfd rights"); /* Enter Capsicum capability sandbox */ - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(EX_OSERR, "cap_enter"); #endif user_uid = pw->pw_uid; f = openat(maildirfd, user, O_RDONLY|O_CREAT|O_NOFOLLOW, 0600); if (f < 0) logfail(EX_NOINPUT, "cannot open mbox `%s'", user); if (fchown(f, user_uid, mail_gid)) logfail(EX_OSERR, "cannot change owner of mbox `%s'", user); if (fchmod(f, 0620)) logfail(EX_OSERR, "cannot change permissions of mbox `%s'", user); /* file should be present with the right owner and permissions */ syslog(LOG_NOTICE, "successfully created mbox for `%s'", user); return (0); } Index: head/sbin/decryptcore/decryptcore.c =================================================================== --- head/sbin/decryptcore/decryptcore.c (revision 335394) +++ head/sbin/decryptcore/decryptcore.c (revision 335395) @@ -1,387 +1,388 @@ /*- * Copyright (c) 2016 Konrad Witaszczyk * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include "pjdlog.h" #define DECRYPTCORE_CRASHDIR "/var/crash" static void usage(void) { pjdlog_exitx(1, "usage: decryptcore [-fLv] -p privatekeyfile -k keyfile -e encryptedcore -c core\n" " decryptcore [-fLv] [-d crashdir] -p privatekeyfile -n dumpnr"); } static int wait_for_process(pid_t pid) { int status; if (waitpid(pid, &status, WUNTRACED | WEXITED) == -1) { pjdlog_errno(LOG_ERR, "Unable to wait for a child process"); return (1); } if (WIFEXITED(status)) return (WEXITSTATUS(status)); return (1); } static struct kerneldumpkey * read_key(int kfd) { struct kerneldumpkey *kdk; ssize_t size; size_t kdksize; PJDLOG_ASSERT(kfd >= 0); kdksize = sizeof(*kdk); kdk = calloc(1, kdksize); if (kdk == NULL) { pjdlog_errno(LOG_ERR, "Unable to allocate kernel dump key"); goto failed; } size = read(kfd, kdk, kdksize); if (size == (ssize_t)kdksize) { kdk->kdk_encryptedkeysize = dtoh32(kdk->kdk_encryptedkeysize); kdksize += (size_t)kdk->kdk_encryptedkeysize; kdk = realloc(kdk, kdksize); if (kdk == NULL) { pjdlog_errno(LOG_ERR, "Unable to reallocate kernel dump key"); goto failed; } size += read(kfd, &kdk->kdk_encryptedkey, kdk->kdk_encryptedkeysize); } if (size != (ssize_t)kdksize) { pjdlog_errno(LOG_ERR, "Unable to read key"); goto failed; } return (kdk); failed: free(kdk); return (NULL); } static bool decrypt(int ofd, const char *privkeyfile, const char *keyfile, const char *input) { uint8_t buf[KERNELDUMP_BUFFER_SIZE], key[KERNELDUMP_KEY_MAX_SIZE]; EVP_CIPHER_CTX ctx; const EVP_CIPHER *cipher; FILE *fp; struct kerneldumpkey *kdk; RSA *privkey; int ifd, kfd, olen, privkeysize; ssize_t bytes; pid_t pid; PJDLOG_ASSERT(ofd >= 0); PJDLOG_ASSERT(privkeyfile != NULL); PJDLOG_ASSERT(keyfile != NULL); PJDLOG_ASSERT(input != NULL); privkey = NULL; /* * Decrypt a core dump in a child process so we can unlink a partially * decrypted core if the child process fails. */ pid = fork(); if (pid == -1) { pjdlog_errno(LOG_ERR, "Unable to create child process"); close(ofd); return (false); } if (pid > 0) { close(ofd); return (wait_for_process(pid) == 0); } kfd = open(keyfile, O_RDONLY); if (kfd == -1) { pjdlog_errno(LOG_ERR, "Unable to open %s", keyfile); goto failed; } ifd = open(input, O_RDONLY); if (ifd == -1) { pjdlog_errno(LOG_ERR, "Unable to open %s", input); goto failed; } fp = fopen(privkeyfile, "r"); if (fp == NULL) { pjdlog_errno(LOG_ERR, "Unable to open %s", privkeyfile); goto failed; } - if (cap_enter() < 0 && errno != ENOSYS) { + if (caph_enter() < 0) { pjdlog_errno(LOG_ERR, "Unable to enter capability mode"); goto failed; } privkey = RSA_new(); if (privkey == NULL) { pjdlog_error("Unable to allocate an RSA structure: %s", ERR_error_string(ERR_get_error(), NULL)); goto failed; } EVP_CIPHER_CTX_init(&ctx); kdk = read_key(kfd); close(kfd); if (kdk == NULL) goto failed; privkey = PEM_read_RSAPrivateKey(fp, &privkey, NULL, NULL); fclose(fp); if (privkey == NULL) { pjdlog_error("Unable to read data from %s.", privkeyfile); goto failed; } privkeysize = RSA_size(privkey); if (privkeysize != (int)kdk->kdk_encryptedkeysize) { pjdlog_error("RSA modulus size mismatch: equals %db and should be %ub.", 8 * privkeysize, 8 * kdk->kdk_encryptedkeysize); goto failed; } switch (kdk->kdk_encryption) { case KERNELDUMP_ENC_AES_256_CBC: cipher = EVP_aes_256_cbc(); break; default: pjdlog_error("Invalid encryption algorithm."); goto failed; } if (RSA_private_decrypt(kdk->kdk_encryptedkeysize, kdk->kdk_encryptedkey, key, privkey, RSA_PKCS1_PADDING) != sizeof(key)) { pjdlog_error("Unable to decrypt key: %s", ERR_error_string(ERR_get_error(), NULL)); goto failed; } RSA_free(privkey); privkey = NULL; EVP_DecryptInit_ex(&ctx, cipher, NULL, key, kdk->kdk_iv); EVP_CIPHER_CTX_set_padding(&ctx, 0); explicit_bzero(key, sizeof(key)); do { bytes = read(ifd, buf, sizeof(buf)); if (bytes < 0) { pjdlog_errno(LOG_ERR, "Unable to read data from %s", input); goto failed; } if (bytes > 0) { if (EVP_DecryptUpdate(&ctx, buf, &olen, buf, bytes) == 0) { pjdlog_error("Unable to decrypt core."); goto failed; } } else { if (EVP_DecryptFinal_ex(&ctx, buf, &olen) == 0) { pjdlog_error("Unable to decrypt core."); goto failed; } } if (olen > 0 && write(ofd, buf, olen) != olen) { pjdlog_errno(LOG_ERR, "Unable to write core"); goto failed; } } while (bytes > 0); explicit_bzero(buf, sizeof(buf)); EVP_CIPHER_CTX_cleanup(&ctx); exit(0); failed: explicit_bzero(key, sizeof(key)); explicit_bzero(buf, sizeof(buf)); RSA_free(privkey); EVP_CIPHER_CTX_cleanup(&ctx); exit(1); } int main(int argc, char **argv) { char core[PATH_MAX], encryptedcore[PATH_MAX], keyfile[PATH_MAX]; const char *crashdir, *dumpnr, *privatekey; int ch, debug, error, ofd; size_t ii; bool force, usesyslog; error = 1; pjdlog_init(PJDLOG_MODE_STD); pjdlog_prefix_set("(decryptcore) "); debug = 0; *core = '\0'; crashdir = NULL; dumpnr = NULL; *encryptedcore = '\0'; force = false; *keyfile = '\0'; privatekey = NULL; usesyslog = false; while ((ch = getopt(argc, argv, "Lc:d:e:fk:n:p:v")) != -1) { switch (ch) { case 'L': usesyslog = true; break; case 'c': if (strlcpy(core, optarg, sizeof(core)) >= sizeof(core)) pjdlog_exitx(1, "Core file path is too long."); break; case 'd': crashdir = optarg; break; case 'e': if (strlcpy(encryptedcore, optarg, sizeof(encryptedcore)) >= sizeof(encryptedcore)) { pjdlog_exitx(1, "Encrypted core file path is too long."); } break; case 'f': force = true; break; case 'k': if (strlcpy(keyfile, optarg, sizeof(keyfile)) >= sizeof(keyfile)) { pjdlog_exitx(1, "Key file path is too long."); } break; case 'n': dumpnr = optarg; break; case 'p': privatekey = optarg; break; case 'v': debug++; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 0) usage(); /* Verify mutually exclusive options. */ if ((crashdir != NULL || dumpnr != NULL) && (*keyfile != '\0' || *encryptedcore != '\0' || *core != '\0')) { usage(); } /* * Set key, encryptedcore and core file names using crashdir and dumpnr. */ if (dumpnr != NULL) { for (ii = 0; ii < strnlen(dumpnr, PATH_MAX); ii++) { if (isdigit((int)dumpnr[ii]) == 0) usage(); } if (crashdir == NULL) crashdir = DECRYPTCORE_CRASHDIR; PJDLOG_VERIFY(snprintf(keyfile, sizeof(keyfile), "%s/key.%s", crashdir, dumpnr) > 0); PJDLOG_VERIFY(snprintf(core, sizeof(core), "%s/vmcore.%s", crashdir, dumpnr) > 0); PJDLOG_VERIFY(snprintf(encryptedcore, sizeof(encryptedcore), "%s/vmcore_encrypted.%s", crashdir, dumpnr) > 0); } if (privatekey == NULL || *keyfile == '\0' || *encryptedcore == '\0' || *core == '\0') { usage(); } if (usesyslog) pjdlog_mode_set(PJDLOG_MODE_SYSLOG); pjdlog_debug_set(debug); if (force && unlink(core) == -1 && errno != ENOENT) { pjdlog_errno(LOG_ERR, "Unable to remove old core"); goto out; } ofd = open(core, O_WRONLY | O_CREAT | O_EXCL, 0600); if (ofd == -1) { pjdlog_errno(LOG_ERR, "Unable to open %s", core); goto out; } if (!decrypt(ofd, privatekey, keyfile, encryptedcore)) { if (unlink(core) == -1 && errno != ENOENT) pjdlog_errno(LOG_ERR, "Unable to remove core"); goto out; } error = 0; out: pjdlog_fini(); exit(error); } Index: head/sbin/dhclient/dhclient.c =================================================================== --- head/sbin/dhclient/dhclient.c (revision 335394) +++ head/sbin/dhclient/dhclient.c (revision 335395) @@ -1,2829 +1,2831 @@ /* $OpenBSD: dhclient.c,v 1.63 2005/02/06 17:10:13 krw Exp $ */ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright 2004 Henning Brauer * Copyright (c) 1995, 1996, 1997, 1998, 1999 * The Internet Software Consortium. 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie * Enterprises. To learn more about the Internet Software Consortium, * see ``http://www.vix.com/isc''. To learn more about Vixie * Enterprises, see ``http://www.vix.com''. * * This client was substantially modified and enhanced by Elliot Poger * for use on Linux while he was working on the MosquitoNet project at * Stanford. * * The current version owes much to Elliot's Linux enhancements, but * was substantially reorganized and partially rewritten by Ted Lemon * so as to use the same networking framework that the Internet Software * Consortium DHCP server uses. Much system-specific configuration code * was moved into a shell script so that as support for more operating * systems is added, it will not be necessary to port and maintain * system-specific configuration code to these operating systems - instead, * the shell script can invoke the native tools to accomplish the same * purpose. */ #include __FBSDID("$FreeBSD$"); #include "dhcpd.h" #include "privsep.h" #include #include +#include + #include #ifndef _PATH_VAREMPTY #define _PATH_VAREMPTY "/var/empty" #endif #define PERIOD 0x2e #define hyphenchar(c) ((c) == 0x2d) #define bslashchar(c) ((c) == 0x5c) #define periodchar(c) ((c) == PERIOD) #define asterchar(c) ((c) == 0x2a) #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \ ((c) >= 0x61 && (c) <= 0x7a)) #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) #define whitechar(c) ((c) == ' ' || (c) == '\t') #define borderchar(c) (alphachar(c) || digitchar(c)) #define middlechar(c) (borderchar(c) || hyphenchar(c)) #define domainchar(c) ((c) > 0x20 && (c) < 0x7f) #define CLIENT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin" cap_channel_t *capsyslog; time_t cur_time; time_t default_lease_time = 43200; /* 12 hours... */ const char *path_dhclient_conf = _PATH_DHCLIENT_CONF; char *path_dhclient_db = NULL; int log_perror = 1; int privfd; int nullfd = -1; char hostname[_POSIX_HOST_NAME_MAX + 1]; struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; struct in_addr inaddr_any, inaddr_broadcast; char *path_dhclient_pidfile; struct pidfh *pidfile; /* * ASSERT_STATE() does nothing now; it used to be * assert (state_is == state_shouldbe). */ #define ASSERT_STATE(state_is, state_shouldbe) {} /* * We need to check that the expiry, renewal and rebind times are not beyond * the end of time (~2038 when a 32-bit time_t is being used). */ #define TIME_MAX ((((time_t) 1 << (sizeof(time_t) * CHAR_BIT - 2)) - 1) * 2 + 1) int log_priority; int no_daemon; int unknown_ok = 1; int routefd; struct interface_info *ifi; int findproto(char *, int); struct sockaddr *get_ifa(char *, int); void routehandler(struct protocol *); void usage(void); int check_option(struct client_lease *l, int option); int check_classless_option(unsigned char *data, int len); int ipv4addrs(const char * buf); int res_hnok(const char *dn); int check_search(const char *srch); const char *option_as_string(unsigned int code, unsigned char *data, int len); int fork_privchld(int, int); #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) /* Minimum MTU is 68 as per RFC791, p. 24 */ #define MIN_MTU 68 static time_t scripttime; int findproto(char *cp, int n) { struct sockaddr *sa; unsigned i; if (n == 0) return -1; for (i = 1; i; i <<= 1) { if (i & n) { sa = (struct sockaddr *)cp; switch (i) { case RTA_IFA: case RTA_DST: case RTA_GATEWAY: case RTA_NETMASK: if (sa->sa_family == AF_INET) return AF_INET; if (sa->sa_family == AF_INET6) return AF_INET6; break; case RTA_IFP: break; } ADVANCE(cp, sa); } } return (-1); } struct sockaddr * get_ifa(char *cp, int n) { struct sockaddr *sa; unsigned i; if (n == 0) return (NULL); for (i = 1; i; i <<= 1) if (i & n) { sa = (struct sockaddr *)cp; if (i == RTA_IFA) return (sa); ADVANCE(cp, sa); } return (NULL); } struct iaddr defaddr = { .len = 4 }; uint8_t curbssid[6]; static void disassoc(void *arg) { struct interface_info *_ifi = arg; /* * Clear existing state. */ if (_ifi->client->active != NULL) { script_init("EXPIRE", NULL); script_write_params("old_", _ifi->client->active); if (_ifi->client->alias) script_write_params("alias_", _ifi->client->alias); script_go(); } _ifi->client->state = S_INIT; } void routehandler(struct protocol *p __unused) { char msg[2048], *addr; struct rt_msghdr *rtm; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct if_announcemsghdr *ifan; struct ieee80211_join_event *jev; struct client_lease *l; time_t t = time(NULL); struct sockaddr_in *sa; struct iaddr a; ssize_t n; int linkstat; n = read(routefd, &msg, sizeof(msg)); rtm = (struct rt_msghdr *)msg; if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < (ssize_t)rtm->rtm_msglen || rtm->rtm_version != RTM_VERSION) return; switch (rtm->rtm_type) { case RTM_NEWADDR: case RTM_DELADDR: ifam = (struct ifa_msghdr *)rtm; if (ifam->ifam_index != ifi->index) break; if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET) break; if (scripttime == 0 || t < scripttime + 10) break; sa = (struct sockaddr_in*)get_ifa((char *)(ifam + 1), ifam->ifam_addrs); if (sa == NULL) break; if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf)) error("king bula sez: len mismatch"); memcpy(a.iabuf, &sa->sin_addr, a.len); if (addr_eq(a, defaddr)) break; for (l = ifi->client->active; l != NULL; l = l->next) if (addr_eq(a, l->address)) break; if (l == NULL) /* added/deleted addr is not the one we set */ break; addr = inet_ntoa(sa->sin_addr); if (rtm->rtm_type == RTM_NEWADDR) { /* * XXX: If someone other than us adds our address, * should we assume they are taking over from us, * delete the lease record, and exit without modifying * the interface? */ warning("My address (%s) was re-added", addr); } else { warning("My address (%s) was deleted, dhclient exiting", addr); goto die; } break; case RTM_IFINFO: ifm = (struct if_msghdr *)rtm; if (ifm->ifm_index != ifi->index) break; if ((rtm->rtm_flags & RTF_UP) == 0) { warning("Interface %s is down, dhclient exiting", ifi->name); goto die; } linkstat = interface_link_status(ifi->name); if (linkstat != ifi->linkstat) { debug("%s link state %s -> %s", ifi->name, ifi->linkstat ? "up" : "down", linkstat ? "up" : "down"); ifi->linkstat = linkstat; if (linkstat) state_reboot(ifi); } break; case RTM_IFANNOUNCE: ifan = (struct if_announcemsghdr *)rtm; if (ifan->ifan_what == IFAN_DEPARTURE && ifan->ifan_index == ifi->index) { warning("Interface %s is gone, dhclient exiting", ifi->name); goto die; } break; case RTM_IEEE80211: ifan = (struct if_announcemsghdr *)rtm; if (ifan->ifan_index != ifi->index) break; switch (ifan->ifan_what) { case RTM_IEEE80211_ASSOC: case RTM_IEEE80211_REASSOC: /* * Use assoc/reassoc event to kick state machine * in case we roam. Otherwise fall back to the * normal state machine just like a wired network. */ jev = (struct ieee80211_join_event *) &ifan[1]; if (memcmp(curbssid, jev->iev_addr, 6)) { disassoc(ifi); state_reboot(ifi); } memcpy(curbssid, jev->iev_addr, 6); break; } break; default: break; } return; die: script_init("FAIL", NULL); if (ifi->client->alias) script_write_params("alias_", ifi->client->alias); script_go(); if (pidfile != NULL) pidfile_remove(pidfile); exit(1); } static void init_casper(void) { cap_channel_t *casper; casper = cap_init(); if (casper == NULL) error("unable to start casper"); capsyslog = cap_service_open(casper, "system.syslog"); cap_close(casper); if (capsyslog == NULL) error("unable to open system.syslog service"); } int main(int argc, char *argv[]) { extern char *__progname; int ch, fd, quiet = 0, i = 0; int pipe_fd[2]; int immediate_daemon = 0; struct passwd *pw; pid_t otherpid; cap_rights_t rights; init_casper(); /* Initially, log errors to stderr as well as to syslogd. */ cap_openlog(capsyslog, __progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY); cap_setlogmask(capsyslog, LOG_UPTO(LOG_DEBUG)); while ((ch = getopt(argc, argv, "bc:dl:p:qu")) != -1) switch (ch) { case 'b': immediate_daemon = 1; break; case 'c': path_dhclient_conf = optarg; break; case 'd': no_daemon = 1; break; case 'l': path_dhclient_db = optarg; break; case 'p': path_dhclient_pidfile = optarg; break; case 'q': quiet = 1; break; case 'u': unknown_ok = 0; break; default: usage(); } argc -= optind; argv += optind; if (argc != 1) usage(); if (path_dhclient_pidfile == NULL) { asprintf(&path_dhclient_pidfile, "%sdhclient.%s.pid", _PATH_VARRUN, *argv); if (path_dhclient_pidfile == NULL) error("asprintf"); } pidfile = pidfile_open(path_dhclient_pidfile, 0644, &otherpid); if (pidfile == NULL) { if (errno == EEXIST) error("dhclient already running, pid: %d.", otherpid); if (errno == EAGAIN) error("dhclient already running."); warning("Cannot open or create pidfile: %m"); } if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL) error("calloc"); if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ) error("Interface name too long"); if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s", _PATH_DHCLIENT_DB, ifi->name) == -1) error("asprintf"); if (quiet) log_perror = 0; tzset(); time(&cur_time); inaddr_broadcast.s_addr = INADDR_BROADCAST; inaddr_any.s_addr = INADDR_ANY; read_client_conf(); /* The next bit is potentially very time-consuming, so write out the pidfile right away. We will write it out again with the correct pid after daemonizing. */ if (pidfile != NULL) pidfile_write(pidfile); if (!interface_link_status(ifi->name)) { fprintf(stderr, "%s: no link ...", ifi->name); fflush(stderr); sleep(1); while (!interface_link_status(ifi->name)) { fprintf(stderr, "."); fflush(stderr); if (++i > 10) { fprintf(stderr, " giving up\n"); exit(1); } sleep(1); } fprintf(stderr, " got link\n"); } ifi->linkstat = 1; if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) error("cannot open %s: %m", _PATH_DEVNULL); if ((pw = getpwnam("_dhcp")) == NULL) { warning("no such user: _dhcp, falling back to \"nobody\""); if ((pw = getpwnam("nobody")) == NULL) error("no such user: nobody"); } /* * Obtain hostname before entering capability mode - it won't be * possible then, as reading kern.hostname is not permitted. */ if (gethostname(hostname, sizeof(hostname)) < 0) hostname[0] = '\0'; priv_script_init("PREINIT", NULL); if (ifi->client->alias) priv_script_write_params("alias_", ifi->client->alias); priv_script_go(); /* set up the interface */ discover_interfaces(ifi); if (pipe(pipe_fd) == -1) error("pipe"); fork_privchld(pipe_fd[0], pipe_fd[1]); close(ifi->ufdesc); ifi->ufdesc = -1; close(ifi->wfdesc); ifi->wfdesc = -1; close(pipe_fd[0]); privfd = pipe_fd[1]; cap_rights_init(&rights, CAP_READ, CAP_WRITE); if (cap_rights_limit(privfd, &rights) < 0 && errno != ENOSYS) error("can't limit private descriptor: %m"); if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1) error("can't open and lock %s: %m", path_dhclient_db); read_client_leases(); rewrite_client_leases(); close(fd); if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1) add_protocol("AF_ROUTE", routefd, routehandler, ifi); if (shutdown(routefd, SHUT_WR) < 0) error("can't shutdown route socket: %m"); cap_rights_init(&rights, CAP_EVENT, CAP_READ); if (cap_rights_limit(routefd, &rights) < 0 && errno != ENOSYS) error("can't limit route socket: %m"); if (chroot(_PATH_VAREMPTY) == -1) error("chroot"); if (chdir("/") == -1) error("chdir(\"/\")"); if (setgroups(1, &pw->pw_gid) || setegid(pw->pw_gid) || setgid(pw->pw_gid) || seteuid(pw->pw_uid) || setuid(pw->pw_uid)) error("can't drop privileges: %m"); endpwent(); setproctitle("%s", ifi->name); - if (CASPER_SUPPORT && cap_enter() < 0 && errno != ENOSYS) + if (caph_enter_casper() < 0) error("can't enter capability mode: %m"); if (immediate_daemon) go_daemon(); ifi->client->state = S_INIT; state_reboot(ifi); bootp_packet_handler = do_packet; dispatch(); /* not reached */ return (0); } void usage(void) { extern char *__progname; fprintf(stderr, "usage: %s [-bdqu] ", __progname); fprintf(stderr, "[-c conffile] [-l leasefile] interface\n"); exit(1); } /* * Individual States: * * Each routine is called from the dhclient_state_machine() in one of * these conditions: * -> entering INIT state * -> recvpacket_flag == 0: timeout in this state * -> otherwise: received a packet in this state * * Return conditions as handled by dhclient_state_machine(): * Returns 1, sendpacket_flag = 1: send packet, reset timer. * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone). * Returns 0: finish the nap which was interrupted for no good reason. * * Several per-interface variables are used to keep track of the process: * active_lease: the lease that is being used on the interface * (null pointer if not configured yet). * offered_leases: leases corresponding to DHCPOFFER messages that have * been sent to us by DHCP servers. * acked_leases: leases corresponding to DHCPACK messages that have been * sent to us by DHCP servers. * sendpacket: DHCP packet we're trying to send. * destination: IP address to send sendpacket to * In addition, there are several relevant per-lease variables. * T1_expiry, T2_expiry, lease_expiry: lease milestones * In the active lease, these control the process of renewing the lease; * In leases on the acked_leases list, this simply determines when we * can no longer legitimately use the lease. */ void state_reboot(void *ipp) { struct interface_info *ip = ipp; /* If we don't remember an active lease, go straight to INIT. */ if (!ip->client->active || ip->client->active->is_bootp) { state_init(ip); return; } /* We are in the rebooting state. */ ip->client->state = S_REBOOTING; /* make_request doesn't initialize xid because it normally comes from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, so pick an xid now. */ ip->client->xid = arc4random(); /* Make a DHCPREQUEST packet, and set appropriate per-interface flags. */ make_request(ip, ip->client->active); ip->client->destination = iaddr_broadcast; ip->client->first_sending = cur_time; ip->client->interval = ip->client->config->initial_interval; /* Zap the medium list... */ ip->client->medium = NULL; /* Send out the first DHCPREQUEST packet. */ send_request(ip); } /* * Called when a lease has completely expired and we've * been unable to renew it. */ void state_init(void *ipp) { struct interface_info *ip = ipp; ASSERT_STATE(state, S_INIT); /* Make a DHCPDISCOVER packet, and set appropriate per-interface flags. */ make_discover(ip, ip->client->active); ip->client->xid = ip->client->packet.xid; ip->client->destination = iaddr_broadcast; ip->client->state = S_SELECTING; ip->client->first_sending = cur_time; ip->client->interval = ip->client->config->initial_interval; /* Add an immediate timeout to cause the first DHCPDISCOVER packet to go out. */ send_discover(ip); } /* * state_selecting is called when one or more DHCPOFFER packets * have been received and a configurable period of time has passed. */ void state_selecting(void *ipp) { struct interface_info *ip = ipp; struct client_lease *lp, *next, *picked; ASSERT_STATE(state, S_SELECTING); /* Cancel state_selecting and send_discover timeouts, since either one could have got us here. */ cancel_timeout(state_selecting, ip); cancel_timeout(send_discover, ip); /* We have received one or more DHCPOFFER packets. Currently, the only criterion by which we judge leases is whether or not we get a response when we arp for them. */ picked = NULL; for (lp = ip->client->offered_leases; lp; lp = next) { next = lp->next; /* Check to see if we got an ARPREPLY for the address in this particular lease. */ if (!picked) { script_init("ARPCHECK", lp->medium); script_write_params("check_", lp); /* If the ARPCHECK code detects another machine using the offered address, it exits nonzero. We need to send a DHCPDECLINE and toss the lease. */ if (script_go()) { make_decline(ip, lp); send_decline(ip); goto freeit; } picked = lp; picked->next = NULL; } else { freeit: free_client_lease(lp); } } ip->client->offered_leases = NULL; /* If we just tossed all the leases we were offered, go back to square one. */ if (!picked) { ip->client->state = S_INIT; state_init(ip); return; } /* If it was a BOOTREPLY, we can just take the address right now. */ if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) { ip->client->new = picked; /* Make up some lease expiry times XXX these should be configurable. */ ip->client->new->expiry = cur_time + 12000; ip->client->new->renewal += cur_time + 8000; ip->client->new->rebind += cur_time + 10000; ip->client->state = S_REQUESTING; /* Bind to the address we received. */ bind_lease(ip); return; } /* Go to the REQUESTING state. */ ip->client->destination = iaddr_broadcast; ip->client->state = S_REQUESTING; ip->client->first_sending = cur_time; ip->client->interval = ip->client->config->initial_interval; /* Make a DHCPREQUEST packet from the lease we picked. */ make_request(ip, picked); ip->client->xid = ip->client->packet.xid; /* Toss the lease we picked - we'll get it back in a DHCPACK. */ free_client_lease(picked); /* Add an immediate timeout to send the first DHCPREQUEST packet. */ send_request(ip); } /* state_requesting is called when we receive a DHCPACK message after having sent out one or more DHCPREQUEST packets. */ void dhcpack(struct packet *packet) { struct interface_info *ip = packet->interface; struct client_lease *lease; /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ if (packet->interface->client->xid != packet->raw->xid || (packet->interface->hw_address.hlen != packet->raw->hlen) || (memcmp(packet->interface->hw_address.haddr, packet->raw->chaddr, packet->raw->hlen))) return; if (ip->client->state != S_REBOOTING && ip->client->state != S_REQUESTING && ip->client->state != S_RENEWING && ip->client->state != S_REBINDING) return; note("DHCPACK from %s", piaddr(packet->client_addr)); lease = packet_to_lease(packet); if (!lease) { note("packet_to_lease failed."); return; } ip->client->new = lease; /* Stop resending DHCPREQUEST. */ cancel_timeout(send_request, ip); /* Figure out the lease time. */ if (ip->client->config->default_actions[DHO_DHCP_LEASE_TIME] == ACTION_SUPERSEDE) ip->client->new->expiry = getULong( ip->client->config->defaults[DHO_DHCP_LEASE_TIME].data); else if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data) ip->client->new->expiry = getULong( ip->client->new->options[DHO_DHCP_LEASE_TIME].data); else ip->client->new->expiry = default_lease_time; /* A number that looks negative here is really just very large, because the lease expiry offset is unsigned. Also make sure that the addition of cur_time below does not overflow (a 32 bit) time_t. */ if (ip->client->new->expiry < 0 || ip->client->new->expiry > TIME_MAX - cur_time) ip->client->new->expiry = TIME_MAX - cur_time; /* XXX should be fixed by resetting the client state */ if (ip->client->new->expiry < 60) ip->client->new->expiry = 60; /* Unless overridden in the config, take the server-provided renewal * time if there is one. Otherwise figure it out according to the spec. * Also make sure the renewal time does not exceed the expiry time. */ if (ip->client->config->default_actions[DHO_DHCP_RENEWAL_TIME] == ACTION_SUPERSEDE) ip->client->new->renewal = getULong( ip->client->config->defaults[DHO_DHCP_RENEWAL_TIME].data); else if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len) ip->client->new->renewal = getULong( ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data); else ip->client->new->renewal = ip->client->new->expiry / 2; if (ip->client->new->renewal < 0 || ip->client->new->renewal > ip->client->new->expiry / 2) ip->client->new->renewal = ip->client->new->expiry / 2; /* Same deal with the rebind time. */ if (ip->client->config->default_actions[DHO_DHCP_REBINDING_TIME] == ACTION_SUPERSEDE) ip->client->new->rebind = getULong( ip->client->config->defaults[DHO_DHCP_REBINDING_TIME].data); else if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len) ip->client->new->rebind = getULong( ip->client->new->options[DHO_DHCP_REBINDING_TIME].data); else ip->client->new->rebind = ip->client->new->renewal / 4 * 7; if (ip->client->new->rebind < 0 || ip->client->new->rebind > ip->client->new->renewal / 4 * 7) ip->client->new->rebind = ip->client->new->renewal / 4 * 7; /* Convert the time offsets into seconds-since-the-epoch */ ip->client->new->expiry += cur_time; ip->client->new->renewal += cur_time; ip->client->new->rebind += cur_time; bind_lease(ip); } void bind_lease(struct interface_info *ip) { struct option_data *opt; /* Remember the medium. */ ip->client->new->medium = ip->client->medium; opt = &ip->client->new->options[DHO_INTERFACE_MTU]; if (opt->len == sizeof(u_int16_t)) { u_int16_t mtu = 0; bool supersede = (ip->client->config->default_actions[DHO_INTERFACE_MTU] == ACTION_SUPERSEDE); if (supersede) mtu = getUShort(ip->client->config->defaults[DHO_INTERFACE_MTU].data); else mtu = be16dec(opt->data); if (mtu < MIN_MTU) { /* Treat 0 like a user intentionally doesn't want to change MTU and, * therefore, warning is not needed */ if (!supersede || mtu != 0) warning("mtu size %u < %d: ignored", (unsigned)mtu, MIN_MTU); } else { interface_set_mtu_unpriv(privfd, mtu); } } /* Write out the new lease. */ write_client_lease(ip, ip->client->new, 0); /* Run the client script with the new parameters. */ script_init((ip->client->state == S_REQUESTING ? "BOUND" : (ip->client->state == S_RENEWING ? "RENEW" : (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))), ip->client->new->medium); if (ip->client->active && ip->client->state != S_REBOOTING) script_write_params("old_", ip->client->active); script_write_params("new_", ip->client->new); if (ip->client->alias) script_write_params("alias_", ip->client->alias); script_go(); /* Replace the old active lease with the new one. */ if (ip->client->active) free_client_lease(ip->client->active); ip->client->active = ip->client->new; ip->client->new = NULL; /* Set up a timeout to start the renewal process. */ add_timeout(ip->client->active->renewal, state_bound, ip); note("bound to %s -- renewal in %d seconds.", piaddr(ip->client->active->address), (int)(ip->client->active->renewal - cur_time)); ip->client->state = S_BOUND; reinitialize_interfaces(); go_daemon(); } /* * state_bound is called when we've successfully bound to a particular * lease, but the renewal time on that lease has expired. We are * expected to unicast a DHCPREQUEST to the server that gave us our * original lease. */ void state_bound(void *ipp) { struct interface_info *ip = ipp; ASSERT_STATE(state, S_BOUND); /* T1 has expired. */ make_request(ip, ip->client->active); ip->client->xid = ip->client->packet.xid; if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) { memcpy(ip->client->destination.iabuf, ip->client->active-> options[DHO_DHCP_SERVER_IDENTIFIER].data, 4); ip->client->destination.len = 4; } else ip->client->destination = iaddr_broadcast; ip->client->first_sending = cur_time; ip->client->interval = ip->client->config->initial_interval; ip->client->state = S_RENEWING; /* Send the first packet immediately. */ send_request(ip); } void bootp(struct packet *packet) { struct iaddrlist *ap; if (packet->raw->op != BOOTREPLY) return; /* If there's a reject list, make sure this packet's sender isn't on it. */ for (ap = packet->interface->client->config->reject_list; ap; ap = ap->next) { if (addr_eq(packet->client_addr, ap->addr)) { note("BOOTREPLY from %s rejected.", piaddr(ap->addr)); return; } } dhcpoffer(packet); } void dhcp(struct packet *packet) { struct iaddrlist *ap; void (*handler)(struct packet *); const char *type; switch (packet->packet_type) { case DHCPOFFER: handler = dhcpoffer; type = "DHCPOFFER"; break; case DHCPNAK: handler = dhcpnak; type = "DHCPNACK"; break; case DHCPACK: handler = dhcpack; type = "DHCPACK"; break; default: return; } /* If there's a reject list, make sure this packet's sender isn't on it. */ for (ap = packet->interface->client->config->reject_list; ap; ap = ap->next) { if (addr_eq(packet->client_addr, ap->addr)) { note("%s from %s rejected.", type, piaddr(ap->addr)); return; } } (*handler)(packet); } void dhcpoffer(struct packet *packet) { struct interface_info *ip = packet->interface; struct client_lease *lease, *lp; int i; int arp_timeout_needed, stop_selecting; const char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ? "DHCPOFFER" : "BOOTREPLY"; /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ if (ip->client->state != S_SELECTING || packet->interface->client->xid != packet->raw->xid || (packet->interface->hw_address.hlen != packet->raw->hlen) || (memcmp(packet->interface->hw_address.haddr, packet->raw->chaddr, packet->raw->hlen))) return; note("%s from %s", name, piaddr(packet->client_addr)); /* If this lease doesn't supply the minimum required parameters, blow it off. */ for (i = 0; ip->client->config->required_options[i]; i++) { if (!packet->options[ip->client->config-> required_options[i]].len) { note("%s isn't satisfactory.", name); return; } } /* If we've already seen this lease, don't record it again. */ for (lease = ip->client->offered_leases; lease; lease = lease->next) { if (lease->address.len == sizeof(packet->raw->yiaddr) && !memcmp(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len)) { debug("%s already seen.", name); return; } } lease = packet_to_lease(packet); if (!lease) { note("packet_to_lease failed."); return; } /* If this lease was acquired through a BOOTREPLY, record that fact. */ if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len) lease->is_bootp = 1; /* Record the medium under which this lease was offered. */ lease->medium = ip->client->medium; /* Send out an ARP Request for the offered IP address. */ script_init("ARPSEND", lease->medium); script_write_params("check_", lease); /* If the script can't send an ARP request without waiting, we'll be waiting when we do the ARPCHECK, so don't wait now. */ if (script_go()) arp_timeout_needed = 0; else arp_timeout_needed = 2; /* Figure out when we're supposed to stop selecting. */ stop_selecting = ip->client->first_sending + ip->client->config->select_interval; /* If this is the lease we asked for, put it at the head of the list, and don't mess with the arp request timeout. */ if (lease->address.len == ip->client->requested_address.len && !memcmp(lease->address.iabuf, ip->client->requested_address.iabuf, ip->client->requested_address.len)) { lease->next = ip->client->offered_leases; ip->client->offered_leases = lease; } else { /* If we already have an offer, and arping for this offer would take us past the selection timeout, then don't extend the timeout - just hope for the best. */ if (ip->client->offered_leases && (cur_time + arp_timeout_needed) > stop_selecting) arp_timeout_needed = 0; /* Put the lease at the end of the list. */ lease->next = NULL; if (!ip->client->offered_leases) ip->client->offered_leases = lease; else { for (lp = ip->client->offered_leases; lp->next; lp = lp->next) ; /* nothing */ lp->next = lease; } } /* If we're supposed to stop selecting before we've had time to wait for the ARPREPLY, add some delay to wait for the ARPREPLY. */ if (stop_selecting - cur_time < arp_timeout_needed) stop_selecting = cur_time + arp_timeout_needed; /* If the selecting interval has expired, go immediately to state_selecting(). Otherwise, time out into state_selecting at the select interval. */ if (stop_selecting <= 0) state_selecting(ip); else { add_timeout(stop_selecting, state_selecting, ip); cancel_timeout(send_discover, ip); } } /* Allocate a client_lease structure and initialize it from the parameters in the specified packet. */ struct client_lease * packet_to_lease(struct packet *packet) { struct client_lease *lease; int i; lease = malloc(sizeof(struct client_lease)); if (!lease) { warning("dhcpoffer: no memory to record lease."); return (NULL); } memset(lease, 0, sizeof(*lease)); /* Copy the lease options. */ for (i = 0; i < 256; i++) { if (packet->options[i].len) { lease->options[i].data = malloc(packet->options[i].len + 1); if (!lease->options[i].data) { warning("dhcpoffer: no memory for option %d", i); free_client_lease(lease); return (NULL); } else { memcpy(lease->options[i].data, packet->options[i].data, packet->options[i].len); lease->options[i].len = packet->options[i].len; lease->options[i].data[lease->options[i].len] = 0; } if (!check_option(lease,i)) { /* ignore a bogus lease offer */ warning("Invalid lease option - ignoring offer"); free_client_lease(lease); return (NULL); } } } lease->address.len = sizeof(packet->raw->yiaddr); memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len); lease->nextserver.len = sizeof(packet->raw->siaddr); memcpy(lease->nextserver.iabuf, &packet->raw->siaddr, lease->nextserver.len); /* If the server name was filled out, copy it. Do not attempt to validate the server name as a host name. RFC 2131 merely states that sname is NUL-terminated (which do do not assume) and that it is the server's host name. Since the ISC client and server allow arbitrary characters, we do as well. */ if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len || !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) && packet->raw->sname[0]) { lease->server_name = malloc(DHCP_SNAME_LEN + 1); if (!lease->server_name) { warning("dhcpoffer: no memory for server name."); free_client_lease(lease); return (NULL); } memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN); lease->server_name[DHCP_SNAME_LEN]='\0'; } /* Ditto for the filename. */ if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len || !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) && packet->raw->file[0]) { /* Don't count on the NUL terminator. */ lease->filename = malloc(DHCP_FILE_LEN + 1); if (!lease->filename) { warning("dhcpoffer: no memory for filename."); free_client_lease(lease); return (NULL); } memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN); lease->filename[DHCP_FILE_LEN]='\0'; } return lease; } void dhcpnak(struct packet *packet) { struct interface_info *ip = packet->interface; /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ if (packet->interface->client->xid != packet->raw->xid || (packet->interface->hw_address.hlen != packet->raw->hlen) || (memcmp(packet->interface->hw_address.haddr, packet->raw->chaddr, packet->raw->hlen))) return; if (ip->client->state != S_REBOOTING && ip->client->state != S_REQUESTING && ip->client->state != S_RENEWING && ip->client->state != S_REBINDING) return; note("DHCPNAK from %s", piaddr(packet->client_addr)); if (!ip->client->active) { note("DHCPNAK with no active lease.\n"); return; } free_client_lease(ip->client->active); ip->client->active = NULL; /* Stop sending DHCPREQUEST packets... */ cancel_timeout(send_request, ip); ip->client->state = S_INIT; state_init(ip); } /* Send out a DHCPDISCOVER packet, and set a timeout to send out another one after the right interval has expired. If we don't get an offer by the time we reach the panic interval, call the panic function. */ void send_discover(void *ipp) { struct interface_info *ip = ipp; int interval, increase = 1; /* Figure out how long it's been since we started transmitting. */ interval = cur_time - ip->client->first_sending; /* If we're past the panic timeout, call the script and tell it we haven't found anything for this interface yet. */ if (interval > ip->client->config->timeout) { state_panic(ip); return; } /* If we're selecting media, try the whole list before doing the exponential backoff, but if we've already received an offer, stop looping, because we obviously have it right. */ if (!ip->client->offered_leases && ip->client->config->media) { int fail = 0; again: if (ip->client->medium) { ip->client->medium = ip->client->medium->next; increase = 0; } if (!ip->client->medium) { if (fail) error("No valid media types for %s!", ip->name); ip->client->medium = ip->client->config->media; increase = 1; } note("Trying medium \"%s\" %d", ip->client->medium->string, increase); script_init("MEDIUM", ip->client->medium); if (script_go()) goto again; } /* * If we're supposed to increase the interval, do so. If it's * currently zero (i.e., we haven't sent any packets yet), set * it to one; otherwise, add to it a random number between zero * and two times itself. On average, this means that it will * double with every transmission. */ if (increase) { if (!ip->client->interval) ip->client->interval = ip->client->config->initial_interval; else { ip->client->interval += (arc4random() >> 2) % (2 * ip->client->interval); } /* Don't backoff past cutoff. */ if (ip->client->interval > ip->client->config->backoff_cutoff) ip->client->interval = ((ip->client->config->backoff_cutoff / 2) + ((arc4random() >> 2) % ip->client->config->backoff_cutoff)); } else if (!ip->client->interval) ip->client->interval = ip->client->config->initial_interval; /* If the backoff would take us to the panic timeout, just use that as the interval. */ if (cur_time + ip->client->interval > ip->client->first_sending + ip->client->config->timeout) ip->client->interval = (ip->client->first_sending + ip->client->config->timeout) - cur_time + 1; /* Record the number of seconds since we started sending. */ if (interval < 65536) ip->client->packet.secs = htons(interval); else ip->client->packet.secs = htons(65535); ip->client->secs = ip->client->packet.secs; note("DHCPDISCOVER on %s to %s port %d interval %d", ip->name, inet_ntoa(inaddr_broadcast), REMOTE_PORT, (int)ip->client->interval); /* Send out a packet. */ send_packet_unpriv(privfd, &ip->client->packet, ip->client->packet_length, inaddr_any, inaddr_broadcast); add_timeout(cur_time + ip->client->interval, send_discover, ip); } /* * state_panic gets called if we haven't received any offers in a preset * amount of time. When this happens, we try to use existing leases * that haven't yet expired, and failing that, we call the client script * and hope it can do something. */ void state_panic(void *ipp) { struct interface_info *ip = ipp; struct client_lease *loop = ip->client->active; struct client_lease *lp; note("No DHCPOFFERS received."); /* We may not have an active lease, but we may have some predefined leases that we can try. */ if (!ip->client->active && ip->client->leases) goto activate_next; /* Run through the list of leases and see if one can be used. */ while (ip->client->active) { if (ip->client->active->expiry > cur_time) { note("Trying recorded lease %s", piaddr(ip->client->active->address)); /* Run the client script with the existing parameters. */ script_init("TIMEOUT", ip->client->active->medium); script_write_params("new_", ip->client->active); if (ip->client->alias) script_write_params("alias_", ip->client->alias); /* If the old lease is still good and doesn't yet need renewal, go into BOUND state and timeout at the renewal time. */ if (!script_go()) { if (cur_time < ip->client->active->renewal) { ip->client->state = S_BOUND; note("bound: renewal in %d seconds.", (int)(ip->client->active->renewal - cur_time)); add_timeout( ip->client->active->renewal, state_bound, ip); } else { ip->client->state = S_BOUND; note("bound: immediate renewal."); state_bound(ip); } reinitialize_interfaces(); go_daemon(); return; } } /* If there are no other leases, give up. */ if (!ip->client->leases) { ip->client->leases = ip->client->active; ip->client->active = NULL; break; } activate_next: /* Otherwise, put the active lease at the end of the lease list, and try another lease.. */ for (lp = ip->client->leases; lp->next; lp = lp->next) ; lp->next = ip->client->active; if (lp->next) lp->next->next = NULL; ip->client->active = ip->client->leases; ip->client->leases = ip->client->leases->next; /* If we already tried this lease, we've exhausted the set of leases, so we might as well give up for now. */ if (ip->client->active == loop) break; else if (!loop) loop = ip->client->active; } /* No leases were available, or what was available didn't work, so tell the shell script that we failed to allocate an address, and try again later. */ note("No working leases in persistent database - sleeping.\n"); script_init("FAIL", NULL); if (ip->client->alias) script_write_params("alias_", ip->client->alias); script_go(); ip->client->state = S_INIT; add_timeout(cur_time + ip->client->config->retry_interval, state_init, ip); go_daemon(); } void send_request(void *ipp) { struct interface_info *ip = ipp; struct in_addr from, to; int interval; /* Figure out how long it's been since we started transmitting. */ interval = cur_time - ip->client->first_sending; /* If we're in the INIT-REBOOT or REQUESTING state and we're past the reboot timeout, go to INIT and see if we can DISCOVER an address... */ /* XXX In the INIT-REBOOT state, if we don't get an ACK, it means either that we're on a network with no DHCP server, or that our server is down. In the latter case, assuming that there is a backup DHCP server, DHCPDISCOVER will get us a new address, but we could also have successfully reused our old address. In the former case, we're hosed anyway. This is not a win-prone situation. */ if ((ip->client->state == S_REBOOTING || ip->client->state == S_REQUESTING) && interval > ip->client->config->reboot_timeout) { cancel: ip->client->state = S_INIT; cancel_timeout(send_request, ip); state_init(ip); return; } /* If we're in the reboot state, make sure the media is set up correctly. */ if (ip->client->state == S_REBOOTING && !ip->client->medium && ip->client->active->medium ) { script_init("MEDIUM", ip->client->active->medium); /* If the medium we chose won't fly, go to INIT state. */ if (script_go()) goto cancel; /* Record the medium. */ ip->client->medium = ip->client->active->medium; } /* If the lease has expired, relinquish the address and go back to the INIT state. */ if (ip->client->state != S_REQUESTING && cur_time > ip->client->active->expiry) { /* Run the client script with the new parameters. */ script_init("EXPIRE", NULL); script_write_params("old_", ip->client->active); if (ip->client->alias) script_write_params("alias_", ip->client->alias); script_go(); /* Now do a preinit on the interface so that we can discover a new address. */ script_init("PREINIT", NULL); if (ip->client->alias) script_write_params("alias_", ip->client->alias); script_go(); ip->client->state = S_INIT; state_init(ip); return; } /* Do the exponential backoff... */ if (!ip->client->interval) ip->client->interval = ip->client->config->initial_interval; else ip->client->interval += ((arc4random() >> 2) % (2 * ip->client->interval)); /* Don't backoff past cutoff. */ if (ip->client->interval > ip->client->config->backoff_cutoff) ip->client->interval = ((ip->client->config->backoff_cutoff / 2) + ((arc4random() >> 2) % ip->client->interval)); /* If the backoff would take us to the expiry time, just set the timeout to the expiry time. */ if (ip->client->state != S_REQUESTING && cur_time + ip->client->interval > ip->client->active->expiry) ip->client->interval = ip->client->active->expiry - cur_time + 1; /* If the lease T2 time has elapsed, or if we're not yet bound, broadcast the DHCPREQUEST rather than unicasting. */ if (ip->client->state == S_REQUESTING || ip->client->state == S_REBOOTING || cur_time > ip->client->active->rebind) to.s_addr = INADDR_BROADCAST; else memcpy(&to.s_addr, ip->client->destination.iabuf, sizeof(to.s_addr)); if (ip->client->state != S_REQUESTING && ip->client->state != S_REBOOTING) memcpy(&from, ip->client->active->address.iabuf, sizeof(from)); else from.s_addr = INADDR_ANY; /* Record the number of seconds since we started sending. */ if (ip->client->state == S_REQUESTING) ip->client->packet.secs = ip->client->secs; else { if (interval < 65536) ip->client->packet.secs = htons(interval); else ip->client->packet.secs = htons(65535); } note("DHCPREQUEST on %s to %s port %d", ip->name, inet_ntoa(to), REMOTE_PORT); /* Send out a packet. */ send_packet_unpriv(privfd, &ip->client->packet, ip->client->packet_length, from, to); add_timeout(cur_time + ip->client->interval, send_request, ip); } void send_decline(void *ipp) { struct interface_info *ip = ipp; note("DHCPDECLINE on %s to %s port %d", ip->name, inet_ntoa(inaddr_broadcast), REMOTE_PORT); /* Send out a packet. */ send_packet_unpriv(privfd, &ip->client->packet, ip->client->packet_length, inaddr_any, inaddr_broadcast); } void make_discover(struct interface_info *ip, struct client_lease *lease) { unsigned char discover = DHCPDISCOVER; struct tree_cache *options[256]; struct tree_cache option_elements[256]; int i; memset(option_elements, 0, sizeof(option_elements)); memset(options, 0, sizeof(options)); memset(&ip->client->packet, 0, sizeof(ip->client->packet)); /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */ i = DHO_DHCP_MESSAGE_TYPE; options[i] = &option_elements[i]; options[i]->value = &discover; options[i]->len = sizeof(discover); options[i]->buf_size = sizeof(discover); options[i]->timeout = 0xFFFFFFFF; /* Request the options we want */ i = DHO_DHCP_PARAMETER_REQUEST_LIST; options[i] = &option_elements[i]; options[i]->value = ip->client->config->requested_options; options[i]->len = ip->client->config->requested_option_count; options[i]->buf_size = ip->client->config->requested_option_count; options[i]->timeout = 0xFFFFFFFF; /* If we had an address, try to get it again. */ if (lease) { ip->client->requested_address = lease->address; i = DHO_DHCP_REQUESTED_ADDRESS; options[i] = &option_elements[i]; options[i]->value = lease->address.iabuf; options[i]->len = lease->address.len; options[i]->buf_size = lease->address.len; options[i]->timeout = 0xFFFFFFFF; } else ip->client->requested_address.len = 0; /* Send any options requested in the config file. */ for (i = 0; i < 256; i++) if (!options[i] && ip->client->config->send_options[i].data) { options[i] = &option_elements[i]; options[i]->value = ip->client->config->send_options[i].data; options[i]->len = ip->client->config->send_options[i].len; options[i]->buf_size = ip->client->config->send_options[i].len; options[i]->timeout = 0xFFFFFFFF; } /* send host name if not set via config file. */ if (!options[DHO_HOST_NAME]) { if (hostname[0] != '\0') { size_t len; char* posDot = strchr(hostname, '.'); if (posDot != NULL) len = posDot - hostname; else len = strlen(hostname); options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME]; options[DHO_HOST_NAME]->value = hostname; options[DHO_HOST_NAME]->len = len; options[DHO_HOST_NAME]->buf_size = len; options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF; } } /* set unique client identifier */ char client_ident[sizeof(ip->hw_address.haddr) + 1]; if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) { int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ? ip->hw_address.hlen : sizeof(client_ident)-1; client_ident[0] = ip->hw_address.htype; memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER]; options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident; options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1; options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1; options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF; } /* Set up the option buffer... */ ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, options, 0, 0, 0, NULL, 0); if (ip->client->packet_length < BOOTP_MIN_LEN) ip->client->packet_length = BOOTP_MIN_LEN; ip->client->packet.op = BOOTREQUEST; ip->client->packet.htype = ip->hw_address.htype; ip->client->packet.hlen = ip->hw_address.hlen; ip->client->packet.hops = 0; ip->client->packet.xid = arc4random(); ip->client->packet.secs = 0; /* filled in by send_discover. */ ip->client->packet.flags = 0; memset(&(ip->client->packet.ciaddr), 0, sizeof(ip->client->packet.ciaddr)); memset(&(ip->client->packet.yiaddr), 0, sizeof(ip->client->packet.yiaddr)); memset(&(ip->client->packet.siaddr), 0, sizeof(ip->client->packet.siaddr)); memset(&(ip->client->packet.giaddr), 0, sizeof(ip->client->packet.giaddr)); memcpy(ip->client->packet.chaddr, ip->hw_address.haddr, ip->hw_address.hlen); } void make_request(struct interface_info *ip, struct client_lease * lease) { unsigned char request = DHCPREQUEST; struct tree_cache *options[256]; struct tree_cache option_elements[256]; int i; memset(options, 0, sizeof(options)); memset(&ip->client->packet, 0, sizeof(ip->client->packet)); /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */ i = DHO_DHCP_MESSAGE_TYPE; options[i] = &option_elements[i]; options[i]->value = &request; options[i]->len = sizeof(request); options[i]->buf_size = sizeof(request); options[i]->timeout = 0xFFFFFFFF; /* Request the options we want */ i = DHO_DHCP_PARAMETER_REQUEST_LIST; options[i] = &option_elements[i]; options[i]->value = ip->client->config->requested_options; options[i]->len = ip->client->config->requested_option_count; options[i]->buf_size = ip->client->config->requested_option_count; options[i]->timeout = 0xFFFFFFFF; /* If we are requesting an address that hasn't yet been assigned to us, use the DHCP Requested Address option. */ if (ip->client->state == S_REQUESTING) { /* Send back the server identifier... */ i = DHO_DHCP_SERVER_IDENTIFIER; options[i] = &option_elements[i]; options[i]->value = lease->options[i].data; options[i]->len = lease->options[i].len; options[i]->buf_size = lease->options[i].len; options[i]->timeout = 0xFFFFFFFF; } if (ip->client->state == S_REQUESTING || ip->client->state == S_REBOOTING) { ip->client->requested_address = lease->address; i = DHO_DHCP_REQUESTED_ADDRESS; options[i] = &option_elements[i]; options[i]->value = lease->address.iabuf; options[i]->len = lease->address.len; options[i]->buf_size = lease->address.len; options[i]->timeout = 0xFFFFFFFF; } else ip->client->requested_address.len = 0; /* Send any options requested in the config file. */ for (i = 0; i < 256; i++) if (!options[i] && ip->client->config->send_options[i].data) { options[i] = &option_elements[i]; options[i]->value = ip->client->config->send_options[i].data; options[i]->len = ip->client->config->send_options[i].len; options[i]->buf_size = ip->client->config->send_options[i].len; options[i]->timeout = 0xFFFFFFFF; } /* send host name if not set via config file. */ if (!options[DHO_HOST_NAME]) { if (hostname[0] != '\0') { size_t len; char* posDot = strchr(hostname, '.'); if (posDot != NULL) len = posDot - hostname; else len = strlen(hostname); options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME]; options[DHO_HOST_NAME]->value = hostname; options[DHO_HOST_NAME]->len = len; options[DHO_HOST_NAME]->buf_size = len; options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF; } } /* set unique client identifier */ char client_ident[sizeof(struct hardware)]; if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) { int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ? ip->hw_address.hlen : sizeof(client_ident)-1; client_ident[0] = ip->hw_address.htype; memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER]; options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident; options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1; options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1; options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF; } /* Set up the option buffer... */ ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, options, 0, 0, 0, NULL, 0); if (ip->client->packet_length < BOOTP_MIN_LEN) ip->client->packet_length = BOOTP_MIN_LEN; ip->client->packet.op = BOOTREQUEST; ip->client->packet.htype = ip->hw_address.htype; ip->client->packet.hlen = ip->hw_address.hlen; ip->client->packet.hops = 0; ip->client->packet.xid = ip->client->xid; ip->client->packet.secs = 0; /* Filled in by send_request. */ /* If we own the address we're requesting, put it in ciaddr; otherwise set ciaddr to zero. */ if (ip->client->state == S_BOUND || ip->client->state == S_RENEWING || ip->client->state == S_REBINDING) { memcpy(&ip->client->packet.ciaddr, lease->address.iabuf, lease->address.len); ip->client->packet.flags = 0; } else { memset(&ip->client->packet.ciaddr, 0, sizeof(ip->client->packet.ciaddr)); ip->client->packet.flags = 0; } memset(&ip->client->packet.yiaddr, 0, sizeof(ip->client->packet.yiaddr)); memset(&ip->client->packet.siaddr, 0, sizeof(ip->client->packet.siaddr)); memset(&ip->client->packet.giaddr, 0, sizeof(ip->client->packet.giaddr)); memcpy(ip->client->packet.chaddr, ip->hw_address.haddr, ip->hw_address.hlen); } void make_decline(struct interface_info *ip, struct client_lease *lease) { struct tree_cache *options[256], message_type_tree; struct tree_cache requested_address_tree; struct tree_cache server_id_tree, client_id_tree; unsigned char decline = DHCPDECLINE; int i; memset(options, 0, sizeof(options)); memset(&ip->client->packet, 0, sizeof(ip->client->packet)); /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */ i = DHO_DHCP_MESSAGE_TYPE; options[i] = &message_type_tree; options[i]->value = &decline; options[i]->len = sizeof(decline); options[i]->buf_size = sizeof(decline); options[i]->timeout = 0xFFFFFFFF; /* Send back the server identifier... */ i = DHO_DHCP_SERVER_IDENTIFIER; options[i] = &server_id_tree; options[i]->value = lease->options[i].data; options[i]->len = lease->options[i].len; options[i]->buf_size = lease->options[i].len; options[i]->timeout = 0xFFFFFFFF; /* Send back the address we're declining. */ i = DHO_DHCP_REQUESTED_ADDRESS; options[i] = &requested_address_tree; options[i]->value = lease->address.iabuf; options[i]->len = lease->address.len; options[i]->buf_size = lease->address.len; options[i]->timeout = 0xFFFFFFFF; /* Send the uid if the user supplied one. */ i = DHO_DHCP_CLIENT_IDENTIFIER; if (ip->client->config->send_options[i].len) { options[i] = &client_id_tree; options[i]->value = ip->client->config->send_options[i].data; options[i]->len = ip->client->config->send_options[i].len; options[i]->buf_size = ip->client->config->send_options[i].len; options[i]->timeout = 0xFFFFFFFF; } /* Set up the option buffer... */ ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, options, 0, 0, 0, NULL, 0); if (ip->client->packet_length < BOOTP_MIN_LEN) ip->client->packet_length = BOOTP_MIN_LEN; ip->client->packet.op = BOOTREQUEST; ip->client->packet.htype = ip->hw_address.htype; ip->client->packet.hlen = ip->hw_address.hlen; ip->client->packet.hops = 0; ip->client->packet.xid = ip->client->xid; ip->client->packet.secs = 0; /* Filled in by send_request. */ ip->client->packet.flags = 0; /* ciaddr must always be zero. */ memset(&ip->client->packet.ciaddr, 0, sizeof(ip->client->packet.ciaddr)); memset(&ip->client->packet.yiaddr, 0, sizeof(ip->client->packet.yiaddr)); memset(&ip->client->packet.siaddr, 0, sizeof(ip->client->packet.siaddr)); memset(&ip->client->packet.giaddr, 0, sizeof(ip->client->packet.giaddr)); memcpy(ip->client->packet.chaddr, ip->hw_address.haddr, ip->hw_address.hlen); } void free_client_lease(struct client_lease *lease) { int i; if (lease->server_name) free(lease->server_name); if (lease->filename) free(lease->filename); for (i = 0; i < 256; i++) { if (lease->options[i].len) free(lease->options[i].data); } free(lease); } FILE *leaseFile; void rewrite_client_leases(void) { struct client_lease *lp; cap_rights_t rights; if (!leaseFile) { leaseFile = fopen(path_dhclient_db, "w"); if (!leaseFile) error("can't create %s: %m", path_dhclient_db); cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_FSYNC, CAP_FTRUNCATE, CAP_SEEK, CAP_WRITE); if (cap_rights_limit(fileno(leaseFile), &rights) < 0 && errno != ENOSYS) { error("can't limit lease descriptor: %m"); } if (cap_fcntls_limit(fileno(leaseFile), CAP_FCNTL_GETFL) < 0 && errno != ENOSYS) { error("can't limit lease descriptor fcntls: %m"); } } else { fflush(leaseFile); rewind(leaseFile); } for (lp = ifi->client->leases; lp; lp = lp->next) write_client_lease(ifi, lp, 1); if (ifi->client->active) write_client_lease(ifi, ifi->client->active, 1); fflush(leaseFile); ftruncate(fileno(leaseFile), ftello(leaseFile)); fsync(fileno(leaseFile)); } void write_client_lease(struct interface_info *ip, struct client_lease *lease, int rewrite) { static int leases_written; struct tm *t; int i; if (!rewrite) { if (leases_written++ > 20) { rewrite_client_leases(); leases_written = 0; } } /* If the lease came from the config file, we don't need to stash a copy in the lease database. */ if (lease->is_static) return; if (!leaseFile) { /* XXX */ leaseFile = fopen(path_dhclient_db, "w"); if (!leaseFile) error("can't create %s: %m", path_dhclient_db); } fprintf(leaseFile, "lease {\n"); if (lease->is_bootp) fprintf(leaseFile, " bootp;\n"); fprintf(leaseFile, " interface \"%s\";\n", ip->name); fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address)); if (lease->nextserver.len == sizeof(inaddr_any) && 0 != memcmp(lease->nextserver.iabuf, &inaddr_any, sizeof(inaddr_any))) fprintf(leaseFile, " next-server %s;\n", piaddr(lease->nextserver)); if (lease->filename) fprintf(leaseFile, " filename \"%s\";\n", lease->filename); if (lease->server_name) fprintf(leaseFile, " server-name \"%s\";\n", lease->server_name); if (lease->medium) fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string); for (i = 0; i < 256; i++) if (lease->options[i].len) fprintf(leaseFile, " option %s %s;\n", dhcp_options[i].name, pretty_print_option(i, lease->options[i].data, lease->options[i].len, 1, 1)); t = gmtime(&lease->renewal); fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n", t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); t = gmtime(&lease->rebind); fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n", t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); t = gmtime(&lease->expiry); fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n", t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); fprintf(leaseFile, "}\n"); fflush(leaseFile); } void script_init(const char *reason, struct string_list *medium) { size_t len, mediumlen = 0; struct imsg_hdr hdr; struct buf *buf; int errs; if (medium != NULL && medium->string != NULL) mediumlen = strlen(medium->string); hdr.code = IMSG_SCRIPT_INIT; hdr.len = sizeof(struct imsg_hdr) + sizeof(size_t) + mediumlen + sizeof(size_t) + strlen(reason); if ((buf = buf_open(hdr.len)) == NULL) error("buf_open: %m"); errs = 0; errs += buf_add(buf, &hdr, sizeof(hdr)); errs += buf_add(buf, &mediumlen, sizeof(mediumlen)); if (mediumlen > 0) errs += buf_add(buf, medium->string, mediumlen); len = strlen(reason); errs += buf_add(buf, &len, sizeof(len)); errs += buf_add(buf, reason, len); if (errs) error("buf_add: %m"); if (buf_close(privfd, buf) == -1) error("buf_close: %m"); } void priv_script_init(const char *reason, char *medium) { struct interface_info *ip = ifi; if (ip) { ip->client->scriptEnvsize = 100; if (ip->client->scriptEnv == NULL) ip->client->scriptEnv = malloc(ip->client->scriptEnvsize * sizeof(char *)); if (ip->client->scriptEnv == NULL) error("script_init: no memory for environment"); ip->client->scriptEnv[0] = strdup(CLIENT_PATH); if (ip->client->scriptEnv[0] == NULL) error("script_init: no memory for environment"); ip->client->scriptEnv[1] = NULL; script_set_env(ip->client, "", "interface", ip->name); if (medium) script_set_env(ip->client, "", "medium", medium); script_set_env(ip->client, "", "reason", reason); } } void priv_script_write_params(const char *prefix, struct client_lease *lease) { struct interface_info *ip = ifi; u_int8_t dbuf[1500], *dp = NULL; int i; size_t len; char tbuf[128]; script_set_env(ip->client, prefix, "ip_address", piaddr(lease->address)); if (ip->client->config->default_actions[DHO_SUBNET_MASK] == ACTION_SUPERSEDE) { dp = ip->client->config->defaults[DHO_SUBNET_MASK].data; len = ip->client->config->defaults[DHO_SUBNET_MASK].len; } else { dp = lease->options[DHO_SUBNET_MASK].data; len = lease->options[DHO_SUBNET_MASK].len; } if (len && (len < sizeof(lease->address.iabuf))) { struct iaddr netmask, subnet, broadcast; memcpy(netmask.iabuf, dp, len); netmask.len = len; subnet = subnet_number(lease->address, netmask); if (subnet.len) { script_set_env(ip->client, prefix, "network_number", piaddr(subnet)); if (!lease->options[DHO_BROADCAST_ADDRESS].len) { broadcast = broadcast_addr(subnet, netmask); if (broadcast.len) script_set_env(ip->client, prefix, "broadcast_address", piaddr(broadcast)); } } } if (lease->filename) script_set_env(ip->client, prefix, "filename", lease->filename); if (lease->server_name) script_set_env(ip->client, prefix, "server_name", lease->server_name); for (i = 0; i < 256; i++) { len = 0; if (ip->client->config->defaults[i].len) { if (lease->options[i].len) { switch ( ip->client->config->default_actions[i]) { case ACTION_DEFAULT: dp = lease->options[i].data; len = lease->options[i].len; break; case ACTION_SUPERSEDE: supersede: dp = ip->client-> config->defaults[i].data; len = ip->client-> config->defaults[i].len; break; case ACTION_PREPEND: len = ip->client-> config->defaults[i].len + lease->options[i].len; if (len >= sizeof(dbuf)) { warning("no space to %s %s", "prepend option", dhcp_options[i].name); goto supersede; } dp = dbuf; memcpy(dp, ip->client-> config->defaults[i].data, ip->client-> config->defaults[i].len); memcpy(dp + ip->client-> config->defaults[i].len, lease->options[i].data, lease->options[i].len); dp[len] = '\0'; break; case ACTION_APPEND: /* * When we append, we assume that we're * appending to text. Some MS servers * include a NUL byte at the end of * the search string provided. */ len = ip->client-> config->defaults[i].len + lease->options[i].len; if (len >= sizeof(dbuf)) { warning("no space to %s %s", "append option", dhcp_options[i].name); goto supersede; } memcpy(dbuf, lease->options[i].data, lease->options[i].len); for (dp = dbuf + lease->options[i].len; dp > dbuf; dp--, len--) if (dp[-1] != '\0') break; memcpy(dp, ip->client-> config->defaults[i].data, ip->client-> config->defaults[i].len); dp = dbuf; dp[len] = '\0'; } } else { dp = ip->client-> config->defaults[i].data; len = ip->client-> config->defaults[i].len; } } else if (lease->options[i].len) { len = lease->options[i].len; dp = lease->options[i].data; } else { len = 0; } if (len) { char name[256]; if (dhcp_option_ev_name(name, sizeof(name), &dhcp_options[i])) script_set_env(ip->client, prefix, name, pretty_print_option(i, dp, len, 0, 0)); } } snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry); script_set_env(ip->client, prefix, "expiry", tbuf); } void script_write_params(const char *prefix, struct client_lease *lease) { size_t fn_len = 0, sn_len = 0, pr_len = 0; struct imsg_hdr hdr; struct buf *buf; int errs, i; if (lease->filename != NULL) fn_len = strlen(lease->filename); if (lease->server_name != NULL) sn_len = strlen(lease->server_name); if (prefix != NULL) pr_len = strlen(prefix); hdr.code = IMSG_SCRIPT_WRITE_PARAMS; hdr.len = sizeof(hdr) + sizeof(*lease) + sizeof(fn_len) + fn_len + sizeof(sn_len) + sn_len + sizeof(pr_len) + pr_len; for (i = 0; i < 256; i++) { hdr.len += sizeof(lease->options[i].len); hdr.len += lease->options[i].len; } scripttime = time(NULL); if ((buf = buf_open(hdr.len)) == NULL) error("buf_open: %m"); errs = 0; errs += buf_add(buf, &hdr, sizeof(hdr)); errs += buf_add(buf, lease, sizeof(*lease)); errs += buf_add(buf, &fn_len, sizeof(fn_len)); errs += buf_add(buf, lease->filename, fn_len); errs += buf_add(buf, &sn_len, sizeof(sn_len)); errs += buf_add(buf, lease->server_name, sn_len); errs += buf_add(buf, &pr_len, sizeof(pr_len)); errs += buf_add(buf, prefix, pr_len); for (i = 0; i < 256; i++) { errs += buf_add(buf, &lease->options[i].len, sizeof(lease->options[i].len)); errs += buf_add(buf, lease->options[i].data, lease->options[i].len); } if (errs) error("buf_add: %m"); if (buf_close(privfd, buf) == -1) error("buf_close: %m"); } int script_go(void) { struct imsg_hdr hdr; struct buf *buf; int ret; hdr.code = IMSG_SCRIPT_GO; hdr.len = sizeof(struct imsg_hdr); if ((buf = buf_open(hdr.len)) == NULL) error("buf_open: %m"); if (buf_add(buf, &hdr, sizeof(hdr))) error("buf_add: %m"); if (buf_close(privfd, buf) == -1) error("buf_close: %m"); bzero(&hdr, sizeof(hdr)); buf_read(privfd, &hdr, sizeof(hdr)); if (hdr.code != IMSG_SCRIPT_GO_RET) error("unexpected msg type %u", hdr.code); if (hdr.len != sizeof(hdr) + sizeof(int)) error("received corrupted message"); buf_read(privfd, &ret, sizeof(ret)); scripttime = time(NULL); return (ret); } int priv_script_go(void) { char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI"; static char client_path[] = CLIENT_PATH; struct interface_info *ip = ifi; int pid, wpid, wstatus; scripttime = time(NULL); if (ip) { scriptName = ip->client->config->script_name; envp = ip->client->scriptEnv; } else { scriptName = top_level_config.script_name; epp[0] = reason; epp[1] = client_path; epp[2] = NULL; envp = epp; } argv[0] = scriptName; argv[1] = NULL; pid = fork(); if (pid < 0) { error("fork: %m"); wstatus = 0; } else if (pid) { do { wpid = wait(&wstatus); } while (wpid != pid && wpid > 0); if (wpid < 0) { error("wait: %m"); wstatus = 0; } } else { execve(scriptName, argv, envp); error("execve (%s, ...): %m", scriptName); } if (ip) script_flush_env(ip->client); return (wstatus & 0xff); } void script_set_env(struct client_state *client, const char *prefix, const char *name, const char *value) { int i, namelen; size_t j; /* No `` or $() command substitution allowed in environment values! */ for (j=0; j < strlen(value); j++) switch (value[j]) { case '`': case '$': warning("illegal character (%c) in value '%s'", value[j], value); /* Ignore this option */ return; } namelen = strlen(name); for (i = 0; client->scriptEnv[i]; i++) if (strncmp(client->scriptEnv[i], name, namelen) == 0 && client->scriptEnv[i][namelen] == '=') break; if (client->scriptEnv[i]) /* Reuse the slot. */ free(client->scriptEnv[i]); else { /* New variable. Expand if necessary. */ if (i >= client->scriptEnvsize - 1) { char **newscriptEnv; int newscriptEnvsize = client->scriptEnvsize + 50; newscriptEnv = realloc(client->scriptEnv, newscriptEnvsize); if (newscriptEnv == NULL) { free(client->scriptEnv); client->scriptEnv = NULL; client->scriptEnvsize = 0; error("script_set_env: no memory for variable"); } client->scriptEnv = newscriptEnv; client->scriptEnvsize = newscriptEnvsize; } /* need to set the NULL pointer at end of array beyond the new slot. */ client->scriptEnv[i + 1] = NULL; } /* Allocate space and format the variable in the appropriate slot. */ client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 + strlen(value) + 1); if (client->scriptEnv[i] == NULL) error("script_set_env: no memory for variable assignment"); snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) + 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value); } void script_flush_env(struct client_state *client) { int i; for (i = 0; client->scriptEnv[i]; i++) { free(client->scriptEnv[i]); client->scriptEnv[i] = NULL; } client->scriptEnvsize = 0; } int dhcp_option_ev_name(char *buf, size_t buflen, struct option *option) { size_t i; for (i = 0; option->name[i]; i++) { if (i + 1 == buflen) return 0; if (option->name[i] == '-') buf[i] = '_'; else buf[i] = option->name[i]; } buf[i] = 0; return 1; } void go_daemon(void) { static int state = 0; cap_rights_t rights; if (no_daemon || state) return; state = 1; /* Stop logging to stderr... */ log_perror = 0; if (daemonfd(-1, nullfd) == -1) error("daemon"); cap_rights_init(&rights); if (pidfile != NULL) { pidfile_write(pidfile); if (cap_rights_limit(pidfile_fileno(pidfile), &rights) < 0 && errno != ENOSYS) { error("can't limit pidfile descriptor: %m"); } } if (nullfd != -1) { close(nullfd); nullfd = -1; } if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) error("can't limit stdin: %m"); cap_rights_init(&rights, CAP_WRITE); if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS) error("can't limit stdout: %m"); if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS) error("can't limit stderr: %m"); } int check_option(struct client_lease *l, int option) { const char *opbuf; const char *sbuf; /* we use this, since this is what gets passed to dhclient-script */ opbuf = pretty_print_option(option, l->options[option].data, l->options[option].len, 0, 0); sbuf = option_as_string(option, l->options[option].data, l->options[option].len); switch (option) { case DHO_SUBNET_MASK: case DHO_TIME_SERVERS: case DHO_NAME_SERVERS: case DHO_ROUTERS: case DHO_DOMAIN_NAME_SERVERS: case DHO_LOG_SERVERS: case DHO_COOKIE_SERVERS: case DHO_LPR_SERVERS: case DHO_IMPRESS_SERVERS: case DHO_RESOURCE_LOCATION_SERVERS: case DHO_SWAP_SERVER: case DHO_BROADCAST_ADDRESS: case DHO_NIS_SERVERS: case DHO_NTP_SERVERS: case DHO_NETBIOS_NAME_SERVERS: case DHO_NETBIOS_DD_SERVER: case DHO_FONT_SERVERS: case DHO_DHCP_SERVER_IDENTIFIER: case DHO_NISPLUS_SERVERS: case DHO_MOBILE_IP_HOME_AGENT: case DHO_SMTP_SERVER: case DHO_POP_SERVER: case DHO_NNTP_SERVER: case DHO_WWW_SERVER: case DHO_FINGER_SERVER: case DHO_IRC_SERVER: case DHO_STREETTALK_SERVER: case DHO_STREETTALK_DA_SERVER: if (!ipv4addrs(opbuf)) { warning("Invalid IP address in option: %s", opbuf); return (0); } return (1) ; case DHO_HOST_NAME: case DHO_NIS_DOMAIN: case DHO_NISPLUS_DOMAIN: case DHO_TFTP_SERVER_NAME: if (!res_hnok(sbuf)) { warning("Bogus Host Name option %d: %s (%s)", option, sbuf, opbuf); l->options[option].len = 0; free(l->options[option].data); } return (1); case DHO_DOMAIN_NAME: case DHO_DOMAIN_SEARCH: if (!res_hnok(sbuf)) { if (!check_search(sbuf)) { warning("Bogus domain search list %d: %s (%s)", option, sbuf, opbuf); l->options[option].len = 0; free(l->options[option].data); } } return (1); case DHO_PAD: case DHO_TIME_OFFSET: case DHO_BOOT_SIZE: case DHO_MERIT_DUMP: case DHO_ROOT_PATH: case DHO_EXTENSIONS_PATH: case DHO_IP_FORWARDING: case DHO_NON_LOCAL_SOURCE_ROUTING: case DHO_POLICY_FILTER: case DHO_MAX_DGRAM_REASSEMBLY: case DHO_DEFAULT_IP_TTL: case DHO_PATH_MTU_AGING_TIMEOUT: case DHO_PATH_MTU_PLATEAU_TABLE: case DHO_INTERFACE_MTU: case DHO_ALL_SUBNETS_LOCAL: case DHO_PERFORM_MASK_DISCOVERY: case DHO_MASK_SUPPLIER: case DHO_ROUTER_DISCOVERY: case DHO_ROUTER_SOLICITATION_ADDRESS: case DHO_STATIC_ROUTES: case DHO_TRAILER_ENCAPSULATION: case DHO_ARP_CACHE_TIMEOUT: case DHO_IEEE802_3_ENCAPSULATION: case DHO_DEFAULT_TCP_TTL: case DHO_TCP_KEEPALIVE_INTERVAL: case DHO_TCP_KEEPALIVE_GARBAGE: case DHO_VENDOR_ENCAPSULATED_OPTIONS: case DHO_NETBIOS_NODE_TYPE: case DHO_NETBIOS_SCOPE: case DHO_X_DISPLAY_MANAGER: case DHO_DHCP_REQUESTED_ADDRESS: case DHO_DHCP_LEASE_TIME: case DHO_DHCP_OPTION_OVERLOAD: case DHO_DHCP_MESSAGE_TYPE: case DHO_DHCP_PARAMETER_REQUEST_LIST: case DHO_DHCP_MESSAGE: case DHO_DHCP_MAX_MESSAGE_SIZE: case DHO_DHCP_RENEWAL_TIME: case DHO_DHCP_REBINDING_TIME: case DHO_DHCP_CLASS_IDENTIFIER: case DHO_DHCP_CLIENT_IDENTIFIER: case DHO_BOOTFILE_NAME: case DHO_DHCP_USER_CLASS_ID: case DHO_END: return (1); case DHO_CLASSLESS_ROUTES: return (check_classless_option(l->options[option].data, l->options[option].len)); default: warning("unknown dhcp option value 0x%x", option); return (unknown_ok); } } /* RFC 3442 The Classless Static Routes option checks */ int check_classless_option(unsigned char *data, int len) { int i = 0; unsigned char width; in_addr_t addr, mask; if (len < 5) { warning("Too small length: %d", len); return (0); } while(i < len) { width = data[i++]; if (width == 0) { i += 4; continue; } else if (width < 9) { addr = (in_addr_t)(data[i] << 24); i += 1; } else if (width < 17) { addr = (in_addr_t)(data[i] << 24) + (in_addr_t)(data[i + 1] << 16); i += 2; } else if (width < 25) { addr = (in_addr_t)(data[i] << 24) + (in_addr_t)(data[i + 1] << 16) + (in_addr_t)(data[i + 2] << 8); i += 3; } else if (width < 33) { addr = (in_addr_t)(data[i] << 24) + (in_addr_t)(data[i + 1] << 16) + (in_addr_t)(data[i + 2] << 8) + data[i + 3]; i += 4; } else { warning("Incorrect subnet width: %d", width); return (0); } mask = (in_addr_t)(~0) << (32 - width); addr = ntohl(addr); mask = ntohl(mask); /* * From RFC 3442: * ... After deriving a subnet number and subnet mask * from each destination descriptor, the DHCP client * MUST zero any bits in the subnet number where the * corresponding bit in the mask is zero... */ if ((addr & mask) != addr) { addr &= mask; data[i - 1] = (unsigned char)( (addr >> (((32 - width)/8)*8)) & 0xFF); } i += 4; } if (i > len) { warning("Incorrect data length: %d (must be %d)", len, i); return (0); } return (1); } int res_hnok(const char *dn) { int pch = PERIOD, ch = *dn++; while (ch != '\0') { int nch = *dn++; if (periodchar(ch)) { ; } else if (periodchar(pch)) { if (!borderchar(ch)) return (0); } else if (periodchar(nch) || nch == '\0') { if (!borderchar(ch)) return (0); } else { if (!middlechar(ch)) return (0); } pch = ch, ch = nch; } return (1); } int check_search(const char *srch) { int pch = PERIOD, ch = *srch++; int domains = 1; /* 256 char limit re resolv.conf(5) */ if (strlen(srch) > 256) return (0); while (whitechar(ch)) ch = *srch++; while (ch != '\0') { int nch = *srch++; if (periodchar(ch) || whitechar(ch)) { ; } else if (periodchar(pch)) { if (!borderchar(ch)) return (0); } else if (periodchar(nch) || nch == '\0') { if (!borderchar(ch)) return (0); } else { if (!middlechar(ch)) return (0); } if (!whitechar(ch)) { pch = ch; } else { while (whitechar(nch)) { nch = *srch++; } if (nch != '\0') domains++; pch = PERIOD; } ch = nch; } /* 6 domain limit re resolv.conf(5) */ if (domains > 6) return (0); return (1); } /* Does buf consist only of dotted decimal ipv4 addrs? * return how many if so, * otherwise, return 0 */ int ipv4addrs(const char * buf) { struct in_addr jnk; int count = 0; while (inet_aton(buf, &jnk) == 1){ count++; while (periodchar(*buf) || digitchar(*buf)) buf++; if (*buf == '\0') return (count); while (*buf == ' ') buf++; } return (0); } const char * option_as_string(unsigned int code, unsigned char *data, int len) { static char optbuf[32768]; /* XXX */ char *op = optbuf; int opleft = sizeof(optbuf); unsigned char *dp = data; if (code > 255) error("option_as_string: bad code %d", code); for (; dp < data + len; dp++) { if (!isascii(*dp) || !isprint(*dp)) { if (dp + 1 != data + len || *dp != 0) { snprintf(op, opleft, "\\%03o", *dp); op += 4; opleft -= 4; } } else if (*dp == '"' || *dp == '\'' || *dp == '$' || *dp == '`' || *dp == '\\') { *op++ = '\\'; *op++ = *dp; opleft -= 2; } else { *op++ = *dp; opleft--; } } if (opleft < 1) goto toobig; *op = 0; return optbuf; toobig: warning("dhcp option too large"); return ""; } int fork_privchld(int fd, int fd2) { struct pollfd pfd[1]; int nfds; switch (fork()) { case -1: error("cannot fork"); case 0: break; default: return (0); } setproctitle("%s [priv]", ifi->name); setsid(); dup2(nullfd, STDIN_FILENO); dup2(nullfd, STDOUT_FILENO); dup2(nullfd, STDERR_FILENO); close(nullfd); close(fd2); close(ifi->rfdesc); ifi->rfdesc = -1; for (;;) { pfd[0].fd = fd; pfd[0].events = POLLIN; if ((nfds = poll(pfd, 1, INFTIM)) == -1) if (errno != EINTR) error("poll error"); if (nfds == 0 || !(pfd[0].revents & POLLIN)) continue; dispatch_imsg(ifi, fd); } } Index: head/sbin/dumpon/dumpon.c =================================================================== --- head/sbin/dumpon/dumpon.c (revision 335394) +++ head/sbin/dumpon/dumpon.c (revision 335395) @@ -1,495 +1,496 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1980, 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. */ #if 0 #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1980, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "From: @(#)swapon.c 8.1 (Berkeley) 6/5/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CRYPTO #include #include #include #endif static int verbose; static void _Noreturn usage(void) { fprintf(stderr, "usage: dumpon [-v] [-k ] [-Zz] \n" " dumpon [-v] [-k ] [-Zz]\n" " [-g |default] -s -c \n" " dumpon [-v] off\n" " dumpon [-v] -l\n"); exit(EX_USAGE); } /* * Look for a default route on the specified interface. */ static char * find_gateway(const char *ifname) { struct ifaddrs *ifa, *ifap; struct rt_msghdr *rtm; struct sockaddr *sa; struct sockaddr_dl *sdl; struct sockaddr_in *dst, *mask, *gw; char *buf, *next, *ret; size_t sz; int error, i, ifindex, mib[7]; ret = NULL; /* First look up the interface index. */ if (getifaddrs(&ifap) != 0) err(EX_OSERR, "getifaddrs"); for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != AF_LINK) continue; if (strcmp(ifa->ifa_name, ifname) == 0) { sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr; ifindex = sdl->sdl_index; break; } } if (ifa == NULL) errx(1, "couldn't find interface index for '%s'", ifname); freeifaddrs(ifap); /* Now get the IPv4 routing table. */ mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET; mib[4] = NET_RT_DUMP; mib[5] = 0; mib[6] = -1; /* FIB */ for (;;) { if (sysctl(mib, nitems(mib), NULL, &sz, NULL, 0) != 0) err(EX_OSERR, "sysctl(NET_RT_DUMP)"); buf = malloc(sz); error = sysctl(mib, nitems(mib), buf, &sz, NULL, 0); if (error == 0) break; if (errno != ENOMEM) err(EX_OSERR, "sysctl(NET_RT_DUMP)"); free(buf); } for (next = buf; next < buf + sz; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)(void *)next; if (rtm->rtm_version != RTM_VERSION) continue; if ((rtm->rtm_flags & RTF_GATEWAY) == 0 || rtm->rtm_index != ifindex) continue; dst = gw = mask = NULL; sa = (struct sockaddr *)(rtm + 1); for (i = 0; i < RTAX_MAX; i++) { if ((rtm->rtm_addrs & (1 << i)) != 0) { switch (i) { case RTAX_DST: dst = (void *)sa; break; case RTAX_GATEWAY: gw = (void *)sa; break; case RTAX_NETMASK: mask = (void *)sa; break; } } sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa)); } if (dst->sin_addr.s_addr == INADDR_ANY && mask->sin_addr.s_addr == 0) { ret = inet_ntoa(gw->sin_addr); break; } } free(buf); return (ret); } static void check_size(int fd, const char *fn) { int name[] = { CTL_HW, HW_PHYSMEM }; size_t namelen = nitems(name); unsigned long physmem; size_t len; off_t mediasize; int minidump; len = sizeof(minidump); if (sysctlbyname("debug.minidump", &minidump, &len, NULL, 0) == 0 && minidump == 1) return; len = sizeof(physmem); if (sysctl(name, namelen, &physmem, &len, NULL, 0) != 0) err(EX_OSERR, "can't get memory size"); if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) != 0) err(EX_OSERR, "%s: can't get size", fn); if ((uintmax_t)mediasize < (uintmax_t)physmem) { if (verbose) printf("%s is smaller than physical memory\n", fn); exit(EX_IOERR); } } #ifdef HAVE_CRYPTO static void genkey(const char *pubkeyfile, struct diocskerneldump_arg *kdap) { FILE *fp; RSA *pubkey; assert(pubkeyfile != NULL); assert(kdap != NULL); fp = NULL; pubkey = NULL; fp = fopen(pubkeyfile, "r"); if (fp == NULL) err(1, "Unable to open %s", pubkeyfile); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "Unable to enter capability mode"); pubkey = RSA_new(); if (pubkey == NULL) { errx(1, "Unable to allocate an RSA structure: %s", ERR_error_string(ERR_get_error(), NULL)); } pubkey = PEM_read_RSA_PUBKEY(fp, &pubkey, NULL, NULL); fclose(fp); fp = NULL; if (pubkey == NULL) errx(1, "Unable to read data from %s.", pubkeyfile); kdap->kda_encryptedkeysize = RSA_size(pubkey); if (kdap->kda_encryptedkeysize > KERNELDUMP_ENCKEY_MAX_SIZE) { errx(1, "Public key has to be at most %db long.", 8 * KERNELDUMP_ENCKEY_MAX_SIZE); } kdap->kda_encryptedkey = calloc(1, kdap->kda_encryptedkeysize); if (kdap->kda_encryptedkey == NULL) err(1, "Unable to allocate encrypted key"); kdap->kda_encryption = KERNELDUMP_ENC_AES_256_CBC; arc4random_buf(kdap->kda_key, sizeof(kdap->kda_key)); if (RSA_public_encrypt(sizeof(kdap->kda_key), kdap->kda_key, kdap->kda_encryptedkey, pubkey, RSA_PKCS1_PADDING) != (int)kdap->kda_encryptedkeysize) { errx(1, "Unable to encrypt the one-time key."); } RSA_free(pubkey); } #endif static void listdumpdev(void) { char dumpdev[PATH_MAX]; struct netdump_conf ndconf; size_t len; const char *sysctlname = "kern.shutdown.dumpdevname"; int fd; len = sizeof(dumpdev); if (sysctlbyname(sysctlname, &dumpdev, &len, NULL, 0) != 0) { if (errno == ENOMEM) { err(EX_OSERR, "Kernel returned too large of a buffer for '%s'\n", sysctlname); } else { err(EX_OSERR, "Sysctl get '%s'\n", sysctlname); } } if (strlen(dumpdev) == 0) (void)strlcpy(dumpdev, _PATH_DEVNULL, sizeof(dumpdev)); if (verbose) printf("kernel dumps on "); printf("%s\n", dumpdev); /* If netdump is enabled, print the configuration parameters. */ if (verbose) { fd = open(_PATH_NETDUMP, O_RDONLY); if (fd < 0) { if (errno != ENOENT) err(EX_OSERR, "opening %s", _PATH_NETDUMP); return; } if (ioctl(fd, NETDUMPGCONF, &ndconf) != 0) { if (errno != ENXIO) err(EX_OSERR, "ioctl(NETDUMPGCONF)"); (void)close(fd); return; } printf("server address: %s\n", inet_ntoa(ndconf.ndc_server)); printf("client address: %s\n", inet_ntoa(ndconf.ndc_client)); printf("gateway address: %s\n", inet_ntoa(ndconf.ndc_gateway)); (void)close(fd); } } static int opendumpdev(const char *arg, char *dumpdev) { int fd, i; if (strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) strlcpy(dumpdev, arg, PATH_MAX); else { i = snprintf(dumpdev, PATH_MAX, "%s%s", _PATH_DEV, arg); if (i < 0) err(EX_OSERR, "%s", arg); if (i >= PATH_MAX) errc(EX_DATAERR, EINVAL, "%s", arg); } fd = open(dumpdev, O_RDONLY); if (fd < 0) err(EX_OSFILE, "%s", dumpdev); return (fd); } int main(int argc, char *argv[]) { char dumpdev[PATH_MAX]; struct diocskerneldump_arg _kda, *kdap; struct netdump_conf ndconf; struct addrinfo hints, *res; const char *dev, *pubkeyfile, *server, *client, *gateway; int ch, error, fd; bool enable, gzip, list, netdump, zstd; gzip = list = netdump = zstd = false; kdap = NULL; pubkeyfile = NULL; server = client = gateway = NULL; while ((ch = getopt(argc, argv, "c:g:k:ls:vZz")) != -1) switch ((char)ch) { case 'c': client = optarg; break; case 'g': gateway = optarg; break; case 'k': pubkeyfile = optarg; break; case 'l': list = true; break; case 's': server = optarg; break; case 'v': verbose = 1; break; case 'Z': zstd = true; break; case 'z': gzip = true; break; default: usage(); } if (gzip && zstd) errx(EX_USAGE, "The -z and -Z options are mutually exclusive."); argc -= optind; argv += optind; if (list) { listdumpdev(); exit(EX_OK); } if (argc != 1) usage(); #ifndef HAVE_CRYPTO if (pubkeyfile != NULL) errx(EX_UNAVAILABLE,"Unable to use the public key." " Recompile dumpon with OpenSSL support."); #endif if (server != NULL && client != NULL) { enable = true; dev = _PATH_NETDUMP; netdump = true; kdap = &ndconf.ndc_kda; } else if (server == NULL && client == NULL && argc > 0) { enable = strcmp(argv[0], "off") != 0; dev = enable ? argv[0] : _PATH_DEVNULL; netdump = false; kdap = &_kda; } else usage(); fd = opendumpdev(dev, dumpdev); if (!netdump && !gzip) check_size(fd, dumpdev); bzero(kdap, sizeof(*kdap)); kdap->kda_enable = 0; if (ioctl(fd, DIOCSKERNELDUMP, kdap) != 0) err(EX_OSERR, "ioctl(DIOCSKERNELDUMP)"); if (!enable) exit(EX_OK); explicit_bzero(kdap, sizeof(*kdap)); kdap->kda_enable = 1; kdap->kda_compression = KERNELDUMP_COMP_NONE; if (zstd) kdap->kda_compression = KERNELDUMP_COMP_ZSTD; else if (gzip) kdap->kda_compression = KERNELDUMP_COMP_GZIP; if (netdump) { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_protocol = IPPROTO_UDP; res = NULL; error = getaddrinfo(server, NULL, &hints, &res); if (error != 0) err(1, "%s", gai_strerror(error)); if (res == NULL) errx(1, "failed to resolve '%s'", server); server = inet_ntoa( ((struct sockaddr_in *)(void *)res->ai_addr)->sin_addr); freeaddrinfo(res); if (strlcpy(ndconf.ndc_iface, argv[0], sizeof(ndconf.ndc_iface)) >= sizeof(ndconf.ndc_iface)) errx(EX_USAGE, "invalid interface name '%s'", argv[0]); if (inet_aton(server, &ndconf.ndc_server) == 0) errx(EX_USAGE, "invalid server address '%s'", server); if (inet_aton(client, &ndconf.ndc_client) == 0) errx(EX_USAGE, "invalid client address '%s'", client); if (gateway == NULL) gateway = server; else if (strcmp(gateway, "default") == 0 && (gateway = find_gateway(argv[0])) == NULL) errx(EX_NOHOST, "failed to look up next-hop router for %s", server); if (inet_aton(gateway, &ndconf.ndc_gateway) == 0) errx(EX_USAGE, "invalid gateway address '%s'", gateway); #ifdef HAVE_CRYPTO if (pubkeyfile != NULL) genkey(pubkeyfile, kdap); #endif error = ioctl(fd, NETDUMPSCONF, &ndconf); if (error != 0) error = errno; explicit_bzero(kdap->kda_encryptedkey, kdap->kda_encryptedkeysize); free(kdap->kda_encryptedkey); explicit_bzero(kdap, sizeof(*kdap)); if (error != 0) errc(EX_OSERR, error, "ioctl(NETDUMPSCONF)"); } else { #ifdef HAVE_CRYPTO if (pubkeyfile != NULL) genkey(pubkeyfile, kdap); #endif error = ioctl(fd, DIOCSKERNELDUMP, kdap); if (error != 0) error = errno; explicit_bzero(kdap->kda_encryptedkey, kdap->kda_encryptedkeysize); free(kdap->kda_encryptedkey); explicit_bzero(kdap, sizeof(*kdap)); if (error != 0) errc(EX_OSERR, error, "ioctl(DIOCSKERNELDUMP)"); } if (verbose) printf("kernel dumps on %s\n", dumpdev); exit(EX_OK); } Index: head/sbin/md5/md5.c =================================================================== --- head/sbin/md5/md5.c (revision 335394) +++ head/sbin/md5/md5.c (revision 335395) @@ -1,504 +1,502 @@ /* * Derived from: * * MDDRIVER.C - test driver for MD2, MD4 and MD5 */ /* * Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All * rights reserved. * * RSA Data Security, Inc. makes no representations concerning either * the merchantability of this software or the suitability of this * software for any particular purpose. It is provided "as is" * without express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * documentation and/or software. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Length of test block, number of test blocks. */ #define TEST_BLOCK_LEN 10000 #define TEST_BLOCK_COUNT 100000 #define MDTESTCOUNT 8 static int qflag; static int rflag; static int sflag; static char* checkAgainst; static int checksFailed; typedef void (DIGEST_Init)(void *); typedef void (DIGEST_Update)(void *, const unsigned char *, size_t); typedef char *(DIGEST_End)(void *, char *); extern const char *MD5TestOutput[MDTESTCOUNT]; extern const char *SHA1_TestOutput[MDTESTCOUNT]; extern const char *SHA256_TestOutput[MDTESTCOUNT]; extern const char *SHA384_TestOutput[MDTESTCOUNT]; extern const char *SHA512_TestOutput[MDTESTCOUNT]; extern const char *SHA512t256_TestOutput[MDTESTCOUNT]; extern const char *RIPEMD160_TestOutput[MDTESTCOUNT]; extern const char *SKEIN256_TestOutput[MDTESTCOUNT]; extern const char *SKEIN512_TestOutput[MDTESTCOUNT]; extern const char *SKEIN1024_TestOutput[MDTESTCOUNT]; typedef struct Algorithm_t { const char *progname; const char *name; const char *(*TestOutput)[MDTESTCOUNT]; DIGEST_Init *Init; DIGEST_Update *Update; DIGEST_End *End; char *(*Data)(const void *, unsigned int, char *); char *(*Fd)(int, char *); } Algorithm_t; static void MD5_Update(MD5_CTX *, const unsigned char *, size_t); static void MDString(const Algorithm_t *, const char *); static void MDTimeTrial(const Algorithm_t *); static void MDTestSuite(const Algorithm_t *); static void MDFilter(const Algorithm_t *, int); static void usage(const Algorithm_t *); typedef union { MD5_CTX md5; SHA1_CTX sha1; SHA256_CTX sha256; SHA384_CTX sha384; SHA512_CTX sha512; RIPEMD160_CTX ripemd160; SKEIN256_CTX skein256; SKEIN512_CTX skein512; SKEIN1024_CTX skein1024; } DIGEST_CTX; /* max(MD5_DIGEST_LENGTH, SHA_DIGEST_LENGTH, SHA256_DIGEST_LENGTH, SHA512_DIGEST_LENGTH, RIPEMD160_DIGEST_LENGTH, SKEIN1024_DIGEST_LENGTH)*2+1 */ #define HEX_DIGEST_LENGTH 257 /* algorithm function table */ static const struct Algorithm_t Algorithm[] = { { "md5", "MD5", &MD5TestOutput, (DIGEST_Init*)&MD5Init, (DIGEST_Update*)&MD5_Update, (DIGEST_End*)&MD5End, &MD5Data, &MD5Fd }, { "sha1", "SHA1", &SHA1_TestOutput, (DIGEST_Init*)&SHA1_Init, (DIGEST_Update*)&SHA1_Update, (DIGEST_End*)&SHA1_End, &SHA1_Data, &SHA1_Fd }, { "sha256", "SHA256", &SHA256_TestOutput, (DIGEST_Init*)&SHA256_Init, (DIGEST_Update*)&SHA256_Update, (DIGEST_End*)&SHA256_End, &SHA256_Data, &SHA256_Fd }, { "sha384", "SHA384", &SHA384_TestOutput, (DIGEST_Init*)&SHA384_Init, (DIGEST_Update*)&SHA384_Update, (DIGEST_End*)&SHA384_End, &SHA384_Data, &SHA384_Fd }, { "sha512", "SHA512", &SHA512_TestOutput, (DIGEST_Init*)&SHA512_Init, (DIGEST_Update*)&SHA512_Update, (DIGEST_End*)&SHA512_End, &SHA512_Data, &SHA512_Fd }, { "sha512t256", "SHA512t256", &SHA512t256_TestOutput, (DIGEST_Init*)&SHA512_256_Init, (DIGEST_Update*)&SHA512_256_Update, (DIGEST_End*)&SHA512_256_End, &SHA512_256_Data, &SHA512_256_Fd }, { "rmd160", "RMD160", &RIPEMD160_TestOutput, (DIGEST_Init*)&RIPEMD160_Init, (DIGEST_Update*)&RIPEMD160_Update, (DIGEST_End*)&RIPEMD160_End, &RIPEMD160_Data, &RIPEMD160_Fd }, { "skein256", "Skein256", &SKEIN256_TestOutput, (DIGEST_Init*)&SKEIN256_Init, (DIGEST_Update*)&SKEIN256_Update, (DIGEST_End*)&SKEIN256_End, &SKEIN256_Data, &SKEIN256_Fd }, { "skein512", "Skein512", &SKEIN512_TestOutput, (DIGEST_Init*)&SKEIN512_Init, (DIGEST_Update*)&SKEIN512_Update, (DIGEST_End*)&SKEIN512_End, &SKEIN512_Data, &SKEIN512_Fd }, { "skein1024", "Skein1024", &SKEIN1024_TestOutput, (DIGEST_Init*)&SKEIN1024_Init, (DIGEST_Update*)&SKEIN1024_Update, (DIGEST_End*)&SKEIN1024_End, &SKEIN1024_Data, &SKEIN1024_Fd } }; static void MD5_Update(MD5_CTX *c, const unsigned char *data, size_t len) { MD5Update(c, data, len); } /* Main driver. Arguments (may be any combination): -sstring - digests string -t - runs time trial -x - runs test script filename - digests file (none) - digests standard input */ int main(int argc, char *argv[]) { cap_rights_t rights; int ch, fd; char *p; char buf[HEX_DIGEST_LENGTH]; int failed; unsigned digest; const char* progname; if ((progname = strrchr(argv[0], '/')) == NULL) progname = argv[0]; else progname++; for (digest = 0; digest < sizeof(Algorithm)/sizeof(*Algorithm); digest++) if (strcasecmp(Algorithm[digest].progname, progname) == 0) break; if (digest == sizeof(Algorithm)/sizeof(*Algorithm)) digest = 0; failed = 0; checkAgainst = NULL; checksFailed = 0; while ((ch = getopt(argc, argv, "c:pqrs:tx")) != -1) switch (ch) { case 'c': checkAgainst = optarg; break; case 'p': MDFilter(&Algorithm[digest], 1); break; case 'q': qflag = 1; break; case 'r': rflag = 1; break; case 's': sflag = 1; MDString(&Algorithm[digest], optarg); break; case 't': MDTimeTrial(&Algorithm[digest]); break; case 'x': MDTestSuite(&Algorithm[digest]); break; default: usage(&Algorithm[digest]); } argc -= optind; argv += optind; if (caph_limit_stdout() < 0 || caph_limit_stderr() < 0) err(1, "unable to limit rights for stdio"); if (*argv) { do { if ((fd = open(*argv, O_RDONLY)) < 0) { warn("%s", *argv); failed++; continue; } /* * XXX Enter capability mode on the last argv file. * When a casper file service or other approach is * available, switch to that and enter capability mode * earlier. */ if (*(argv + 1) == NULL) { cap_rights_init(&rights, CAP_READ); if ((cap_rights_limit(fd, &rights) < 0 && - errno != ENOSYS) || - (cap_enter() < 0 && errno != ENOSYS)) + errno != ENOSYS) || caph_enter() < 0) err(1, "capsicum"); } if ((p = Algorithm[digest].Fd(fd, buf)) == NULL) { warn("%s", *argv); failed++; } else { if (qflag) printf("%s", p); else if (rflag) printf("%s %s", p, *argv); else printf("%s (%s) = %s", Algorithm[digest].name, *argv, p); if (checkAgainst && strcasecmp(checkAgainst, p) != 0) { checksFailed++; if (!qflag) printf(" [ Failed ]"); } printf("\n"); } } while (*++argv); } else if (!sflag && (optind == 1 || qflag || rflag)) { - if (caph_limit_stdin() < 0 || - (cap_enter() < 0 && errno != ENOSYS)) + if (caph_limit_stdin() < 0 || caph_enter() < 0) err(1, "capsicum"); MDFilter(&Algorithm[digest], 0); } if (failed != 0) return (1); if (checksFailed != 0) return (2); return (0); } /* * Digests a string and prints the result. */ static void MDString(const Algorithm_t *alg, const char *string) { size_t len = strlen(string); char buf[HEX_DIGEST_LENGTH]; alg->Data(string,len,buf); if (qflag) printf("%s", buf); else if (rflag) printf("%s \"%s\"", buf, string); else printf("%s (\"%s\") = %s", alg->name, string, buf); if (checkAgainst && strcasecmp(buf,checkAgainst) != 0) { checksFailed++; if (!qflag) printf(" [ failed ]"); } printf("\n"); } /* * Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks. */ static void MDTimeTrial(const Algorithm_t *alg) { DIGEST_CTX context; struct rusage before, after; struct timeval total; float seconds; unsigned char block[TEST_BLOCK_LEN]; unsigned int i; char *p, buf[HEX_DIGEST_LENGTH]; printf("%s time trial. Digesting %d %d-byte blocks ...", alg->name, TEST_BLOCK_COUNT, TEST_BLOCK_LEN); fflush(stdout); /* Initialize block */ for (i = 0; i < TEST_BLOCK_LEN; i++) block[i] = (unsigned char) (i & 0xff); /* Start timer */ getrusage(RUSAGE_SELF, &before); /* Digest blocks */ alg->Init(&context); for (i = 0; i < TEST_BLOCK_COUNT; i++) alg->Update(&context, block, TEST_BLOCK_LEN); p = alg->End(&context, buf); /* Stop timer */ getrusage(RUSAGE_SELF, &after); timersub(&after.ru_utime, &before.ru_utime, &total); seconds = total.tv_sec + (float) total.tv_usec / 1000000; printf(" done\n"); printf("Digest = %s", p); printf("\nTime = %f seconds\n", seconds); printf("Speed = %f MiB/second\n", (float) TEST_BLOCK_LEN * (float) TEST_BLOCK_COUNT / seconds / (1 << 20)); } /* * Digests a reference suite of strings and prints the results. */ static const char *MDTestInput[MDTESTCOUNT] = { "", "a", "abc", "message digest", "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "12345678901234567890123456789012345678901234567890123456789012345678901234567890", "MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been made \ that its security is in some doubt" }; const char *MD5TestOutput[MDTESTCOUNT] = { "d41d8cd98f00b204e9800998ecf8427e", "0cc175b9c0f1b6a831c399e269772661", "900150983cd24fb0d6963f7d28e17f72", "f96b697d7cb7938d525a2f31aaf161d0", "c3fcd3d76192e4007dfb496cca67e13b", "d174ab98d277d9f5a5611c2c9f419d9f", "57edf4a22be3c955ac49da2e2107b67a", "b50663f41d44d92171cb9976bc118538" }; const char *SHA1_TestOutput[MDTESTCOUNT] = { "da39a3ee5e6b4b0d3255bfef95601890afd80709", "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a9993e364706816aba3e25717850c26c9cd0d89d", "c12252ceda8be8994d5fa0290a47231c1d16aae3", "32d10c7b8cf96570ca04ce37f2a19d84240d3a89", "761c457bf73b14d27e9e9265c46f4b4dda11f940", "50abf5706a150990a08b2c5ea40fa0e585554732", "18eca4333979c4181199b7b4fab8786d16cf2846" }; const char *SHA256_TestOutput[MDTESTCOUNT] = { "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650", "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73", "db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0", "f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e", "e6eae09f10ad4122a0e2a4075761d185a272ebd9f5aa489e998ff2f09cbfdd9f" }; const char *SHA384_TestOutput[MDTESTCOUNT] = { "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "473ed35167ec1f5d8e550368a3db39be54639f828868e9454c239fc8b52e3c61dbd0d8b4de1390c256dcbb5d5fd99cd5", "feb67349df3db6f5924815d6c3dc133f091809213731fe5c7b5f4999e463479ff2877f5f2936fa63bb43784b12f3ebb4", "1761336e3f7cbfe51deb137f026f89e01a448e3b1fafa64039c1464ee8732f11a5341a6f41e0c202294736ed64db1a84", "b12932b0627d1c060942f5447764155655bd4da0c9afa6dd9b9ef53129af1b8fb0195996d2de9ca0df9d821ffee67026", "99428d401bf4abcd4ee0695248c9858b7503853acfae21a9cffa7855f46d1395ef38596fcd06d5a8c32d41a839cc5dfb" }; const char *SHA512_TestOutput[MDTESTCOUNT] = { "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f3309e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c", "4dbff86cc2ca1bae1e16468a05cb9881c97f1753bce3619034898faa1aabe429955a1bf8ec483d7421fe3c1646613a59ed5441fb0f321389f77f48a879c7b1f1", "1e07be23c26a86ea37ea810c8ec7809352515a970e9253c26f536cfc7a9996c45c8370583e0a78fa4a90041d71a4ceab7423f19c71b9d5a3e01249f0bebd5894", "72ec1ef1124a45b047e8b7c75a932195135bb61de24ec0d1914042246e0aec3a2354e093d76f3048b456764346900cb130d2a4fd5dd16abb5e30bcb850dee843", "e8a835195e039708b13d9131e025f4441dbdc521ce625f245a436dcd762f54bf5cb298d96235e6c6a304e087ec8189b9512cbdf6427737ea82793460c367b9c3" }; const char *SHA512t256_TestOutput[MDTESTCOUNT] = { "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a", "455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8", "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23", "0cf471fd17ed69d990daf3433c89b16d63dec1bb9cb42a6094604ee5d7b4e9fb", "fc3189443f9c268f626aea08a756abe7b726b05f701cb08222312ccfd6710a26", "cdf1cc0effe26ecc0c13758f7b4a48e000615df241284185c39eb05d355bb9c8", "2c9fdbc0c90bdd87612ee8455474f9044850241dc105b1e8b94b8ddf5fac9148", "dd095fc859b336c30a52548b3dc59fcc0d1be8616ebcf3368fad23107db2d736" }; const char *RIPEMD160_TestOutput[MDTESTCOUNT] = { "9c1185a5c5e9fc54612808977ee8f548b2258d31", "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "5d0689ef49d2fae572b881b123a85ffa21595f36", "f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "b0e20b6e3116640286ed3a87a5713079b21f5189", "9b752e45573d4b39f4dbd3323cab82bf63326bfb", "5feb69c6bf7c29d95715ad55f57d8ac5b2b7dd32" }; const char *SKEIN256_TestOutput[MDTESTCOUNT] = { "c8877087da56e072870daa843f176e9453115929094c3a40c463a196c29bf7ba", "7fba44ff1a31d71a0c1f82e6e82fb5e9ac6c92a39c9185b9951fed82d82fe635", "258bdec343b9fde1639221a5ae0144a96e552e5288753c5fec76c05fc2fc1870", "4d2ce0062b5eb3a4db95bc1117dd8aa014f6cd50fdc8e64f31f7d41f9231e488", "46d8440685461b00e3ddb891b2ecc6855287d2bd8834a95fb1c1708b00ea5e82", "7c5eb606389556b33d34eb2536459528dc0af97adbcd0ce273aeb650f598d4b2", "4def7a7e5464a140ae9c3a80279fbebce4bd00f9faad819ab7e001512f67a10d", "d9c017dbe355f318d036469eb9b5fbe129fc2b5786a9dc6746a516eab6fe0126" }; const char *SKEIN512_TestOutput[MDTESTCOUNT] = { "bc5b4c50925519c290cc634277ae3d6257212395cba733bbad37a4af0fa06af41fca7903d06564fea7a2d3730dbdb80c1f85562dfcc070334ea4d1d9e72cba7a", "b1cd8d33f61b3737adfd59bb13ad82f4a9548e92f22956a8976cca3fdb7fee4fe91698146c4197cec85d38b83c5d93bdba92c01fd9a53870d0c7f967bc62bdce", "8f5dd9ec798152668e35129496b029a960c9a9b88662f7f9482f110b31f9f93893ecfb25c009baad9e46737197d5630379816a886aa05526d3a70df272d96e75", "15b73c158ffb875fed4d72801ded0794c720b121c0c78edf45f900937e6933d9e21a3a984206933d504b5dbb2368000411477ee1b204c986068df77886542fcc", "23793ad900ef12f9165c8080da6fdfd2c8354a2929b8aadf83aa82a3c6470342f57cf8c035ec0d97429b626c4d94f28632c8f5134fd367dca5cf293d2ec13f8c", "0c6bed927e022f5ddcf81877d42e5f75798a9f8fd3ede3d83baac0a2f364b082e036c11af35fe478745459dd8f5c0b73efe3c56ba5bb2009208d5a29cc6e469c", "2ca9fcffb3456f297d1b5f407014ecb856f0baac8eb540f534b1f187196f21e88f31103128c2f03fcc9857d7a58eb66f9525e2302d88833ee069295537a434ce", "1131f2aaa0e97126c9314f9f968cc827259bbfabced2943bb8c9274448998fb3b78738b4580dd500c76105fd3c03e465e1414f2c29664286b1f79d3e51128125" }; const char *SKEIN1024_TestOutput[MDTESTCOUNT] = { "0fff9563bb3279289227ac77d319b6fff8d7e9f09da1247b72a0a265cd6d2a62645ad547ed8193db48cff847c06494a03f55666d3b47eb4c20456c9373c86297d630d5578ebd34cb40991578f9f52b18003efa35d3da6553ff35db91b81ab890bec1b189b7f52cb2a783ebb7d823d725b0b4a71f6824e88f68f982eefc6d19c6", "6ab4c4ba9814a3d976ec8bffa7fcc638ceba0544a97b3c98411323ffd2dc936315d13dc93c13c4e88cda6f5bac6f2558b2d8694d3b6143e40d644ae43ca940685cb37f809d3d0550c56cba8036dee729a4f8fb960732e59e64d57f7f7710f8670963cdcdc95b41daab4855fcf8b6762a64b173ee61343a2c7689af1d293eba97", "35a599a0f91abcdb4cb73c19b8cb8d947742d82c309137a7caed29e8e0a2ca7a9ff9a90c34c1908cc7e7fd99bb15032fb86e76df21b72628399b5f7c3cc209d7bb31c99cd4e19465622a049afbb87c03b5ce3888d17e6e667279ec0aa9b3e2712624c01b5f5bbe1a564220bdcf6990af0c2539019f313fdd7406cca3892a1f1f", "ea891f5268acd0fac97467fc1aa89d1ce8681a9992a42540e53babee861483110c2d16f49e73bac27653ff173003e40cfb08516cd34262e6af95a5d8645c9c1abb3e813604d508b8511b30f9a5c1b352aa0791c7d2f27b2706dccea54bc7de6555b5202351751c3299f97c09cf89c40f67187e2521c0fad82b30edbb224f0458", "f23d95c2a25fbcd0e797cd058fec39d3c52d2b5afd7a9af1df934e63257d1d3dcf3246e7329c0f1104c1e51e3d22e300507b0c3b9f985bb1f645ef49835080536becf83788e17fed09c9982ba65c3cb7ffe6a5f745b911c506962adf226e435c42f6f6bc08d288f9c810e807e3216ef444f3db22744441deefa4900982a1371f", "cf3889e8a8d11bfd3938055d7d061437962bc5eac8ae83b1b71c94be201b8cf657fdbfc38674997a008c0c903f56a23feb3ae30e012377f1cfa080a9ca7fe8b96138662653fb3335c7d06595bf8baf65e215307532094cfdfa056bd8052ab792a3944a2adaa47b30335b8badb8fe9eb94fe329cdca04e58bbc530f0af709f469", "cf21a613620e6c119eca31fdfaad449a8e02f95ca256c21d2a105f8e4157048f9fe1e897893ea18b64e0e37cb07d5ac947f27ba544caf7cbc1ad094e675aed77a366270f7eb7f46543bccfa61c526fd628408058ed00ed566ac35a9761d002e629c4fb0d430b2f4ad016fcc49c44d2981c4002da0eecc42144160e2eaea4855a", "e6799b78db54085a2be7ff4c8007f147fa88d326abab30be0560b953396d8802feee9a15419b48a467574e9283be15685ca8a079ee52b27166b64dd70b124b1d4e4f6aca37224c3f2685e67e67baef9f94b905698adc794a09672aba977a61b20966912acdb08c21a2c37001785355dc884751a21f848ab36e590331ff938138" }; static void MDTestSuite(const Algorithm_t *alg) { int i; char buffer[HEX_DIGEST_LENGTH]; printf("%s test suite:\n", alg->name); for (i = 0; i < MDTESTCOUNT; i++) { (*alg->Data)(MDTestInput[i], strlen(MDTestInput[i]), buffer); printf("%s (\"%s\") = %s", alg->name, MDTestInput[i], buffer); if (strcmp(buffer, (*alg->TestOutput)[i]) == 0) printf(" - verified correct\n"); else printf(" - INCORRECT RESULT!\n"); } } /* * Digests the standard input and prints the result. */ static void MDFilter(const Algorithm_t *alg, int tee) { DIGEST_CTX context; unsigned int len; unsigned char buffer[BUFSIZ]; char buf[HEX_DIGEST_LENGTH]; alg->Init(&context); while ((len = fread(buffer, 1, BUFSIZ, stdin))) { if (tee && len != fwrite(buffer, 1, len, stdout)) err(1, "stdout"); alg->Update(&context, buffer, len); } printf("%s\n", alg->End(&context, buf)); } static void usage(const Algorithm_t *alg) { fprintf(stderr, "usage: %s [-pqrtx] [-c string] [-s string] [files ...]\n", alg->progname); exit(1); } Index: head/usr.bin/basename/basename.c =================================================================== --- head/usr.bin/basename/basename.c (revision 335394) +++ head/usr.bin/basename/basename.c (revision 335395) @@ -1,149 +1,149 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1991, 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1991, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif #if 0 #ifndef lint static char sccsid[] = "@(#)basename.c 8.4 (Berkeley) 5/4/95"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include void stripsuffix(char *, const char *, size_t); void usage(void); int main(int argc, char **argv) { char *p, *suffix; size_t suffixlen; int aflag, ch; setlocale(LC_ALL, ""); - if (caph_limit_stdio() < 0 || (cap_enter() < 0 && errno != ENOSYS)) + if (caph_limit_stdio() < 0 || caph_enter() < 0) err(1, "capsicum"); aflag = 0; suffix = NULL; suffixlen = 0; while ((ch = getopt(argc, argv, "as:")) != -1) switch(ch) { case 'a': aflag = 1; break; case 's': suffix = optarg; break; case '?': default: usage(); } argc -= optind; argv += optind; if (argc < 1) usage(); if (!*argv[0]) { printf("\n"); exit(0); } if ((p = basename(argv[0])) == NULL) err(1, "%s", argv[0]); if ((suffix == NULL && !aflag) && argc == 2) { suffix = argv[1]; argc--; } if (suffix != NULL) suffixlen = strlen(suffix); while (argc--) { if ((p = basename(*argv)) == NULL) err(1, "%s", argv[0]); stripsuffix(p, suffix, suffixlen); argv++; (void)printf("%s\n", p); } exit(0); } void stripsuffix(char *p, const char *suffix, size_t suffixlen) { char *q, *r; mbstate_t mbs; size_t n; if (suffixlen && (q = strchr(p, '\0') - suffixlen) > p && strcmp(suffix, q) == 0) { /* Ensure that the match occurred on a character boundary. */ memset(&mbs, 0, sizeof(mbs)); for (r = p; r < q; r += n) { n = mbrlen(r, MB_LEN_MAX, &mbs); if (n == (size_t)-1 || n == (size_t)-2) { memset(&mbs, 0, sizeof(mbs)); n = 1; } } /* Chop off the suffix. */ if (q == r) *q = '\0'; } } void usage(void) { (void)fprintf(stderr, "usage: basename string [suffix]\n" " basename [-a] [-s suffix] string [...]\n"); exit(1); } Index: head/usr.bin/cmp/cmp.c =================================================================== --- head/usr.bin/cmp/cmp.c (revision 335394) +++ head/usr.bin/cmp/cmp.c (revision 335395) @@ -1,237 +1,237 @@ /* * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1987, 1990, 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1987, 1990, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif #if 0 #ifndef lint static char sccsid[] = "@(#)cmp.c 8.3 (Berkeley) 4/2/94"; #endif #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "extern.h" int lflag, sflag, xflag, zflag; static const struct option long_opts[] = { {"verbose", no_argument, NULL, 'l'}, {"silent", no_argument, NULL, 's'}, {"quiet", no_argument, NULL, 's'}, {NULL, no_argument, NULL, 0} }; static void usage(void); int main(int argc, char *argv[]) { struct stat sb1, sb2; off_t skip1, skip2; int ch, fd1, fd2, oflag, special; const char *file1, *file2; cap_rights_t rights; uint32_t fcntls; oflag = O_RDONLY; while ((ch = getopt_long(argc, argv, "+hlsxz", long_opts, NULL)) != -1) switch (ch) { case 'h': /* Don't follow symlinks */ oflag |= O_NOFOLLOW; break; case 'l': /* print all differences */ lflag = 1; break; case 's': /* silent run */ sflag = 1; zflag = 1; break; case 'x': /* hex output */ lflag = 1; xflag = 1; break; case 'z': /* compare size first */ zflag = 1; break; case '?': default: usage(); } argv += optind; argc -= optind; if (lflag && sflag) errx(ERR_EXIT, "specifying -s with -l or -x is not permitted"); if (argc < 2 || argc > 4) usage(); /* Backward compatibility -- handle "-" meaning stdin. */ special = 0; if (strcmp(file1 = argv[0], "-") == 0) { special = 1; fd1 = 0; file1 = "stdin"; } else if ((fd1 = open(file1, oflag, 0)) < 0 && errno != EMLINK) { if (!sflag) err(ERR_EXIT, "%s", file1); else exit(ERR_EXIT); } if (strcmp(file2 = argv[1], "-") == 0) { if (special) errx(ERR_EXIT, "standard input may only be specified once"); special = 1; fd2 = 0; file2 = "stdin"; } else if ((fd2 = open(file2, oflag, 0)) < 0 && errno != EMLINK) { if (!sflag) err(ERR_EXIT, "%s", file2); else exit(ERR_EXIT); } skip1 = argc > 2 ? strtol(argv[2], NULL, 0) : 0; skip2 = argc == 4 ? strtol(argv[3], NULL, 0) : 0; if (fd1 == -1) { if (fd2 == -1) { c_link(file1, skip1, file2, skip2); exit(0); } else if (!sflag) errx(ERR_EXIT, "%s: Not a symbolic link", file2); else exit(ERR_EXIT); } else if (fd2 == -1) { if (!sflag) errx(ERR_EXIT, "%s: Not a symbolic link", file1); else exit(ERR_EXIT); } cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_MMAP_R); if (cap_rights_limit(fd1, &rights) < 0 && errno != ENOSYS) err(ERR_EXIT, "unable to limit rights for %s", file1); if (cap_rights_limit(fd2, &rights) < 0 && errno != ENOSYS) err(ERR_EXIT, "unable to limit rights for %s", file2); /* Required for fdopen(3). */ fcntls = CAP_FCNTL_GETFL; if (cap_fcntls_limit(fd1, fcntls) < 0 && errno != ENOSYS) err(ERR_EXIT, "unable to limit fcntls for %s", file1); if (cap_fcntls_limit(fd2, fcntls) < 0 && errno != ENOSYS) err(ERR_EXIT, "unable to limit fcntls for %s", file2); if (!special) { cap_rights_init(&rights); if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) { err(ERR_EXIT, "unable to limit stdio"); } } if (caph_limit_stdout() == -1 || caph_limit_stderr() == -1) err(ERR_EXIT, "unable to limit stdio"); caph_cache_catpages(); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(ERR_EXIT, "unable to enter capability mode"); if (!special) { if (fstat(fd1, &sb1)) { if (!sflag) err(ERR_EXIT, "%s", file1); else exit(ERR_EXIT); } if (!S_ISREG(sb1.st_mode)) special = 1; else { if (fstat(fd2, &sb2)) { if (!sflag) err(ERR_EXIT, "%s", file2); else exit(ERR_EXIT); } if (!S_ISREG(sb2.st_mode)) special = 1; } } if (special) c_special(fd1, file1, skip1, fd2, file2, skip2); else { if (zflag && sb1.st_size != sb2.st_size) { if (!sflag) (void) printf("%s %s differ: size\n", file1, file2); exit(DIFF_EXIT); } c_regular(fd1, file1, skip1, sb1.st_size, fd2, file2, skip2, sb2.st_size); } exit(0); } static void usage(void) { (void)fprintf(stderr, "usage: cmp [-l | -s | -x] [-hz] file1 file2 [skip1 [skip2]]\n"); exit(ERR_EXIT); } Index: head/usr.bin/col/col.c =================================================================== --- head/usr.bin/col/col.c (revision 335394) +++ head/usr.bin/col/col.c (revision 335395) @@ -1,593 +1,593 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Michael Rendell of the Memorial University of Newfoundland. * * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1990, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif #if 0 #ifndef lint static char sccsid[] = "@(#)col.c 8.5 (Berkeley) 5/4/95"; #endif #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #define BS '\b' /* backspace */ #define TAB '\t' /* tab */ #define SPACE ' ' /* space */ #define NL '\n' /* newline */ #define CR '\r' /* carriage return */ #define ESC '\033' /* escape */ #define SI '\017' /* shift in to normal character set */ #define SO '\016' /* shift out to alternate character set */ #define VT '\013' /* vertical tab (aka reverse line feed) */ #define RLF '7' /* ESC-7 reverse line feed */ #define RHLF '8' /* ESC-8 reverse half-line feed */ #define FHLF '9' /* ESC-9 forward half-line feed */ /* build up at least this many lines before flushing them out */ #define BUFFER_MARGIN 32 typedef char CSET; typedef struct char_str { #define CS_NORMAL 1 #define CS_ALTERNATE 2 short c_column; /* column character is in */ CSET c_set; /* character set (currently only 2) */ wchar_t c_char; /* character in question */ int c_width; /* character width */ } CHAR; typedef struct line_str LINE; struct line_str { CHAR *l_line; /* characters on the line */ LINE *l_prev; /* previous line */ LINE *l_next; /* next line */ int l_lsize; /* allocated sizeof l_line */ int l_line_len; /* strlen(l_line) */ int l_needs_sort; /* set if chars went in out of order */ int l_max_col; /* max column in the line */ }; static void addto_lineno(int *, int); static LINE *alloc_line(void); static void dowarn(int); static void flush_line(LINE *); static void flush_lines(int); static void flush_blanks(void); static void free_line(LINE *); static void usage(void); static CSET last_set; /* char_set of last char printed */ static LINE *lines; static int compress_spaces; /* if doing space -> tab conversion */ static int fine; /* if `fine' resolution (half lines) */ static int max_bufd_lines; /* max # of half lines to keep in memory */ static int nblank_lines; /* # blanks after last flushed line */ static int no_backspaces; /* if not to output any backspaces */ static int pass_unknown_seqs; /* pass unknown control sequences */ #define PUTC(ch) \ do { \ if (putwchar(ch) == WEOF) \ errx(1, "write error"); \ } while (0) int main(int argc, char **argv) { wint_t ch; CHAR *c; CSET cur_set; /* current character set */ LINE *l; /* current line */ int extra_lines; /* # of lines above first line */ int cur_col; /* current column */ int cur_line; /* line number of current position */ int max_line; /* max value of cur_line */ int this_line; /* line l points to */ int nflushd_lines; /* number of lines that were flushed */ int adjust, opt, warned, width; const char *errstr; (void)setlocale(LC_CTYPE, ""); if (caph_limit_stdio() == -1) err(1, "unable to limit stdio"); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "unable to enter capability mode"); max_bufd_lines = 256; compress_spaces = 1; /* compress spaces into tabs */ while ((opt = getopt(argc, argv, "bfhl:px")) != -1) switch (opt) { case 'b': /* do not output backspaces */ no_backspaces = 1; break; case 'f': /* allow half forward line feeds */ fine = 1; break; case 'h': /* compress spaces into tabs */ compress_spaces = 1; break; case 'l': /* buffered line count */ max_bufd_lines = strtonum(optarg, 1, (INT_MAX - BUFFER_MARGIN) / 2, &errstr) * 2; if (errstr != NULL) errx(1, "bad -l argument, %s: %s", errstr, optarg); break; case 'p': /* pass unknown control sequences */ pass_unknown_seqs = 1; break; case 'x': /* do not compress spaces into tabs */ compress_spaces = 0; break; case '?': default: usage(); } if (optind != argc) usage(); adjust = cur_col = extra_lines = warned = 0; cur_line = max_line = nflushd_lines = this_line = 0; cur_set = last_set = CS_NORMAL; lines = l = alloc_line(); while ((ch = getwchar()) != WEOF) { if (!iswgraph(ch)) { switch (ch) { case BS: /* can't go back further */ if (cur_col == 0) continue; --cur_col; continue; case CR: cur_col = 0; continue; case ESC: /* just ignore EOF */ switch(getwchar()) { /* * In the input stream, accept both the * XPG5 sequences ESC-digit and the * traditional BSD sequences ESC-ctrl. */ case '\007': /* FALLTHROUGH */ case RLF: addto_lineno(&cur_line, -2); break; case '\010': /* FALLTHROUGH */ case RHLF: addto_lineno(&cur_line, -1); break; case '\011': /* FALLTHROUGH */ case FHLF: addto_lineno(&cur_line, 1); if (cur_line > max_line) max_line = cur_line; } continue; case NL: addto_lineno(&cur_line, 2); if (cur_line > max_line) max_line = cur_line; cur_col = 0; continue; case SPACE: ++cur_col; continue; case SI: cur_set = CS_NORMAL; continue; case SO: cur_set = CS_ALTERNATE; continue; case TAB: /* adjust column */ cur_col |= 7; ++cur_col; continue; case VT: addto_lineno(&cur_line, -2); continue; } if (iswspace(ch)) { if ((width = wcwidth(ch)) > 0) cur_col += width; continue; } if (!pass_unknown_seqs) continue; } /* Must stuff ch in a line - are we at the right one? */ if (cur_line + adjust != this_line) { LINE *lnew; /* round up to next line */ adjust = !fine && (cur_line & 1); if (cur_line + adjust < this_line) { while (cur_line + adjust < this_line && l->l_prev != NULL) { l = l->l_prev; this_line--; } if (cur_line + adjust < this_line) { if (nflushd_lines == 0) { /* * Allow backup past first * line if nothing has been * flushed yet. */ while (cur_line + adjust < this_line) { lnew = alloc_line(); l->l_prev = lnew; lnew->l_next = l; l = lines = lnew; extra_lines++; this_line--; } } else { if (!warned++) dowarn(cur_line); cur_line = this_line - adjust; } } } else { /* may need to allocate here */ while (cur_line + adjust > this_line) { if (l->l_next == NULL) { l->l_next = alloc_line(); l->l_next->l_prev = l; } l = l->l_next; this_line++; } } if (this_line > nflushd_lines && this_line - nflushd_lines >= max_bufd_lines + BUFFER_MARGIN) { if (extra_lines) { flush_lines(extra_lines); extra_lines = 0; } flush_lines(this_line - nflushd_lines - max_bufd_lines); nflushd_lines = this_line - max_bufd_lines; } } /* grow line's buffer? */ if (l->l_line_len + 1 >= l->l_lsize) { int need; need = l->l_lsize ? l->l_lsize * 2 : 90; if ((l->l_line = realloc(l->l_line, (unsigned)need * sizeof(CHAR))) == NULL) err(1, NULL); l->l_lsize = need; } c = &l->l_line[l->l_line_len++]; c->c_char = ch; c->c_set = cur_set; c->c_column = cur_col; c->c_width = wcwidth(ch); /* * If things are put in out of order, they will need sorting * when it is flushed. */ if (cur_col < l->l_max_col) l->l_needs_sort = 1; else l->l_max_col = cur_col; if (c->c_width > 0) cur_col += c->c_width; } if (ferror(stdin)) err(1, NULL); if (extra_lines) flush_lines(extra_lines); /* goto the last line that had a character on it */ for (; l->l_next; l = l->l_next) this_line++; flush_lines(this_line - nflushd_lines + 1); /* make sure we leave things in a sane state */ if (last_set != CS_NORMAL) PUTC(SI); /* flush out the last few blank lines */ if (max_line > this_line) nblank_lines = max_line - this_line; if (max_line & 1) nblank_lines++; flush_blanks(); exit(0); } static void flush_lines(int nflush) { LINE *l; while (--nflush >= 0) { l = lines; lines = l->l_next; if (l->l_line) { flush_blanks(); flush_line(l); } if (l->l_line || l->l_next) nblank_lines++; if (l->l_line) (void)free(l->l_line); free_line(l); } if (lines) lines->l_prev = NULL; } /* * Print a number of newline/half newlines. If fine flag is set, nblank_lines * is the number of half line feeds, otherwise it is the number of whole line * feeds. */ static void flush_blanks(void) { int half, i, nb; half = 0; nb = nblank_lines; if (nb & 1) { if (fine) half = 1; else nb++; } nb /= 2; for (i = nb; --i >= 0;) PUTC('\n'); if (half) { PUTC(ESC); PUTC(FHLF); if (!nb) PUTC('\r'); } nblank_lines = 0; } /* * Write a line to stdout taking care of space to tab conversion (-h flag) * and character set shifts. */ static void flush_line(LINE *l) { CHAR *c, *endc; int i, j, nchars, last_col, save, this_col, tot; last_col = 0; nchars = l->l_line_len; if (l->l_needs_sort) { static CHAR *sorted; static int count_size, *count, sorted_size; /* * Do an O(n) sort on l->l_line by column being careful to * preserve the order of characters in the same column. */ if (l->l_lsize > sorted_size) { sorted_size = l->l_lsize; if ((sorted = realloc(sorted, (unsigned)sizeof(CHAR) * sorted_size)) == NULL) err(1, NULL); } if (l->l_max_col >= count_size) { count_size = l->l_max_col + 1; if ((count = realloc(count, (unsigned)sizeof(int) * count_size)) == NULL) err(1, NULL); } memset(count, 0, sizeof(int) * l->l_max_col + 1); for (i = nchars, c = l->l_line; --i >= 0; c++) count[c->c_column]++; /* * calculate running total (shifted down by 1) to use as * indices into new line. */ for (tot = 0, i = 0; i <= l->l_max_col; i++) { save = count[i]; count[i] = tot; tot += save; } for (i = nchars, c = l->l_line; --i >= 0; c++) sorted[count[c->c_column]++] = *c; c = sorted; } else c = l->l_line; while (nchars > 0) { this_col = c->c_column; endc = c; do { ++endc; } while (--nchars > 0 && this_col == endc->c_column); /* if -b only print last character */ if (no_backspaces) { c = endc - 1; if (nchars > 0 && this_col + c->c_width > endc->c_column) continue; } if (this_col > last_col) { int nspace = this_col - last_col; if (compress_spaces && nspace > 1) { while (1) { int tab_col, tab_size; tab_col = (last_col + 8) & ~7; if (tab_col > this_col) break; tab_size = tab_col - last_col; if (tab_size == 1) PUTC(' '); else PUTC('\t'); nspace -= tab_size; last_col = tab_col; } } while (--nspace >= 0) PUTC(' '); last_col = this_col; } for (;;) { if (c->c_set != last_set) { switch (c->c_set) { case CS_NORMAL: PUTC(SI); break; case CS_ALTERNATE: PUTC(SO); } last_set = c->c_set; } PUTC(c->c_char); if ((c + 1) < endc) for (j = 0; j < c->c_width; j++) PUTC('\b'); if (++c >= endc) break; } last_col += (c - 1)->c_width; } } /* * Increment or decrement a line number, checking for overflow. * Stop one below INT_MAX such that the adjust variable is safe. */ void addto_lineno(int *lno, int offset) { if (offset > 0) { if (*lno >= INT_MAX - offset) errx(1, "too many lines"); } else { if (*lno < INT_MIN - offset) errx(1, "too many reverse line feeds"); } *lno += offset; } #define NALLOC 64 static LINE *line_freelist; static LINE * alloc_line(void) { LINE *l; int i; if (!line_freelist) { if ((l = realloc(NULL, sizeof(LINE) * NALLOC)) == NULL) err(1, NULL); line_freelist = l; for (i = 1; i < NALLOC; i++, l++) l->l_next = l + 1; l->l_next = NULL; } l = line_freelist; line_freelist = l->l_next; memset(l, 0, sizeof(LINE)); return (l); } static void free_line(LINE *l) { l->l_next = line_freelist; line_freelist = l; } static void usage(void) { (void)fprintf(stderr, "usage: col [-bfhpx] [-l nline]\n"); exit(1); } static void dowarn(int line) { warnx("warning: can't back up %s", line < 0 ? "past first line" : "-- line already flushed"); } Index: head/usr.bin/diff/diffreg.c =================================================================== --- head/usr.bin/diff/diffreg.c (revision 335394) +++ head/usr.bin/diff/diffreg.c (revision 335395) @@ -1,1556 +1,1556 @@ /* $OpenBSD: diffreg.c,v 1.91 2016/03/01 20:57:35 natano Exp $ */ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (C) Caldera International Inc. 2001-2002. * 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 and documentation 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 or owned by Caldera * International, Inc. * 4. Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, 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 CALDERA INTERNATIONAL, INC. 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. */ /*- * Copyright (c) 1991, 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. * * @(#)diffreg.c 8.1 (Berkeley) 6/6/93 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pr.h" #include "diff.h" #include "xmalloc.h" /* * diff - compare two files. */ /* * Uses an algorithm due to Harold Stone, which finds * a pair of longest identical subsequences in the two * files. * * The major goal is to generate the match vector J. * J[i] is the index of the line in file1 corresponding * to line i file0. J[i] = 0 if there is no * such line in file1. * * Lines are hashed so as to work in core. All potential * matches are located by sorting the lines of each file * on the hash (called ``value''). In particular, this * collects the equivalence classes in file1 together. * Subroutine equiv replaces the value of each line in * file0 by the index of the first element of its * matching equivalence in (the reordered) file1. * To save space equiv squeezes file1 into a single * array member in which the equivalence classes * are simply concatenated, except that their first * members are flagged by changing sign. * * Next the indices that point into member are unsorted into * array class according to the original order of file0. * * The cleverness lies in routine stone. This marches * through the lines of file0, developing a vector klist * of "k-candidates". At step i a k-candidate is a matched * pair of lines x,y (x in file0 y in file1) such that * there is a common subsequence of length k * between the first i lines of file0 and the first y * lines of file1, but there is no such subsequence for * any smaller y. x is the earliest possible mate to y * that occurs in such a subsequence. * * Whenever any of the members of the equivalence class of * lines in file1 matable to a line in file0 has serial number * less than the y of some k-candidate, that k-candidate * with the smallest such y is replaced. The new * k-candidate is chained (via pred) to the current * k-1 candidate so that the actual subsequence can * be recovered. When a member has serial number greater * that the y of all k-candidates, the klist is extended. * At the end, the longest subsequence is pulled out * and placed in the array J by unravel * * With J in hand, the matches there recorded are * check'ed against reality to assure that no spurious * matches have crept in due to hashing. If they have, * they are broken, and "jackpot" is recorded--a harmless * matter except that a true match for a spuriously * mated line may now be unnecessarily reported as a change. * * Much of the complexity of the program comes simply * from trying to minimize core utilization and * maximize the range of doable problems by dynamically * allocating what is needed and reusing what is not. * The core requirements for problems larger than somewhat * are (in words) 2*length(file0) + length(file1) + * 3*(number of k-candidates installed), typically about * 6n words for files of length n. */ struct cand { int x; int y; int pred; }; static struct line { int serial; int value; } *file[2]; /* * The following struct is used to record change information when * doing a "context" or "unified" diff. (see routine "change" to * understand the highly mnemonic field names) */ struct context_vec { int a; /* start line in old file */ int b; /* end line in old file */ int c; /* start line in new file */ int d; /* end line in new file */ }; #define diff_output printf static FILE *opentemp(const char *); static void output(char *, FILE *, char *, FILE *, int); static void check(FILE *, FILE *, int); static void range(int, int, const char *); static void uni_range(int, int); static void dump_context_vec(FILE *, FILE *, int); static void dump_unified_vec(FILE *, FILE *, int); static void prepare(int, FILE *, size_t, int); static void prune(void); static void equiv(struct line *, int, struct line *, int, int *); static void unravel(int); static void unsort(struct line *, int, int *); static void change(char *, FILE *, char *, FILE *, int, int, int, int, int *); static void sort(struct line *, int); static void print_header(const char *, const char *); static int ignoreline(char *); static int asciifile(FILE *); static int fetch(long *, int, int, FILE *, int, int, int); static int newcand(int, int, int); static int search(int *, int, int); static int skipline(FILE *); static int isqrt(int); static int stone(int *, int, int *, int *, int); static int readhash(FILE *, int); static int files_differ(FILE *, FILE *, int); static char *match_function(const long *, int, FILE *); static char *preadline(int, size_t, off_t); static int *J; /* will be overlaid on class */ static int *class; /* will be overlaid on file[0] */ static int *klist; /* will be overlaid on file[0] after class */ static int *member; /* will be overlaid on file[1] */ static int clen; static int inifdef; /* whether or not we are in a #ifdef block */ static int len[2]; static int pref, suff; /* length of prefix and suffix */ static int slen[2]; static int anychange; static long *ixnew; /* will be overlaid on file[1] */ static long *ixold; /* will be overlaid on klist */ static struct cand *clist; /* merely a free storage pot for candidates */ static int clistlen; /* the length of clist */ static struct line *sfile[2]; /* shortened by pruning common prefix/suffix */ static int (*chrtran)(int); /* translation table for case-folding */ static struct context_vec *context_vec_start; static struct context_vec *context_vec_end; static struct context_vec *context_vec_ptr; #define FUNCTION_CONTEXT_SIZE 55 static char lastbuf[FUNCTION_CONTEXT_SIZE]; static int lastline; static int lastmatchline; static int clow2low(int c) { return (c); } static int cup2low(int c) { return tolower(c); } int diffreg(char *file1, char *file2, int flags, int capsicum) { FILE *f1, *f2; int i, rval; struct pr *pr = NULL; cap_rights_t rights_ro; f1 = f2 = NULL; rval = D_SAME; anychange = 0; lastline = 0; lastmatchline = 0; context_vec_ptr = context_vec_start - 1; if (flags & D_IGNORECASE) chrtran = cup2low; else chrtran = clow2low; if (S_ISDIR(stb1.st_mode) != S_ISDIR(stb2.st_mode)) return (S_ISDIR(stb1.st_mode) ? D_MISMATCH1 : D_MISMATCH2); if (strcmp(file1, "-") == 0 && strcmp(file2, "-") == 0) goto closem; if (flags & D_EMPTY1) f1 = fopen(_PATH_DEVNULL, "r"); else { if (!S_ISREG(stb1.st_mode)) { if ((f1 = opentemp(file1)) == NULL || fstat(fileno(f1), &stb1) < 0) { warn("%s", file1); status |= 2; goto closem; } } else if (strcmp(file1, "-") == 0) f1 = stdin; else f1 = fopen(file1, "r"); } if (f1 == NULL) { warn("%s", file1); status |= 2; goto closem; } if (flags & D_EMPTY2) f2 = fopen(_PATH_DEVNULL, "r"); else { if (!S_ISREG(stb2.st_mode)) { if ((f2 = opentemp(file2)) == NULL || fstat(fileno(f2), &stb2) < 0) { warn("%s", file2); status |= 2; goto closem; } } else if (strcmp(file2, "-") == 0) f2 = stdin; else f2 = fopen(file2, "r"); } if (f2 == NULL) { warn("%s", file2); status |= 2; goto closem; } if (lflag) pr = start_pr(file1, file2); if (capsicum) { cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK); if (cap_rights_limit(fileno(f1), &rights_ro) < 0 && errno != ENOSYS) err(2, "unable to limit rights on: %s", file1); if (cap_rights_limit(fileno(f2), &rights_ro) < 0 && errno != ENOSYS) err(2, "unable to limit rights on: %s", file2); if (fileno(f1) == STDIN_FILENO || fileno(f2) == STDIN_FILENO) { /* stding has already been limited */ if (caph_limit_stderr() == -1) err(2, "unable to limit stderr"); if (caph_limit_stdout() == -1) err(2, "unable to limit stdout"); } else if (caph_limit_stdio() == -1) err(2, "unable to limit stdio"); caph_cache_catpages(); caph_cache_tzdata(); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(2, "unable to enter capability mode"); } switch (files_differ(f1, f2, flags)) { case 0: goto closem; case 1: break; default: /* error */ status |= 2; goto closem; } if ((flags & D_FORCEASCII) == 0 && (!asciifile(f1) || !asciifile(f2))) { rval = D_BINARY; status |= 1; goto closem; } prepare(0, f1, stb1.st_size, flags); prepare(1, f2, stb2.st_size, flags); prune(); sort(sfile[0], slen[0]); sort(sfile[1], slen[1]); member = (int *)file[1]; equiv(sfile[0], slen[0], sfile[1], slen[1], member); member = xreallocarray(member, slen[1] + 2, sizeof(*member)); class = (int *)file[0]; unsort(sfile[0], slen[0], class); class = xreallocarray(class, slen[0] + 2, sizeof(*class)); klist = xcalloc(slen[0] + 2, sizeof(*klist)); clen = 0; clistlen = 100; clist = xcalloc(clistlen, sizeof(*clist)); i = stone(class, slen[0], member, klist, flags); free(member); free(class); J = xreallocarray(J, len[0] + 2, sizeof(*J)); unravel(klist[i]); free(clist); free(klist); ixold = xreallocarray(ixold, len[0] + 2, sizeof(*ixold)); ixnew = xreallocarray(ixnew, len[1] + 2, sizeof(*ixnew)); check(f1, f2, flags); output(file1, f1, file2, f2, flags); if (pr != NULL) stop_pr(pr); closem: if (anychange) { status |= 1; if (rval == D_SAME) rval = D_DIFFER; } if (f1 != NULL) fclose(f1); if (f2 != NULL) fclose(f2); return (rval); } /* * Check to see if the given files differ. * Returns 0 if they are the same, 1 if different, and -1 on error. * XXX - could use code from cmp(1) [faster] */ static int files_differ(FILE *f1, FILE *f2, int flags) { char buf1[BUFSIZ], buf2[BUFSIZ]; size_t i, j; if ((flags & (D_EMPTY1|D_EMPTY2)) || stb1.st_size != stb2.st_size || (stb1.st_mode & S_IFMT) != (stb2.st_mode & S_IFMT)) return (1); for (;;) { i = fread(buf1, 1, sizeof(buf1), f1); j = fread(buf2, 1, sizeof(buf2), f2); if ((!i && ferror(f1)) || (!j && ferror(f2))) return (-1); if (i != j) return (1); if (i == 0) return (0); if (memcmp(buf1, buf2, i) != 0) return (1); } } static FILE * opentemp(const char *f) { char buf[BUFSIZ], tempfile[PATH_MAX]; ssize_t nread; int ifd, ofd; if (strcmp(f, "-") == 0) ifd = STDIN_FILENO; else if ((ifd = open(f, O_RDONLY, 0644)) < 0) return (NULL); (void)strlcpy(tempfile, _PATH_TMP "/diff.XXXXXXXX", sizeof(tempfile)); if ((ofd = mkstemp(tempfile)) < 0) { close(ifd); return (NULL); } unlink(tempfile); while ((nread = read(ifd, buf, BUFSIZ)) > 0) { if (write(ofd, buf, nread) != nread) { close(ifd); close(ofd); return (NULL); } } close(ifd); lseek(ofd, (off_t)0, SEEK_SET); return (fdopen(ofd, "r")); } char * splice(char *dir, char *path) { char *tail, *buf; size_t dirlen; dirlen = strlen(dir); while (dirlen != 0 && dir[dirlen - 1] == '/') dirlen--; if ((tail = strrchr(path, '/')) == NULL) tail = path; else tail++; xasprintf(&buf, "%.*s/%s", (int)dirlen, dir, tail); return (buf); } static void prepare(int i, FILE *fd, size_t filesize, int flags) { struct line *p; int h; size_t sz, j; rewind(fd); sz = MIN(filesize, SIZE_MAX) / 25; if (sz < 100) sz = 100; p = xcalloc(sz + 3, sizeof(*p)); for (j = 0; (h = readhash(fd, flags));) { if (j == sz) { sz = sz * 3 / 2; p = xreallocarray(p, sz + 3, sizeof(*p)); } p[++j].value = h; } len[i] = j; file[i] = p; } static void prune(void) { int i, j; for (pref = 0; pref < len[0] && pref < len[1] && file[0][pref + 1].value == file[1][pref + 1].value; pref++) ; for (suff = 0; suff < len[0] - pref && suff < len[1] - pref && file[0][len[0] - suff].value == file[1][len[1] - suff].value; suff++) ; for (j = 0; j < 2; j++) { sfile[j] = file[j] + pref; slen[j] = len[j] - pref - suff; for (i = 0; i <= slen[j]; i++) sfile[j][i].serial = i; } } static void equiv(struct line *a, int n, struct line *b, int m, int *c) { int i, j; i = j = 1; while (i <= n && j <= m) { if (a[i].value < b[j].value) a[i++].value = 0; else if (a[i].value == b[j].value) a[i++].value = j; else j++; } while (i <= n) a[i++].value = 0; b[m + 1].value = 0; j = 0; while (++j <= m) { c[j] = -b[j].serial; while (b[j + 1].value == b[j].value) { j++; c[j] = b[j].serial; } } c[j] = -1; } /* Code taken from ping.c */ static int isqrt(int n) { int y, x = 1; if (n == 0) return (0); do { /* newton was a stinker */ y = x; x = n / x; x += y; x /= 2; } while ((x - y) > 1 || (x - y) < -1); return (x); } static int stone(int *a, int n, int *b, int *c, int flags) { int i, k, y, j, l; int oldc, tc, oldl, sq; u_int numtries, bound; if (flags & D_MINIMAL) bound = UINT_MAX; else { sq = isqrt(n); bound = MAX(256, sq); } k = 0; c[0] = newcand(0, 0, 0); for (i = 1; i <= n; i++) { j = a[i]; if (j == 0) continue; y = -b[j]; oldl = 0; oldc = c[0]; numtries = 0; do { if (y <= clist[oldc].y) continue; l = search(c, k, y); if (l != oldl + 1) oldc = c[l - 1]; if (l <= k) { if (clist[c[l]].y <= y) continue; tc = c[l]; c[l] = newcand(i, y, oldc); oldc = tc; oldl = l; numtries++; } else { c[l] = newcand(i, y, oldc); k++; break; } } while ((y = b[++j]) > 0 && numtries < bound); } return (k); } static int newcand(int x, int y, int pred) { struct cand *q; if (clen == clistlen) { clistlen = clistlen * 11 / 10; clist = xreallocarray(clist, clistlen, sizeof(*clist)); } q = clist + clen; q->x = x; q->y = y; q->pred = pred; return (clen++); } static int search(int *c, int k, int y) { int i, j, l, t; if (clist[c[k]].y < y) /* quick look for typical case */ return (k + 1); i = 0; j = k + 1; for (;;) { l = (i + j) / 2; if (l <= i) break; t = clist[c[l]].y; if (t > y) j = l; else if (t < y) i = l; else return (l); } return (l + 1); } static void unravel(int p) { struct cand *q; int i; for (i = 0; i <= len[0]; i++) J[i] = i <= pref ? i : i > len[0] - suff ? i + len[1] - len[0] : 0; for (q = clist + p; q->y != 0; q = clist + q->pred) J[q->x + pref] = q->y + pref; } /* * Check does double duty: * 1. ferret out any fortuitous correspondences due * to confounding by hashing (which result in "jackpot") * 2. collect random access indexes to the two files */ static void check(FILE *f1, FILE *f2, int flags) { int i, j, jackpot, c, d; long ctold, ctnew; rewind(f1); rewind(f2); j = 1; ixold[0] = ixnew[0] = 0; jackpot = 0; ctold = ctnew = 0; for (i = 1; i <= len[0]; i++) { if (J[i] == 0) { ixold[i] = ctold += skipline(f1); continue; } while (j < J[i]) { ixnew[j] = ctnew += skipline(f2); j++; } if (flags & (D_FOLDBLANKS|D_IGNOREBLANKS|D_IGNORECASE|D_STRIPCR)) { for (;;) { c = getc(f1); d = getc(f2); /* * GNU diff ignores a missing newline * in one file for -b or -w. */ if (flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) { if (c == EOF && d == '\n') { ctnew++; break; } else if (c == '\n' && d == EOF) { ctold++; break; } } ctold++; ctnew++; if (flags & D_STRIPCR) { if (c == '\r') { if ((c = getc(f1)) == '\n') { ctnew++; break; } } if (d == '\r') { if ((d = getc(f2)) == '\n') { ctold++; break; } } } if ((flags & D_FOLDBLANKS) && isspace(c) && isspace(d)) { do { if (c == '\n') break; ctold++; } while (isspace(c = getc(f1))); do { if (d == '\n') break; ctnew++; } while (isspace(d = getc(f2))); } else if ((flags & D_IGNOREBLANKS)) { while (isspace(c) && c != '\n') { c = getc(f1); ctold++; } while (isspace(d) && d != '\n') { d = getc(f2); ctnew++; } } if (chrtran(c) != chrtran(d)) { jackpot++; J[i] = 0; if (c != '\n' && c != EOF) ctold += skipline(f1); if (d != '\n' && c != EOF) ctnew += skipline(f2); break; } if (c == '\n' || c == EOF) break; } } else { for (;;) { ctold++; ctnew++; if ((c = getc(f1)) != (d = getc(f2))) { /* jackpot++; */ J[i] = 0; if (c != '\n' && c != EOF) ctold += skipline(f1); if (d != '\n' && c != EOF) ctnew += skipline(f2); break; } if (c == '\n' || c == EOF) break; } } ixold[i] = ctold; ixnew[j] = ctnew; j++; } for (; j <= len[1]; j++) { ixnew[j] = ctnew += skipline(f2); } /* * if (jackpot) * fprintf(stderr, "jackpot\n"); */ } /* shellsort CACM #201 */ static void sort(struct line *a, int n) { struct line *ai, *aim, w; int j, m = 0, k; if (n == 0) return; for (j = 1; j <= n; j *= 2) m = 2 * j - 1; for (m /= 2; m != 0; m /= 2) { k = n - m; for (j = 1; j <= k; j++) { for (ai = &a[j]; ai > a; ai -= m) { aim = &ai[m]; if (aim < ai) break; /* wraparound */ if (aim->value > ai[0].value || (aim->value == ai[0].value && aim->serial > ai[0].serial)) break; w.value = ai[0].value; ai[0].value = aim->value; aim->value = w.value; w.serial = ai[0].serial; ai[0].serial = aim->serial; aim->serial = w.serial; } } } } static void unsort(struct line *f, int l, int *b) { int *a, i; a = xcalloc(l + 1, sizeof(*a)); for (i = 1; i <= l; i++) a[f[i].serial] = f[i].value; for (i = 1; i <= l; i++) b[i] = a[i]; free(a); } static int skipline(FILE *f) { int i, c; for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++) continue; return (i); } static void output(char *file1, FILE *f1, char *file2, FILE *f2, int flags) { int m, i0, i1, j0, j1; rewind(f1); rewind(f2); m = len[0]; J[0] = 0; J[m + 1] = len[1] + 1; if (diff_format != D_EDIT) { for (i0 = 1; i0 <= m; i0 = i1 + 1) { while (i0 <= m && J[i0] == J[i0 - 1] + 1) i0++; j0 = J[i0 - 1] + 1; i1 = i0 - 1; while (i1 < m && J[i1 + 1] == 0) i1++; j1 = J[i1 + 1] - 1; J[i1] = j1; change(file1, f1, file2, f2, i0, i1, j0, j1, &flags); } } else { for (i0 = m; i0 >= 1; i0 = i1 - 1) { while (i0 >= 1 && J[i0] == J[i0 + 1] - 1 && J[i0] != 0) i0--; j0 = J[i0 + 1] - 1; i1 = i0 + 1; while (i1 > 1 && J[i1 - 1] == 0) i1--; j1 = J[i1 - 1] + 1; J[i1] = j1; change(file1, f1, file2, f2, i1, i0, j1, j0, &flags); } } if (m == 0) change(file1, f1, file2, f2, 1, 0, 1, len[1], &flags); if (diff_format == D_IFDEF || diff_format == D_GFORMAT) { for (;;) { #define c i0 if ((c = getc(f1)) == EOF) return; diff_output("%c", c); } #undef c } if (anychange != 0) { if (diff_format == D_CONTEXT) dump_context_vec(f1, f2, flags); else if (diff_format == D_UNIFIED) dump_unified_vec(f1, f2, flags); } } static void range(int a, int b, const char *separator) { diff_output("%d", a > b ? b : a); if (a < b) diff_output("%s%d", separator, b); } static void uni_range(int a, int b) { if (a < b) diff_output("%d,%d", a, b - a + 1); else if (a == b) diff_output("%d", b); else diff_output("%d,0", b); } static char * preadline(int fd, size_t rlen, off_t off) { char *line; ssize_t nr; line = xmalloc(rlen + 1); if ((nr = pread(fd, line, rlen, off)) < 0) err(2, "preadline"); if (nr > 0 && line[nr-1] == '\n') nr--; line[nr] = '\0'; return (line); } static int ignoreline(char *line) { int ret; ret = regexec(&ignore_re, line, 0, NULL, 0); free(line); return (ret == 0); /* if it matched, it should be ignored. */ } /* * Indicate that there is a difference between lines a and b of the from file * to get to lines c to d of the to file. If a is greater then b then there * are no lines in the from file involved and this means that there were * lines appended (beginning at b). If c is greater than d then there are * lines missing from the to file. */ static void change(char *file1, FILE *f1, char *file2, FILE *f2, int a, int b, int c, int d, int *pflags) { static size_t max_context = 64; long curpos; int i, nc, f; const char *walk; restart: if ((diff_format != D_IFDEF || diff_format == D_GFORMAT) && a > b && c > d) return; if (ignore_pats != NULL) { char *line; /* * All lines in the change, insert, or delete must * match an ignore pattern for the change to be * ignored. */ if (a <= b) { /* Changes and deletes. */ for (i = a; i <= b; i++) { line = preadline(fileno(f1), ixold[i] - ixold[i - 1], ixold[i - 1]); if (!ignoreline(line)) goto proceed; } } if (a > b || c <= d) { /* Changes and inserts. */ for (i = c; i <= d; i++) { line = preadline(fileno(f2), ixnew[i] - ixnew[i - 1], ixnew[i - 1]); if (!ignoreline(line)) goto proceed; } } return; } proceed: if (*pflags & D_HEADER && diff_format != D_BRIEF) { diff_output("%s %s %s\n", diffargs, file1, file2); *pflags &= ~D_HEADER; } if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) { /* * Allocate change records as needed. */ if (context_vec_ptr == context_vec_end - 1) { ptrdiff_t offset = context_vec_ptr - context_vec_start; max_context <<= 1; context_vec_start = xreallocarray(context_vec_start, max_context, sizeof(*context_vec_start)); context_vec_end = context_vec_start + max_context; context_vec_ptr = context_vec_start + offset; } if (anychange == 0) { /* * Print the context/unidiff header first time through. */ print_header(file1, file2); anychange = 1; } else if (a > context_vec_ptr->b + (2 * diff_context) + 1 && c > context_vec_ptr->d + (2 * diff_context) + 1) { /* * If this change is more than 'diff_context' lines from the * previous change, dump the record and reset it. */ if (diff_format == D_CONTEXT) dump_context_vec(f1, f2, *pflags); else dump_unified_vec(f1, f2, *pflags); } context_vec_ptr++; context_vec_ptr->a = a; context_vec_ptr->b = b; context_vec_ptr->c = c; context_vec_ptr->d = d; return; } if (anychange == 0) anychange = 1; switch (diff_format) { case D_BRIEF: return; case D_NORMAL: case D_EDIT: range(a, b, ","); diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c'); if (diff_format == D_NORMAL) range(c, d, ","); diff_output("\n"); break; case D_REVERSE: diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c'); range(a, b, " "); diff_output("\n"); break; case D_NREVERSE: if (a > b) diff_output("a%d %d\n", b, d - c + 1); else { diff_output("d%d %d\n", a, b - a + 1); if (!(c > d)) /* add changed lines */ diff_output("a%d %d\n", b, d - c + 1); } break; } if (diff_format == D_GFORMAT) { curpos = ftell(f1); /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ nc = ixold[a > b ? b : a - 1] - curpos; for (i = 0; i < nc; i++) diff_output("%c", getc(f1)); for (walk = group_format; *walk != '\0'; walk++) { if (*walk == '%') { walk++; switch (*walk) { case '<': fetch(ixold, a, b, f1, '<', 1, *pflags); break; case '>': fetch(ixnew, c, d, f2, '>', 0, *pflags); break; default: diff_output("%%%c", *walk); break; } continue; } diff_output("%c", *walk); } } if (diff_format == D_NORMAL || diff_format == D_IFDEF) { fetch(ixold, a, b, f1, '<', 1, *pflags); if (a <= b && c <= d && diff_format == D_NORMAL) diff_output("---\n"); } f = 0; if (diff_format != D_GFORMAT) f = fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0, *pflags); if (f != 0 && diff_format == D_EDIT) { /* * A non-zero return value for D_EDIT indicates that the * last line printed was a bare dot (".") that has been * escaped as ".." to prevent ed(1) from misinterpreting * it. We have to add a substitute command to change this * back and restart where we left off. */ diff_output(".\n"); diff_output("%ds/.//\n", a + f - 1); b = a + f - 1; a = b + 1; c += f; goto restart; } if ((diff_format == D_EDIT || diff_format == D_REVERSE) && c <= d) diff_output(".\n"); if (inifdef) { diff_output("#endif /* %s */\n", ifdefname); inifdef = 0; } } static int fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile, int flags) { int i, j, c, lastc, col, nc; int newcol; /* * When doing #ifdef's, copy down to current line * if this is the first file, so that stuff makes it to output. */ if ((diff_format == D_IFDEF) && oldfile) { long curpos = ftell(lb); /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ nc = f[a > b ? b : a - 1] - curpos; for (i = 0; i < nc; i++) diff_output("%c", getc(lb)); } if (a > b) return (0); if (diff_format == D_IFDEF) { if (inifdef) { diff_output("#else /* %s%s */\n", oldfile == 1 ? "!" : "", ifdefname); } else { if (oldfile) diff_output("#ifndef %s\n", ifdefname); else diff_output("#ifdef %s\n", ifdefname); } inifdef = 1 + oldfile; } for (i = a; i <= b; i++) { fseek(lb, f[i - 1], SEEK_SET); nc = f[i] - f[i - 1]; if ((diff_format != D_IFDEF && diff_format != D_GFORMAT) && ch != '\0') { diff_output("%c", ch); if (Tflag && (diff_format == D_NORMAL || diff_format == D_CONTEXT || diff_format == D_UNIFIED)) diff_output("\t"); else if (diff_format != D_UNIFIED) diff_output(" "); } col = 0; for (j = 0, lastc = '\0'; j < nc; j++, lastc = c) { if ((c = getc(lb)) == EOF) { if (diff_format == D_EDIT || diff_format == D_REVERSE || diff_format == D_NREVERSE) warnx("No newline at end of file"); else diff_output("\n\\ No newline at end of " "file\n"); return (0); } if (c == '\t' && (flags & D_EXPANDTABS)) { newcol = ((col/tabsize)+1)*tabsize; do { diff_output(" "); } while (++col < newcol); } else { if (diff_format == D_EDIT && j == 1 && c == '\n' && lastc == '.') { /* * Don't print a bare "." line * since that will confuse ed(1). * Print ".." instead and return, * giving the caller an offset * from which to restart. */ diff_output(".\n"); return (i - a + 1); } diff_output("%c", c); col++; } } } return (0); } /* * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. */ static int readhash(FILE *f, int flags) { int i, t, space; int sum; sum = 1; space = 0; if ((flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) == 0) { if (flags & D_IGNORECASE) for (i = 0; (t = getc(f)) != '\n'; i++) { if (flags & D_STRIPCR && t == '\r') { t = getc(f); if (t == '\n') break; ungetc(t, f); } if (t == EOF) { if (i == 0) return (0); break; } sum = sum * 127 + chrtran(t); } else for (i = 0; (t = getc(f)) != '\n'; i++) { if (flags & D_STRIPCR && t == '\r') { t = getc(f); if (t == '\n') break; ungetc(t, f); } if (t == EOF) { if (i == 0) return (0); break; } sum = sum * 127 + t; } } else { for (i = 0;;) { switch (t = getc(f)) { case '\r': case '\t': case '\v': case '\f': case ' ': space++; continue; default: if (space && (flags & D_IGNOREBLANKS) == 0) { i++; space = 0; } sum = sum * 127 + chrtran(t); i++; continue; case EOF: if (i == 0) return (0); /* FALLTHROUGH */ case '\n': break; } break; } } /* * There is a remote possibility that we end up with a zero sum. * Zero is used as an EOF marker, so return 1 instead. */ return (sum == 0 ? 1 : sum); } static int asciifile(FILE *f) { unsigned char buf[BUFSIZ]; size_t cnt; if (f == NULL) return (1); rewind(f); cnt = fread(buf, 1, sizeof(buf), f); return (memchr(buf, '\0', cnt) == NULL); } #define begins_with(s, pre) (strncmp(s, pre, sizeof(pre)-1) == 0) static char * match_function(const long *f, int pos, FILE *fp) { unsigned char buf[FUNCTION_CONTEXT_SIZE]; size_t nc; int last = lastline; const char *state = NULL; lastline = pos; while (pos > last) { fseek(fp, f[pos - 1], SEEK_SET); nc = f[pos] - f[pos - 1]; if (nc >= sizeof(buf)) nc = sizeof(buf) - 1; nc = fread(buf, 1, nc, fp); if (nc > 0) { buf[nc] = '\0'; buf[strcspn(buf, "\n")] = '\0'; if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') { if (begins_with(buf, "private:")) { if (!state) state = " (private)"; } else if (begins_with(buf, "protected:")) { if (!state) state = " (protected)"; } else if (begins_with(buf, "public:")) { if (!state) state = " (public)"; } else { strlcpy(lastbuf, buf, sizeof lastbuf); if (state) strlcat(lastbuf, state, sizeof lastbuf); lastmatchline = pos; return lastbuf; } } } pos--; } return lastmatchline > 0 ? lastbuf : NULL; } /* dump accumulated "context" diff changes */ static void dump_context_vec(FILE *f1, FILE *f2, int flags) { struct context_vec *cvp = context_vec_start; int lowa, upb, lowc, upd, do_output; int a, b, c, d; char ch, *f; if (context_vec_start > context_vec_ptr) return; b = d = 0; /* gcc */ lowa = MAX(1, cvp->a - diff_context); upb = MIN(len[0], context_vec_ptr->b + diff_context); lowc = MAX(1, cvp->c - diff_context); upd = MIN(len[1], context_vec_ptr->d + diff_context); diff_output("***************"); if ((flags & D_PROTOTYPE)) { f = match_function(ixold, lowa-1, f1); if (f != NULL) diff_output(" %s", f); } diff_output("\n*** "); range(lowa, upb, ","); diff_output(" ****\n"); /* * Output changes to the "old" file. The first loop suppresses * output if there were no changes to the "old" file (we'll see * the "old" lines as context in the "new" list). */ do_output = 0; for (; cvp <= context_vec_ptr; cvp++) if (cvp->a <= cvp->b) { cvp = context_vec_start; do_output++; break; } if (do_output) { while (cvp <= context_vec_ptr) { a = cvp->a; b = cvp->b; c = cvp->c; d = cvp->d; if (a <= b && c <= d) ch = 'c'; else ch = (a <= b) ? 'd' : 'a'; if (ch == 'a') fetch(ixold, lowa, b, f1, ' ', 0, flags); else { fetch(ixold, lowa, a - 1, f1, ' ', 0, flags); fetch(ixold, a, b, f1, ch == 'c' ? '!' : '-', 0, flags); } lowa = b + 1; cvp++; } fetch(ixold, b + 1, upb, f1, ' ', 0, flags); } /* output changes to the "new" file */ diff_output("--- "); range(lowc, upd, ","); diff_output(" ----\n"); do_output = 0; for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) if (cvp->c <= cvp->d) { cvp = context_vec_start; do_output++; break; } if (do_output) { while (cvp <= context_vec_ptr) { a = cvp->a; b = cvp->b; c = cvp->c; d = cvp->d; if (a <= b && c <= d) ch = 'c'; else ch = (a <= b) ? 'd' : 'a'; if (ch == 'd') fetch(ixnew, lowc, d, f2, ' ', 0, flags); else { fetch(ixnew, lowc, c - 1, f2, ' ', 0, flags); fetch(ixnew, c, d, f2, ch == 'c' ? '!' : '+', 0, flags); } lowc = d + 1; cvp++; } fetch(ixnew, d + 1, upd, f2, ' ', 0, flags); } context_vec_ptr = context_vec_start - 1; } /* dump accumulated "unified" diff changes */ static void dump_unified_vec(FILE *f1, FILE *f2, int flags) { struct context_vec *cvp = context_vec_start; int lowa, upb, lowc, upd; int a, b, c, d; char ch, *f; if (context_vec_start > context_vec_ptr) return; b = d = 0; /* gcc */ lowa = MAX(1, cvp->a - diff_context); upb = MIN(len[0], context_vec_ptr->b + diff_context); lowc = MAX(1, cvp->c - diff_context); upd = MIN(len[1], context_vec_ptr->d + diff_context); diff_output("@@ -"); uni_range(lowa, upb); diff_output(" +"); uni_range(lowc, upd); diff_output(" @@"); if ((flags & D_PROTOTYPE)) { f = match_function(ixold, lowa-1, f1); if (f != NULL) diff_output(" %s", f); } diff_output("\n"); /* * Output changes in "unified" diff format--the old and new lines * are printed together. */ for (; cvp <= context_vec_ptr; cvp++) { a = cvp->a; b = cvp->b; c = cvp->c; d = cvp->d; /* * c: both new and old changes * d: only changes in the old file * a: only changes in the new file */ if (a <= b && c <= d) ch = 'c'; else ch = (a <= b) ? 'd' : 'a'; switch (ch) { case 'c': fetch(ixold, lowa, a - 1, f1, ' ', 0, flags); fetch(ixold, a, b, f1, '-', 0, flags); fetch(ixnew, c, d, f2, '+', 0, flags); break; case 'd': fetch(ixold, lowa, a - 1, f1, ' ', 0, flags); fetch(ixold, a, b, f1, '-', 0, flags); break; case 'a': fetch(ixnew, lowc, c - 1, f2, ' ', 0, flags); fetch(ixnew, c, d, f2, '+', 0, flags); break; } lowa = b + 1; lowc = d + 1; } fetch(ixnew, d + 1, upd, f2, ' ', 0, flags); context_vec_ptr = context_vec_start - 1; } static void print_header(const char *file1, const char *file2) { const char *time_format; char buf1[256]; char buf2[256]; char end1[10]; char end2[10]; struct tm tm1, tm2, *tm_ptr1, *tm_ptr2; int nsec1 = stb1.st_mtim.tv_nsec; int nsec2 = stb2.st_mtim.tv_nsec; time_format = "%Y-%m-%d %H:%M:%S"; if (cflag) time_format = "%c"; tm_ptr1 = localtime_r(&stb1.st_mtime, &tm1); tm_ptr2 = localtime_r(&stb2.st_mtime, &tm2); strftime(buf1, 256, time_format, tm_ptr1); strftime(buf2, 256, time_format, tm_ptr2); if (!cflag) { strftime(end1, 10, "%z", tm_ptr1); strftime(end2, 10, "%z", tm_ptr2); sprintf(buf1, "%s.%.9d %s", buf1, nsec1, end1); sprintf(buf2, "%s.%.9d %s", buf2, nsec2, end2); } if (label[0] != NULL) diff_output("%s %s\n", diff_format == D_CONTEXT ? "***" : "---", label[0]); else diff_output("%s %s\t%s\n", diff_format == D_CONTEXT ? "***" : "---", file1, buf1); if (label[1] != NULL) diff_output("%s %s\n", diff_format == D_CONTEXT ? "---" : "+++", label[1]); else diff_output("%s %s\t%s\n", diff_format == D_CONTEXT ? "---" : "+++", file2, buf2); } Index: head/usr.bin/diff3/diff3.c =================================================================== --- head/usr.bin/diff3/diff3.c (revision 335394) +++ head/usr.bin/diff3/diff3.c (revision 335395) @@ -1,785 +1,785 @@ /* $OpenBSD: diff3prog.c,v 1.11 2009/10/27 23:59:37 deraadt Exp $ */ /* * Copyright (C) Caldera International Inc. 2001-2002. * 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 and documentation 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 or owned by Caldera * International, Inc. * 4. Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, 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 CALDERA INTERNATIONAL, INC. 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. */ /*- * Copyright (c) 1991, 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. * * @(#)diff3.c 8.1 (Berkeley) 6/6/93 */ #if 0 #ifndef lint static char sccsid[] = "@(#)diff3.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include /* * "from" is first in range of changed lines; "to" is last+1 * from=to=line after point of insertion for added lines. */ struct range { int from; int to; }; struct diff { struct range old; struct range new; }; static size_t szchanges; static struct diff *d13; static struct diff *d23; /* * "de" is used to gather editing scripts. These are later spewed out in * reverse order. Its first element must be all zero, the "new" component * of "de" contains line positions or byte positions depending on when you * look (!?). Array overlap indicates which sections in "de" correspond to * lines that are different in all three files. */ static struct diff *de; static char *overlap; static int overlapcnt; static FILE *fp[3]; static int cline[3]; /* # of the last-read line in each file (0-2) */ /* * The latest known correspondence between line numbers of the 3 files * is stored in last[1-3]; */ static int last[4]; static int Aflag, eflag, iflag, mflag, Tflag; static int oflag; /* indicates whether to mark overlaps (-E or -X)*/ static int strip_cr; static char *f1mark, *f2mark, *f3mark; static bool duplicate(struct range *, struct range *); static int edit(struct diff *, bool, int); static char *getchange(FILE *); static char *get_line(FILE *, size_t *); static int number(char **); static int readin(int fd, struct diff **); static int skip(int, int, const char *); static void change(int, struct range *, bool); static void keep(int, struct range *); static void merge(int, int); static void prange(struct range *); static void repos(int); static void edscript(int) __dead2; static void increase(void); static void usage(void) __dead2; enum { DIFFPROG_OPT, STRIPCR_OPT, }; #define DIFF_PATH "/usr/bin/diff" #define OPTIONS "3aAeEiL:mTxX" static struct option longopts[] = { { "ed", no_argument, NULL, 'e' }, { "show-overlap", no_argument, NULL, 'E' }, { "overlap-only", no_argument, NULL, 'x' }, { "initial-tab", no_argument, NULL, 'T' }, { "text", no_argument, NULL, 'a' }, { "strip-trailing-cr", no_argument, NULL, STRIPCR_OPT }, { "show-all", no_argument, NULL, 'A' }, { "easy-only", no_argument, NULL, '3' }, { "merge", no_argument, NULL, 'm' }, { "label", required_argument, NULL, 'L' }, { "diff-program", required_argument, NULL, DIFFPROG_OPT }, }; static void usage(void) { fprintf(stderr, "usage: diff3 [-3aAeEimTxX] [-L lable1] [-L label2] " "[ -L label3] file1 file2 file3\n"); exit (2); } static int readin(int fd, struct diff **dd) { int a, b, c, d; size_t i; char kind, *p; FILE *f; f = fdopen(fd, "r"); if (f == NULL) err(2, "fdopen"); for (i=0; (p = getchange(f)); i++) { if (i >= szchanges - 1) increase(); a = b = number(&p); if (*p == ',') { p++; b = number(&p); } kind = *p++; c = d = number(&p); if (*p==',') { p++; d = number(&p); } if (kind == 'a') a++; if (kind == 'd') c++; b++; d++; (*dd)[i].old.from = a; (*dd)[i].old.to = b; (*dd)[i].new.from = c; (*dd)[i].new.to = d; } if (i) { (*dd)[i].old.from = (*dd)[i-1].old.to; (*dd)[i].new.from = (*dd)[i-1].new.to; } fclose(f); return (i); } static int diffexec(const char *diffprog, char **diffargv, int fd[]) { int pid, pd; switch (pid = pdfork(&pd, PD_CLOEXEC)) { case 0: close(fd[0]); if (dup2(fd[1], STDOUT_FILENO) == -1) err(2, "child could not duplicate descriptor"); close(fd[1]); execvp(diffprog, diffargv); err(2, "could not execute diff: %s", diffprog); break; case -1: err(2, "could not fork"); break; } close(fd[1]); return (pd); } static int number(char **lc) { int nn; nn = 0; while (isdigit((unsigned char)(**lc))) nn = nn*10 + *(*lc)++ - '0'; return (nn); } static char * getchange(FILE *b) { char *line; while ((line = get_line(b, NULL))) { if (isdigit((unsigned char)line[0])) return (line); } return (NULL); } static char * get_line(FILE *b, size_t *n) { char *cp; size_t len; static char *buf; static size_t bufsize; if ((cp = fgetln(b, &len)) == NULL) return (NULL); if (cp[len - 1] != '\n') len++; if (len + 1 > bufsize) { do { bufsize += 1024; } while (len + 1 > bufsize); if ((buf = realloc(buf, bufsize)) == NULL) err(EXIT_FAILURE, NULL); } memcpy(buf, cp, len - 1); buf[len - 1] = '\n'; buf[len] = '\0'; if (n != NULL) *n = len; return (buf); } static void merge(int m1, int m2) { struct diff *d1, *d2, *d3; int j, t1, t2; bool dup = false; d1 = d13; d2 = d23; j = 0; while ((t1 = d1 < d13 + m1) | (t2 = d2 < d23 + m2)) { /* first file is different from the others */ if (!t2 || (t1 && d1->new.to < d2->new.from)) { /* stuff peculiar to 1st file */ if (eflag == 0) { printf("====1\n"); change(1, &d1->old, false); keep(2, &d1->new); change(3, &d1->new, false); } d1++; continue; } /* second file is different from others */ if (!t1 || (t2 && d2->new.to < d1->new.from)) { if (eflag == 0) { printf("====2\n"); keep(1, &d2->new); change(3, &d2->new, false); change(2, &d2->old, false); } d2++; continue; } /* * Merge overlapping changes in first file * this happens after extension (see below). */ if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) { d1[1].old.from = d1->old.from; d1[1].new.from = d1->new.from; d1++; continue; } /* merge overlapping changes in second */ if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) { d2[1].old.from = d2->old.from; d2[1].new.from = d2->new.from; d2++; continue; } /* stuff peculiar to third file or different in all */ if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) { dup = duplicate(&d1->old, &d2->old); /* * dup = 0 means all files differ * dup = 1 means files 1 and 2 identical */ if (eflag == 0) { printf("====%s\n", dup ? "3" : ""); change(1, &d1->old, dup); change(2, &d2->old, false); d3 = d1->old.to > d1->old.from ? d1 : d2; change(3, &d3->new, false); } else j = edit(d1, dup, j); d1++; d2++; continue; } /* * Overlapping changes from file 1 and 2; extend changes * appropriately to make them coincide. */ if (d1->new.from < d2->new.from) { d2->old.from -= d2->new.from - d1->new.from; d2->new.from = d1->new.from; } else if (d2->new.from < d1->new.from) { d1->old.from -= d1->new.from - d2->new.from; d1->new.from = d2->new.from; } if (d1->new.to > d2->new.to) { d2->old.to += d1->new.to - d2->new.to; d2->new.to = d1->new.to; } else if (d2->new.to > d1->new.to) { d1->old.to += d2->new.to - d1->new.to; d1->new.to = d2->new.to; } } if (eflag) edscript(j); } /* * The range of lines rold.from thru rold.to in file i is to be changed. * It is to be printed only if it does not duplicate something to be * printed later. */ static void change(int i, struct range *rold, bool dup) { printf("%d:", i); last[i] = rold->to; prange(rold); if (dup) return; i--; skip(i, rold->from, NULL); skip(i, rold->to, " "); } /* * Print the range of line numbers, rold.from thru rold.to, as n1,n2 or * n1. */ static void prange(struct range *rold) { if (rold->to <= rold->from) printf("%da\n", rold->from - 1); else { printf("%d", rold->from); if (rold->to > rold->from+1) printf(",%d", rold->to - 1); printf("c\n"); } } /* * No difference was reported by diff between file 1 (or 2) and file 3, * and an artificial dummy difference (trange) must be ginned up to * correspond to the change reported in the other file. */ static void keep(int i, struct range *rnew) { int delta; struct range trange; delta = last[3] - last[i]; trange.from = rnew->from - delta; trange.to = rnew->to - delta; change(i, &trange, true); } /* * skip to just before line number from in file "i". If "pr" is non-NULL, * print all skipped stuff with string pr as a prefix. */ static int skip(int i, int from, const char *pr) { size_t j, n; char *line; for (n = 0; cline[i] < from - 1; n += j) { if ((line = get_line(fp[i], &j)) == NULL) errx(EXIT_FAILURE, "logic error"); if (pr != NULL) printf("%s%s", Tflag == 1? "\t" : pr, line); cline[i]++; } return ((int) n); } /* * Return 1 or 0 according as the old range (in file 1) contains exactly * the same data as the new range (in file 2). */ static bool duplicate(struct range *r1, struct range *r2) { int c, d; int nchar; int nline; if (r1->to-r1->from != r2->to-r2->from) return (0); skip(0, r1->from, NULL); skip(1, r2->from, NULL); nchar = 0; for (nline=0; nline < r1->to - r1->from; nline++) { do { c = getc(fp[0]); d = getc(fp[1]); if (c == -1 || d== -1) errx(EXIT_FAILURE, "logic error"); nchar++; if (c != d) { repos(nchar); return (0); } } while (c != '\n'); } repos(nchar); return (1); } static void repos(int nchar) { int i; for (i = 0; i < 2; i++) (void)fseek(fp[i], (long)-nchar, SEEK_CUR); } /* * collect an editing script for later regurgitation */ static int edit(struct diff *diff, bool dup, int j) { if (((dup + 1) & eflag) == 0) return (j); j++; overlap[j] = !dup; if (!dup) overlapcnt++; de[j].old.from = diff->old.from; de[j].old.to = diff->old.to; de[j].new.from = de[j-1].new.to + skip(2, diff->new.from, NULL); de[j].new.to = de[j].new.from + skip(2, diff->new.to, NULL); return (j); } /* regurgitate */ static void edscript(int n) { int k; size_t j; char block[BUFSIZ]; for (; n > 0; n--) { if (!oflag || !overlap[n]) { prange(&de[n].old); } else { printf("%da\n", de[n].old.to -1); if (Aflag) { printf("%s\n", f2mark); fseek(fp[1], de[n].old.from, SEEK_SET); for (k = de[n].old.to - de[n].old.from; k > 0; k -= j) { j = k > BUFSIZ ? BUFSIZ : k; if (fread(block, 1, j, fp[1]) != j) errx(2, "logic error"); fwrite(block, 1, j, stdout); } printf("\n"); } printf("=======\n"); } fseek(fp[2], (long)de[n].new.from, SEEK_SET); for (k = de[n].new.to - de[n].new.from; k > 0; k-= j) { j = k > BUFSIZ ? BUFSIZ : k; if (fread(block, 1, j, fp[2]) != j) errx(2, "logic error"); fwrite(block, 1, j, stdout); } if (!oflag || !overlap[n]) printf(".\n"); else { printf("%s\n.\n", f3mark); printf("%da\n%s\n.\n", de[n].old.from - 1, f1mark); } } if (iflag) printf("w\nq\n"); exit(eflag == 0 ? overlapcnt : 0); } static void increase(void) { struct diff *p; char *q; size_t newsz, incr; /* are the memset(3) calls needed? */ newsz = szchanges == 0 ? 64 : 2 * szchanges; incr = newsz - szchanges; p = realloc(d13, newsz * sizeof(struct diff)); if (p == NULL) err(1, NULL); memset(p + szchanges, 0, incr * sizeof(struct diff)); d13 = p; p = realloc(d23, newsz * sizeof(struct diff)); if (p == NULL) err(1, NULL); memset(p + szchanges, 0, incr * sizeof(struct diff)); d23 = p; p = realloc(de, newsz * sizeof(struct diff)); if (p == NULL) err(1, NULL); memset(p + szchanges, 0, incr * sizeof(struct diff)); de = p; q = realloc(overlap, newsz * sizeof(char)); if (q == NULL) err(1, NULL); memset(q + szchanges, 0, incr * sizeof(char)); overlap = q; szchanges = newsz; } int main(int argc, char **argv) { int ch, nblabels, status, m, n, kq, nke, nleft, i; char *labels[] = { NULL, NULL, NULL }; const char *diffprog = DIFF_PATH; char *file1, *file2, *file3; char *diffargv[6]; int diffargc = 0; int fd13[2], fd23[2]; int pd13, pd23; cap_rights_t rights_ro; struct kevent *e; nblabels = 0; eflag = 0; oflag = 0; diffargv[diffargc++] = __DECONST(char *, diffprog); while ((ch = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { switch (ch) { case '3': eflag = 2; break; case 'a': diffargv[diffargc++] = __DECONST(char *, "-a"); break; case 'A': Aflag = 1; break; case 'e': eflag = 3; break; case 'E': eflag = 3; oflag = 1; break; case 'i': iflag = 1; break; case 'L': oflag = 1; if (nblabels >= 3) errx(2, "too many file label options"); labels[nblabels++] = optarg; break; case 'm': Aflag = 1; oflag = 1; mflag = 1; break; case 'T': Tflag = 1; break; case 'x': eflag = 1; break; case 'X': oflag = 1; eflag = 1; break; case DIFFPROG_OPT: diffprog = optarg; break; case STRIPCR_OPT: strip_cr = 1; break; } } argc -= optind; argv += optind; if (Aflag) { eflag = 3; oflag = 1; } if (argc != 3) usage(); if (caph_limit_stdio() == -1) err(2, "unable to limit stdio"); cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK); kq = kqueue(); if (kq == -1) err(2, "kqueue"); e = malloc(2 * sizeof(struct kevent)); if (e == NULL) err(2, "malloc"); /* TODO stdio */ file1 = argv[0]; file2 = argv[1]; file3 = argv[2]; if (oflag) { asprintf(&f1mark, "<<<<<<< %s", labels[0] != NULL ? labels[0] : file1); if (f1mark == NULL) err(2, "asprintf"); asprintf(&f2mark, "||||||| %s", labels[1] != NULL ? labels[1] : file2); if (f2mark == NULL) err(2, "asprintf"); asprintf(&f3mark, ">>>>>>> %s", labels[2] != NULL ? labels[2] : file3); if (f3mark == NULL) err(2, "asprintf"); } fp[0] = fopen(file1, "r"); if (fp[0] == NULL) err(2, "Can't open %s", file1); if (cap_rights_limit(fileno(fp[0]), &rights_ro) < 0) err(2, "unable to limit rights on: %s", file1); fp[1] = fopen(file2, "r"); if (fp[1] == NULL) err(2, "Can't open %s", file2); if (cap_rights_limit(fileno(fp[1]), &rights_ro) < 0) err(2, "unable to limit rights on: %s", file2); fp[2] = fopen(file3, "r"); if (fp[2] == NULL) err(2, "Can't open %s", file3); if (cap_rights_limit(fileno(fp[2]), &rights_ro) < 0) err(2, "unable to limit rights on: %s", file3); if (pipe(fd13)) err(2, "pipe"); if (pipe(fd23)) err(2, "pipe"); diffargv[diffargc] = file1; diffargv[diffargc + 1] = file3; diffargv[diffargc + 2] = NULL; nleft = 0; pd13 = diffexec(diffprog, diffargv, fd13); EV_SET(e + nleft , pd13, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT, 0, NULL); if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) err(2, "kevent1"); nleft++; diffargv[diffargc] = file2; pd23 = diffexec(diffprog, diffargv, fd23); EV_SET(e + nleft , pd23, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT, 0, NULL); if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) err(2, "kevent2"); nleft++; caph_cache_catpages(); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(2, "unable to enter capability mode"); /* parse diffs */ increase(); m = readin(fd13[0], &d13); n = readin(fd23[0], &d23); /* waitpid cooked over pdforks */ while (nleft > 0) { nke = kevent(kq, NULL, 0, e, nleft, NULL); if (nke == -1) err(2, "kevent"); for (i = 0; i < nke; i++) { status = e[i].data; if (WIFEXITED(status) && WEXITSTATUS(status) >= 2) errx(2, "diff exited abormally"); else if (WIFSIGNALED(status)) errx(2, "diff killed by signal %d", WTERMSIG(status)); } nleft -= nke; } merge(m, n); return (EXIT_SUCCESS); } Index: head/usr.bin/dirname/dirname.c =================================================================== --- head/usr.bin/dirname/dirname.c (revision 335394) +++ head/usr.bin/dirname/dirname.c (revision 335395) @@ -1,89 +1,89 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1991, 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1991, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static const char sccsid[] = "@(#)dirname.c 8.4 (Berkeley) 5/4/95"; #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include void usage(void); int main(int argc, char **argv) { char *p; int ch; - if (caph_limit_stdio() < 0 || (cap_enter() < 0 && errno != ENOSYS)) + if (caph_limit_stdio() < 0 || caph_enter() < 0) err(1, "capsicum"); while ((ch = getopt(argc, argv, "")) != -1) switch(ch) { case '?': default: usage(); } argc -= optind; argv += optind; if (argc < 1) usage(); while (argc--) { if ((p = dirname(*argv)) == NULL) err(1, "%s", *argv); argv++; (void)printf("%s\n", p); } exit(0); } void usage(void) { (void)fprintf(stderr, "usage: dirname string [...]\n"); exit(1); } Index: head/usr.bin/elfdump/elfdump.c =================================================================== --- head/usr.bin/elfdump/elfdump.c (revision 335394) +++ head/usr.bin/elfdump/elfdump.c (revision 335395) @@ -1,1259 +1,1259 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2003 David O'Brien. All rights reserved. * Copyright (c) 2001 Jake Burkholder * 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. * * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define ED_DYN (1<<0) #define ED_EHDR (1<<1) #define ED_GOT (1<<2) #define ED_HASH (1<<3) #define ED_INTERP (1<<4) #define ED_NOTE (1<<5) #define ED_PHDR (1<<6) #define ED_REL (1<<7) #define ED_SHDR (1<<8) #define ED_SYMTAB (1<<9) #define ED_ALL ((1<<10)-1) #define elf_get_addr elf_get_quad #define elf_get_off elf_get_quad #define elf_get_size elf_get_quad enum elf_member { D_TAG = 1, D_PTR, D_VAL, E_CLASS, E_DATA, E_OSABI, E_TYPE, E_MACHINE, E_VERSION, E_ENTRY, E_PHOFF, E_SHOFF, E_FLAGS, E_EHSIZE, E_PHENTSIZE, E_PHNUM, E_SHENTSIZE, E_SHNUM, E_SHSTRNDX, N_NAMESZ, N_DESCSZ, N_TYPE, P_TYPE, P_OFFSET, P_VADDR, P_PADDR, P_FILESZ, P_MEMSZ, P_FLAGS, P_ALIGN, SH_NAME, SH_TYPE, SH_FLAGS, SH_ADDR, SH_OFFSET, SH_SIZE, SH_LINK, SH_INFO, SH_ADDRALIGN, SH_ENTSIZE, ST_NAME, ST_VALUE, ST_SIZE, ST_INFO, ST_SHNDX, R_OFFSET, R_INFO, RA_OFFSET, RA_INFO, RA_ADDEND }; typedef enum elf_member elf_member_t; static int elf32_offsets[] = { 0, offsetof(Elf32_Dyn, d_tag), offsetof(Elf32_Dyn, d_un.d_ptr), offsetof(Elf32_Dyn, d_un.d_val), offsetof(Elf32_Ehdr, e_ident[EI_CLASS]), offsetof(Elf32_Ehdr, e_ident[EI_DATA]), offsetof(Elf32_Ehdr, e_ident[EI_OSABI]), offsetof(Elf32_Ehdr, e_type), offsetof(Elf32_Ehdr, e_machine), offsetof(Elf32_Ehdr, e_version), offsetof(Elf32_Ehdr, e_entry), offsetof(Elf32_Ehdr, e_phoff), offsetof(Elf32_Ehdr, e_shoff), offsetof(Elf32_Ehdr, e_flags), offsetof(Elf32_Ehdr, e_ehsize), offsetof(Elf32_Ehdr, e_phentsize), offsetof(Elf32_Ehdr, e_phnum), offsetof(Elf32_Ehdr, e_shentsize), offsetof(Elf32_Ehdr, e_shnum), offsetof(Elf32_Ehdr, e_shstrndx), offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz), offsetof(Elf_Note, n_type), offsetof(Elf32_Phdr, p_type), offsetof(Elf32_Phdr, p_offset), offsetof(Elf32_Phdr, p_vaddr), offsetof(Elf32_Phdr, p_paddr), offsetof(Elf32_Phdr, p_filesz), offsetof(Elf32_Phdr, p_memsz), offsetof(Elf32_Phdr, p_flags), offsetof(Elf32_Phdr, p_align), offsetof(Elf32_Shdr, sh_name), offsetof(Elf32_Shdr, sh_type), offsetof(Elf32_Shdr, sh_flags), offsetof(Elf32_Shdr, sh_addr), offsetof(Elf32_Shdr, sh_offset), offsetof(Elf32_Shdr, sh_size), offsetof(Elf32_Shdr, sh_link), offsetof(Elf32_Shdr, sh_info), offsetof(Elf32_Shdr, sh_addralign), offsetof(Elf32_Shdr, sh_entsize), offsetof(Elf32_Sym, st_name), offsetof(Elf32_Sym, st_value), offsetof(Elf32_Sym, st_size), offsetof(Elf32_Sym, st_info), offsetof(Elf32_Sym, st_shndx), offsetof(Elf32_Rel, r_offset), offsetof(Elf32_Rel, r_info), offsetof(Elf32_Rela, r_offset), offsetof(Elf32_Rela, r_info), offsetof(Elf32_Rela, r_addend) }; static int elf64_offsets[] = { 0, offsetof(Elf64_Dyn, d_tag), offsetof(Elf64_Dyn, d_un.d_ptr), offsetof(Elf64_Dyn, d_un.d_val), offsetof(Elf32_Ehdr, e_ident[EI_CLASS]), offsetof(Elf32_Ehdr, e_ident[EI_DATA]), offsetof(Elf32_Ehdr, e_ident[EI_OSABI]), offsetof(Elf64_Ehdr, e_type), offsetof(Elf64_Ehdr, e_machine), offsetof(Elf64_Ehdr, e_version), offsetof(Elf64_Ehdr, e_entry), offsetof(Elf64_Ehdr, e_phoff), offsetof(Elf64_Ehdr, e_shoff), offsetof(Elf64_Ehdr, e_flags), offsetof(Elf64_Ehdr, e_ehsize), offsetof(Elf64_Ehdr, e_phentsize), offsetof(Elf64_Ehdr, e_phnum), offsetof(Elf64_Ehdr, e_shentsize), offsetof(Elf64_Ehdr, e_shnum), offsetof(Elf64_Ehdr, e_shstrndx), offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz), offsetof(Elf_Note, n_type), offsetof(Elf64_Phdr, p_type), offsetof(Elf64_Phdr, p_offset), offsetof(Elf64_Phdr, p_vaddr), offsetof(Elf64_Phdr, p_paddr), offsetof(Elf64_Phdr, p_filesz), offsetof(Elf64_Phdr, p_memsz), offsetof(Elf64_Phdr, p_flags), offsetof(Elf64_Phdr, p_align), offsetof(Elf64_Shdr, sh_name), offsetof(Elf64_Shdr, sh_type), offsetof(Elf64_Shdr, sh_flags), offsetof(Elf64_Shdr, sh_addr), offsetof(Elf64_Shdr, sh_offset), offsetof(Elf64_Shdr, sh_size), offsetof(Elf64_Shdr, sh_link), offsetof(Elf64_Shdr, sh_info), offsetof(Elf64_Shdr, sh_addralign), offsetof(Elf64_Shdr, sh_entsize), offsetof(Elf64_Sym, st_name), offsetof(Elf64_Sym, st_value), offsetof(Elf64_Sym, st_size), offsetof(Elf64_Sym, st_info), offsetof(Elf64_Sym, st_shndx), offsetof(Elf64_Rel, r_offset), offsetof(Elf64_Rel, r_info), offsetof(Elf64_Rela, r_offset), offsetof(Elf64_Rela, r_info), offsetof(Elf64_Rela, r_addend) }; /* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#tag_encodings */ static const char * d_tags(u_int64_t tag) { static char unknown_tag[48]; switch (tag) { case DT_NULL: return "DT_NULL"; case DT_NEEDED: return "DT_NEEDED"; case DT_PLTRELSZ: return "DT_PLTRELSZ"; case DT_PLTGOT: return "DT_PLTGOT"; case DT_HASH: return "DT_HASH"; case DT_STRTAB: return "DT_STRTAB"; case DT_SYMTAB: return "DT_SYMTAB"; case DT_RELA: return "DT_RELA"; case DT_RELASZ: return "DT_RELASZ"; case DT_RELAENT: return "DT_RELAENT"; case DT_STRSZ: return "DT_STRSZ"; case DT_SYMENT: return "DT_SYMENT"; case DT_INIT: return "DT_INIT"; case DT_FINI: return "DT_FINI"; case DT_SONAME: return "DT_SONAME"; case DT_RPATH: return "DT_RPATH"; case DT_SYMBOLIC: return "DT_SYMBOLIC"; case DT_REL: return "DT_REL"; case DT_RELSZ: return "DT_RELSZ"; case DT_RELENT: return "DT_RELENT"; case DT_PLTREL: return "DT_PLTREL"; case DT_DEBUG: return "DT_DEBUG"; case DT_TEXTREL: return "DT_TEXTREL"; case DT_JMPREL: return "DT_JMPREL"; case DT_BIND_NOW: return "DT_BIND_NOW"; case DT_INIT_ARRAY: return "DT_INIT_ARRAY"; case DT_FINI_ARRAY: return "DT_FINI_ARRAY"; case DT_INIT_ARRAYSZ: return "DT_INIT_ARRAYSZ"; case DT_FINI_ARRAYSZ: return "DT_FINI_ARRAYSZ"; case DT_RUNPATH: return "DT_RUNPATH"; case DT_FLAGS: return "DT_FLAGS"; case DT_PREINIT_ARRAY: return "DT_PREINIT_ARRAY"; /* XXX DT_ENCODING */ case DT_PREINIT_ARRAYSZ:return "DT_PREINIT_ARRAYSZ"; /* 0x6000000D - 0x6ffff000 operating system-specific semantics */ case 0x6ffffdf5: return "DT_GNU_PRELINKED"; case 0x6ffffdf6: return "DT_GNU_CONFLICTSZ"; case 0x6ffffdf7: return "DT_GNU_LIBLISTSZ"; case 0x6ffffdf8: return "DT_SUNW_CHECKSUM"; case DT_PLTPADSZ: return "DT_PLTPADSZ"; case DT_MOVEENT: return "DT_MOVEENT"; case DT_MOVESZ: return "DT_MOVESZ"; case DT_FEATURE: return "DT_FEATURE"; case DT_POSFLAG_1: return "DT_POSFLAG_1"; case DT_SYMINSZ: return "DT_SYMINSZ"; case DT_SYMINENT : return "DT_SYMINENT (DT_VALRNGHI)"; case DT_ADDRRNGLO: return "DT_ADDRRNGLO"; case DT_GNU_HASH: return "DT_GNU_HASH"; case 0x6ffffef8: return "DT_GNU_CONFLICT"; case 0x6ffffef9: return "DT_GNU_LIBLIST"; case DT_CONFIG: return "DT_CONFIG"; case DT_DEPAUDIT: return "DT_DEPAUDIT"; case DT_AUDIT: return "DT_AUDIT"; case DT_PLTPAD: return "DT_PLTPAD"; case DT_MOVETAB: return "DT_MOVETAB"; case DT_SYMINFO : return "DT_SYMINFO (DT_ADDRRNGHI)"; case DT_RELACOUNT: return "DT_RELACOUNT"; case DT_RELCOUNT: return "DT_RELCOUNT"; case DT_FLAGS_1: return "DT_FLAGS_1"; case DT_VERDEF: return "DT_VERDEF"; case DT_VERDEFNUM: return "DT_VERDEFNUM"; case DT_VERNEED: return "DT_VERNEED"; case DT_VERNEEDNUM: return "DT_VERNEEDNUM"; case 0x6ffffff0: return "DT_GNU_VERSYM"; /* 0x70000000 - 0x7fffffff processor-specific semantics */ case 0x70000000: return "DT_IA_64_PLT_RESERVE"; case DT_AUXILIARY: return "DT_AUXILIARY"; case DT_USED: return "DT_USED"; case DT_FILTER: return "DT_FILTER"; } snprintf(unknown_tag, sizeof(unknown_tag), "ERROR: TAG NOT DEFINED -- tag 0x%jx", (uintmax_t)tag); return (unknown_tag); } static const char * e_machines(u_int mach) { static char machdesc[64]; switch (mach) { case EM_NONE: return "EM_NONE"; case EM_M32: return "EM_M32"; case EM_SPARC: return "EM_SPARC"; case EM_386: return "EM_386"; case EM_68K: return "EM_68K"; case EM_88K: return "EM_88K"; case EM_IAMCU: return "EM_IAMCU"; case EM_860: return "EM_860"; case EM_MIPS: return "EM_MIPS"; case EM_PPC: return "EM_PPC"; case EM_PPC64: return "EM_PPC64"; case EM_ARM: return "EM_ARM"; case EM_ALPHA: return "EM_ALPHA (legacy)"; case EM_SPARCV9:return "EM_SPARCV9"; case EM_IA_64: return "EM_IA_64"; case EM_X86_64: return "EM_X86_64"; case EM_AARCH64:return "EM_AARCH64"; case EM_RISCV: return "EM_RISCV"; } snprintf(machdesc, sizeof(machdesc), "(unknown machine) -- type 0x%x", mach); return (machdesc); } static const char *e_types[] = { "ET_NONE", "ET_REL", "ET_EXEC", "ET_DYN", "ET_CORE" }; static const char *ei_versions[] = { "EV_NONE", "EV_CURRENT" }; static const char *ei_classes[] = { "ELFCLASSNONE", "ELFCLASS32", "ELFCLASS64" }; static const char *ei_data[] = { "ELFDATANONE", "ELFDATA2LSB", "ELFDATA2MSB" }; static const char *ei_abis[256] = { "ELFOSABI_NONE", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX", "ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS", "ELFOSABI_AIX", "ELFOSABI_IRIX", "ELFOSABI_FREEBSD", "ELFOSABI_TRU64", "ELFOSABI_MODESTO", "ELFOSABI_OPENBSD", [255] = "ELFOSABI_STANDALONE" }; static const char *p_types[] = { "PT_NULL", "PT_LOAD", "PT_DYNAMIC", "PT_INTERP", "PT_NOTE", "PT_SHLIB", "PT_PHDR", "PT_TLS" }; static const char *p_flags[] = { "", "PF_X", "PF_W", "PF_X|PF_W", "PF_R", "PF_X|PF_R", "PF_W|PF_R", "PF_X|PF_W|PF_R" }; /* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type */ static const char * sh_types(uint64_t machine, uint64_t sht) { static char unknown_buf[64]; if (sht < 0x60000000) { switch (sht) { case SHT_NULL: return "SHT_NULL"; case SHT_PROGBITS: return "SHT_PROGBITS"; case SHT_SYMTAB: return "SHT_SYMTAB"; case SHT_STRTAB: return "SHT_STRTAB"; case SHT_RELA: return "SHT_RELA"; case SHT_HASH: return "SHT_HASH"; case SHT_DYNAMIC: return "SHT_DYNAMIC"; case SHT_NOTE: return "SHT_NOTE"; case SHT_NOBITS: return "SHT_NOBITS"; case SHT_REL: return "SHT_REL"; case SHT_SHLIB: return "SHT_SHLIB"; case SHT_DYNSYM: return "SHT_DYNSYM"; case SHT_INIT_ARRAY: return "SHT_INIT_ARRAY"; case SHT_FINI_ARRAY: return "SHT_FINI_ARRAY"; case SHT_PREINIT_ARRAY: return "SHT_PREINIT_ARRAY"; case SHT_GROUP: return "SHT_GROUP"; case SHT_SYMTAB_SHNDX: return "SHT_SYMTAB_SHNDX"; } snprintf(unknown_buf, sizeof(unknown_buf), "ERROR: SHT %ju NOT DEFINED", (uintmax_t)sht); return (unknown_buf); } else if (sht < 0x70000000) { /* 0x60000000-0x6fffffff operating system-specific semantics */ switch (sht) { case 0x6ffffff0: return "XXX:VERSYM"; case SHT_SUNW_dof: return "SHT_SUNW_dof"; case SHT_GNU_HASH: return "SHT_GNU_HASH"; case 0x6ffffff7: return "SHT_GNU_LIBLIST"; case 0x6ffffffc: return "XXX:VERDEF"; case SHT_SUNW_verdef: return "SHT_SUNW(GNU)_verdef"; case SHT_SUNW_verneed: return "SHT_SUNW(GNU)_verneed"; case SHT_SUNW_versym: return "SHT_SUNW(GNU)_versym"; } snprintf(unknown_buf, sizeof(unknown_buf), "ERROR: OS-SPECIFIC SHT 0x%jx NOT DEFINED", (uintmax_t)sht); return (unknown_buf); } else if (sht < 0x80000000) { /* 0x70000000-0x7fffffff processor-specific semantics */ switch (machine) { case EM_ARM: switch (sht) { case SHT_ARM_EXIDX: return "SHT_ARM_EXIDX"; case SHT_ARM_PREEMPTMAP:return "SHT_ARM_PREEMPTMAP"; case SHT_ARM_ATTRIBUTES:return "SHT_ARM_ATTRIBUTES"; case SHT_ARM_DEBUGOVERLAY: return "SHT_ARM_DEBUGOVERLAY"; case SHT_ARM_OVERLAYSECTION: return "SHT_ARM_OVERLAYSECTION"; } break; case EM_IA_64: switch (sht) { case 0x70000000: return "SHT_IA_64_EXT"; case 0x70000001: return "SHT_IA_64_UNWIND"; } break; case EM_MIPS: switch (sht) { case SHT_MIPS_REGINFO: return "SHT_MIPS_REGINFO"; case SHT_MIPS_OPTIONS: return "SHT_MIPS_OPTIONS"; case SHT_MIPS_ABIFLAGS: return "SHT_MIPS_ABIFLAGS"; } break; } switch (sht) { case 0x7ffffffd: return "XXX:AUXILIARY"; case 0x7fffffff: return "XXX:FILTER"; } snprintf(unknown_buf, sizeof(unknown_buf), "ERROR: PROCESSOR-SPECIFIC SHT 0x%jx NOT DEFINED", (uintmax_t)sht); return (unknown_buf); } else { /* 0x80000000-0xffffffff application programs */ snprintf(unknown_buf, sizeof(unknown_buf), "ERROR: SHT 0x%jx NOT DEFINED", (uintmax_t)sht); return (unknown_buf); } } static const char *sh_flags[] = { "", "SHF_WRITE", "SHF_ALLOC", "SHF_WRITE|SHF_ALLOC", "SHF_EXECINSTR", "SHF_WRITE|SHF_EXECINSTR", "SHF_ALLOC|SHF_EXECINSTR", "SHF_WRITE|SHF_ALLOC|SHF_EXECINSTR" }; static const char * st_type(unsigned int mach, unsigned int type) { static char s_type[32]; switch (type) { case STT_NOTYPE: return "STT_NOTYPE"; case STT_OBJECT: return "STT_OBJECT"; case STT_FUNC: return "STT_FUNC"; case STT_SECTION: return "STT_SECTION"; case STT_FILE: return "STT_FILE"; case STT_COMMON: return "STT_COMMON"; case STT_TLS: return "STT_TLS"; case 13: if (mach == EM_SPARCV9) return "STT_SPARC_REGISTER"; break; } snprintf(s_type, sizeof(s_type), "", type); return (s_type); } static const char *st_bindings[] = { "STB_LOCAL", "STB_GLOBAL", "STB_WEAK" }; static char *dynstr; static char *shstrtab; static char *strtab; static FILE *out; static u_int64_t elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member); static u_int64_t elf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member); #if 0 static u_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member); #endif static u_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member); static u_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member); static void elf_print_ehdr(Elf32_Ehdr *e, void *sh); static void elf_print_phdr(Elf32_Ehdr *e, void *p); static void elf_print_shdr(Elf32_Ehdr *e, void *sh); static void elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str); static void elf_print_dynamic(Elf32_Ehdr *e, void *sh); static void elf_print_rel(Elf32_Ehdr *e, void *r); static void elf_print_rela(Elf32_Ehdr *e, void *ra); static void elf_print_interp(Elf32_Ehdr *e, void *p); static void elf_print_got(Elf32_Ehdr *e, void *sh); static void elf_print_hash(Elf32_Ehdr *e, void *sh); static void elf_print_note(Elf32_Ehdr *e, void *sh); static void usage(void); /* * Helpers for ELF files with shnum or shstrndx values that don't fit in the * ELF header. If the values are too large then an escape value is used to * indicate that the actual value is found in one of section 0's fields. */ static uint64_t elf_get_shnum(Elf32_Ehdr *e, void *sh) { uint64_t shnum; shnum = elf_get_quarter(e, e, E_SHNUM); if (shnum == 0) shnum = elf_get_word(e, (char *)sh, SH_SIZE); return shnum; } static uint64_t elf_get_shstrndx(Elf32_Ehdr *e, void *sh) { uint64_t shstrndx; shstrndx = elf_get_quarter(e, e, E_SHSTRNDX); if (shstrndx == SHN_XINDEX) shstrndx = elf_get_word(e, (char *)sh, SH_LINK); return shstrndx; } int main(int ac, char **av) { cap_rights_t rights; u_int64_t phoff; u_int64_t shoff; u_int64_t phentsize; u_int64_t phnum; u_int64_t shentsize; u_int64_t shnum; u_int64_t shstrndx; u_int64_t offset; u_int64_t name; u_int64_t type; struct stat sb; u_int flags; Elf32_Ehdr *e; void *p; void *sh; void *v; int fd; int ch; int i; out = stdout; flags = 0; while ((ch = getopt(ac, av, "acdeiGhnprsw:")) != -1) switch (ch) { case 'a': flags = ED_ALL; break; case 'c': flags |= ED_SHDR; break; case 'd': flags |= ED_DYN; break; case 'e': flags |= ED_EHDR; break; case 'i': flags |= ED_INTERP; break; case 'G': flags |= ED_GOT; break; case 'h': flags |= ED_HASH; break; case 'n': flags |= ED_NOTE; break; case 'p': flags |= ED_PHDR; break; case 'r': flags |= ED_REL; break; case 's': flags |= ED_SYMTAB; break; case 'w': if ((out = fopen(optarg, "w")) == NULL) err(1, "%s", optarg); cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE); if (cap_rights_limit(fileno(out), &rights) < 0 && errno != ENOSYS) err(1, "unable to limit rights for %s", optarg); break; case '?': default: usage(); } ac -= optind; av += optind; if (ac == 0 || flags == 0) usage(); if ((fd = open(*av, O_RDONLY)) < 0 || fstat(fd, &sb) < 0) err(1, "%s", *av); cap_rights_init(&rights, CAP_MMAP_R); if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS) err(1, "unable to limit rights for %s", *av); cap_rights_init(&rights); if ((cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) || caph_limit_stdout() < 0 || caph_limit_stderr() < 0) { err(1, "unable to limit rights for stdio"); } - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "unable to enter capability mode"); e = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); if (e == MAP_FAILED) err(1, NULL); if (!IS_ELF(*(Elf32_Ehdr *)e)) errx(1, "not an elf file"); phoff = elf_get_off(e, e, E_PHOFF); shoff = elf_get_off(e, e, E_SHOFF); phentsize = elf_get_quarter(e, e, E_PHENTSIZE); phnum = elf_get_quarter(e, e, E_PHNUM); shentsize = elf_get_quarter(e, e, E_SHENTSIZE); p = (char *)e + phoff; if (shoff > 0) { sh = (char *)e + shoff; shnum = elf_get_shnum(e, sh); shstrndx = elf_get_shstrndx(e, sh); offset = elf_get_off(e, (char *)sh + shstrndx * shentsize, SH_OFFSET); shstrtab = (char *)e + offset; } else { sh = NULL; shnum = 0; shstrndx = 0; shstrtab = NULL; } for (i = 0; (u_int64_t)i < shnum; i++) { name = elf_get_word(e, (char *)sh + i * shentsize, SH_NAME); offset = elf_get_off(e, (char *)sh + i * shentsize, SH_OFFSET); if (strcmp(shstrtab + name, ".strtab") == 0) strtab = (char *)e + offset; if (strcmp(shstrtab + name, ".dynstr") == 0) dynstr = (char *)e + offset; } if (flags & ED_EHDR) elf_print_ehdr(e, sh); if (flags & ED_PHDR) elf_print_phdr(e, p); if (flags & ED_SHDR) elf_print_shdr(e, sh); for (i = 0; (u_int64_t)i < phnum; i++) { v = (char *)p + i * phentsize; type = elf_get_word(e, v, P_TYPE); switch (type) { case PT_INTERP: if (flags & ED_INTERP) elf_print_interp(e, v); break; case PT_NULL: case PT_LOAD: case PT_DYNAMIC: case PT_NOTE: case PT_SHLIB: case PT_PHDR: break; } } for (i = 0; (u_int64_t)i < shnum; i++) { v = (char *)sh + i * shentsize; type = elf_get_word(e, v, SH_TYPE); switch (type) { case SHT_SYMTAB: if (flags & ED_SYMTAB) elf_print_symtab(e, v, strtab); break; case SHT_DYNAMIC: if (flags & ED_DYN) elf_print_dynamic(e, v); break; case SHT_RELA: if (flags & ED_REL) elf_print_rela(e, v); break; case SHT_REL: if (flags & ED_REL) elf_print_rel(e, v); break; case SHT_NOTE: name = elf_get_word(e, v, SH_NAME); if (flags & ED_NOTE && strcmp(shstrtab + name, ".note.tag") == 0) elf_print_note(e, v); break; case SHT_DYNSYM: if (flags & ED_SYMTAB) elf_print_symtab(e, v, dynstr); break; case SHT_PROGBITS: name = elf_get_word(e, v, SH_NAME); if (flags & ED_GOT && strcmp(shstrtab + name, ".got") == 0) elf_print_got(e, v); break; case SHT_HASH: if (flags & ED_HASH) elf_print_hash(e, v); break; case SHT_NULL: case SHT_STRTAB: case SHT_NOBITS: case SHT_SHLIB: break; } } return 0; } static void elf_print_ehdr(Elf32_Ehdr *e, void *sh) { u_int64_t class; u_int64_t data; u_int64_t osabi; u_int64_t type; u_int64_t machine; u_int64_t version; u_int64_t entry; u_int64_t phoff; u_int64_t shoff; u_int64_t flags; u_int64_t ehsize; u_int64_t phentsize; u_int64_t phnum; u_int64_t shentsize; u_int64_t shnum; u_int64_t shstrndx; class = elf_get_byte(e, e, E_CLASS); data = elf_get_byte(e, e, E_DATA); osabi = elf_get_byte(e, e, E_OSABI); type = elf_get_quarter(e, e, E_TYPE); machine = elf_get_quarter(e, e, E_MACHINE); version = elf_get_word(e, e, E_VERSION); entry = elf_get_addr(e, e, E_ENTRY); phoff = elf_get_off(e, e, E_PHOFF); shoff = elf_get_off(e, e, E_SHOFF); flags = elf_get_word(e, e, E_FLAGS); ehsize = elf_get_quarter(e, e, E_EHSIZE); phentsize = elf_get_quarter(e, e, E_PHENTSIZE); phnum = elf_get_quarter(e, e, E_PHNUM); shentsize = elf_get_quarter(e, e, E_SHENTSIZE); fprintf(out, "\nelf header:\n"); fprintf(out, "\n"); fprintf(out, "\te_ident: %s %s %s\n", ei_classes[class], ei_data[data], ei_abis[osabi]); fprintf(out, "\te_type: %s\n", e_types[type]); fprintf(out, "\te_machine: %s\n", e_machines(machine)); fprintf(out, "\te_version: %s\n", ei_versions[version]); fprintf(out, "\te_entry: %#jx\n", (intmax_t)entry); fprintf(out, "\te_phoff: %jd\n", (intmax_t)phoff); fprintf(out, "\te_shoff: %jd\n", (intmax_t)shoff); fprintf(out, "\te_flags: %jd\n", (intmax_t)flags); fprintf(out, "\te_ehsize: %jd\n", (intmax_t)ehsize); fprintf(out, "\te_phentsize: %jd\n", (intmax_t)phentsize); fprintf(out, "\te_phnum: %jd\n", (intmax_t)phnum); fprintf(out, "\te_shentsize: %jd\n", (intmax_t)shentsize); if (sh != NULL) { shnum = elf_get_shnum(e, sh); shstrndx = elf_get_shstrndx(e, sh); fprintf(out, "\te_shnum: %jd\n", (intmax_t)shnum); fprintf(out, "\te_shstrndx: %jd\n", (intmax_t)shstrndx); } } static void elf_print_phdr(Elf32_Ehdr *e, void *p) { u_int64_t phentsize; u_int64_t phnum; u_int64_t type; u_int64_t offset; u_int64_t vaddr; u_int64_t paddr; u_int64_t filesz; u_int64_t memsz; u_int64_t flags; u_int64_t align; void *v; int i; phentsize = elf_get_quarter(e, e, E_PHENTSIZE); phnum = elf_get_quarter(e, e, E_PHNUM); fprintf(out, "\nprogram header:\n"); for (i = 0; (u_int64_t)i < phnum; i++) { v = (char *)p + i * phentsize; type = elf_get_word(e, v, P_TYPE); offset = elf_get_off(e, v, P_OFFSET); vaddr = elf_get_addr(e, v, P_VADDR); paddr = elf_get_addr(e, v, P_PADDR); filesz = elf_get_size(e, v, P_FILESZ); memsz = elf_get_size(e, v, P_MEMSZ); flags = elf_get_word(e, v, P_FLAGS); align = elf_get_size(e, v, P_ALIGN); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\tp_type: %s\n", p_types[type & 0x7]); fprintf(out, "\tp_offset: %jd\n", (intmax_t)offset); fprintf(out, "\tp_vaddr: %#jx\n", (intmax_t)vaddr); fprintf(out, "\tp_paddr: %#jx\n", (intmax_t)paddr); fprintf(out, "\tp_filesz: %jd\n", (intmax_t)filesz); fprintf(out, "\tp_memsz: %jd\n", (intmax_t)memsz); fprintf(out, "\tp_flags: %s\n", p_flags[flags]); fprintf(out, "\tp_align: %jd\n", (intmax_t)align); } } static void elf_print_shdr(Elf32_Ehdr *e, void *sh) { u_int64_t shentsize; u_int64_t shnum; u_int64_t name; u_int64_t type; u_int64_t flags; u_int64_t addr; u_int64_t offset; u_int64_t size; u_int64_t shlink; u_int64_t info; u_int64_t addralign; u_int64_t entsize; u_int64_t machine; void *v; int i; if (sh == NULL) { fprintf(out, "\nNo section headers\n"); return; } machine = elf_get_quarter(e, e, E_MACHINE); shentsize = elf_get_quarter(e, e, E_SHENTSIZE); shnum = elf_get_shnum(e, sh); fprintf(out, "\nsection header:\n"); for (i = 0; (u_int64_t)i < shnum; i++) { v = (char *)sh + i * shentsize; name = elf_get_word(e, v, SH_NAME); type = elf_get_word(e, v, SH_TYPE); flags = elf_get_word(e, v, SH_FLAGS); addr = elf_get_addr(e, v, SH_ADDR); offset = elf_get_off(e, v, SH_OFFSET); size = elf_get_size(e, v, SH_SIZE); shlink = elf_get_word(e, v, SH_LINK); info = elf_get_word(e, v, SH_INFO); addralign = elf_get_size(e, v, SH_ADDRALIGN); entsize = elf_get_size(e, v, SH_ENTSIZE); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\tsh_name: %s\n", shstrtab + name); fprintf(out, "\tsh_type: %s\n", sh_types(machine, type)); fprintf(out, "\tsh_flags: %s\n", sh_flags[flags & 0x7]); fprintf(out, "\tsh_addr: %#jx\n", addr); fprintf(out, "\tsh_offset: %jd\n", (intmax_t)offset); fprintf(out, "\tsh_size: %jd\n", (intmax_t)size); fprintf(out, "\tsh_link: %jd\n", (intmax_t)shlink); fprintf(out, "\tsh_info: %jd\n", (intmax_t)info); fprintf(out, "\tsh_addralign: %jd\n", (intmax_t)addralign); fprintf(out, "\tsh_entsize: %jd\n", (intmax_t)entsize); } } static void elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str) { u_int64_t machine; u_int64_t offset; u_int64_t entsize; u_int64_t size; u_int64_t name; u_int64_t value; u_int64_t info; u_int64_t shndx; void *st; int len; int i; machine = elf_get_quarter(e, e, E_MACHINE); offset = elf_get_off(e, sh, SH_OFFSET); entsize = elf_get_size(e, sh, SH_ENTSIZE); size = elf_get_size(e, sh, SH_SIZE); name = elf_get_word(e, sh, SH_NAME); len = size / entsize; fprintf(out, "\nsymbol table (%s):\n", shstrtab + name); for (i = 0; i < len; i++) { st = (char *)e + offset + i * entsize; name = elf_get_word(e, st, ST_NAME); value = elf_get_addr(e, st, ST_VALUE); size = elf_get_size(e, st, ST_SIZE); info = elf_get_byte(e, st, ST_INFO); shndx = elf_get_quarter(e, st, ST_SHNDX); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\tst_name: %s\n", str + name); fprintf(out, "\tst_value: %#jx\n", value); fprintf(out, "\tst_size: %jd\n", (intmax_t)size); fprintf(out, "\tst_info: %s %s\n", st_type(machine, ELF32_ST_TYPE(info)), st_bindings[ELF32_ST_BIND(info)]); fprintf(out, "\tst_shndx: %jd\n", (intmax_t)shndx); } } static void elf_print_dynamic(Elf32_Ehdr *e, void *sh) { u_int64_t offset; u_int64_t entsize; u_int64_t size; int64_t tag; u_int64_t ptr; u_int64_t val; void *d; int i; offset = elf_get_off(e, sh, SH_OFFSET); entsize = elf_get_size(e, sh, SH_ENTSIZE); size = elf_get_size(e, sh, SH_SIZE); fprintf(out, "\ndynamic:\n"); for (i = 0; (u_int64_t)i < size / entsize; i++) { d = (char *)e + offset + i * entsize; tag = elf_get_size(e, d, D_TAG); ptr = elf_get_size(e, d, D_PTR); val = elf_get_addr(e, d, D_VAL); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\td_tag: %s\n", d_tags(tag)); switch (tag) { case DT_NEEDED: case DT_SONAME: case DT_RPATH: fprintf(out, "\td_val: %s\n", dynstr + val); break; case DT_PLTRELSZ: case DT_RELA: case DT_RELASZ: case DT_RELAENT: case DT_STRSZ: case DT_SYMENT: case DT_RELSZ: case DT_RELENT: case DT_PLTREL: fprintf(out, "\td_val: %jd\n", (intmax_t)val); break; case DT_PLTGOT: case DT_HASH: case DT_STRTAB: case DT_SYMTAB: case DT_INIT: case DT_FINI: case DT_REL: case DT_JMPREL: fprintf(out, "\td_ptr: %#jx\n", ptr); break; case DT_NULL: case DT_SYMBOLIC: case DT_DEBUG: case DT_TEXTREL: break; } } } static void elf_print_rela(Elf32_Ehdr *e, void *sh) { u_int64_t offset; u_int64_t entsize; u_int64_t size; u_int64_t name; u_int64_t info; int64_t addend; void *ra; void *v; int i; offset = elf_get_off(e, sh, SH_OFFSET); entsize = elf_get_size(e, sh, SH_ENTSIZE); size = elf_get_size(e, sh, SH_SIZE); name = elf_get_word(e, sh, SH_NAME); v = (char *)e + offset; fprintf(out, "\nrelocation with addend (%s):\n", shstrtab + name); for (i = 0; (u_int64_t)i < size / entsize; i++) { ra = (char *)v + i * entsize; offset = elf_get_addr(e, ra, RA_OFFSET); info = elf_get_word(e, ra, RA_INFO); addend = elf_get_off(e, ra, RA_ADDEND); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\tr_offset: %#jx\n", offset); fprintf(out, "\tr_info: %jd\n", (intmax_t)info); fprintf(out, "\tr_addend: %jd\n", (intmax_t)addend); } } static void elf_print_rel(Elf32_Ehdr *e, void *sh) { u_int64_t offset; u_int64_t entsize; u_int64_t size; u_int64_t name; u_int64_t info; void *r; void *v; int i; offset = elf_get_off(e, sh, SH_OFFSET); entsize = elf_get_size(e, sh, SH_ENTSIZE); size = elf_get_size(e, sh, SH_SIZE); name = elf_get_word(e, sh, SH_NAME); v = (char *)e + offset; fprintf(out, "\nrelocation (%s):\n", shstrtab + name); for (i = 0; (u_int64_t)i < size / entsize; i++) { r = (char *)v + i * entsize; offset = elf_get_addr(e, r, R_OFFSET); info = elf_get_word(e, r, R_INFO); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\tr_offset: %#jx\n", offset); fprintf(out, "\tr_info: %jd\n", (intmax_t)info); } } static void elf_print_interp(Elf32_Ehdr *e, void *p) { u_int64_t offset; char *s; offset = elf_get_off(e, p, P_OFFSET); s = (char *)e + offset; fprintf(out, "\ninterp:\n"); fprintf(out, "\t%s\n", s); } static void elf_print_got(Elf32_Ehdr *e, void *sh) { u_int64_t offset; u_int64_t addralign; u_int64_t size; u_int64_t addr; void *v; int i; offset = elf_get_off(e, sh, SH_OFFSET); addralign = elf_get_size(e, sh, SH_ADDRALIGN); size = elf_get_size(e, sh, SH_SIZE); v = (char *)e + offset; fprintf(out, "\nglobal offset table:\n"); for (i = 0; (u_int64_t)i < size / addralign; i++) { addr = elf_get_addr(e, (char *)v + i * addralign, 0); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\t%#jx\n", addr); } } static void elf_print_hash(Elf32_Ehdr *e __unused, void *sh __unused) { } static void elf_print_note(Elf32_Ehdr *e, void *sh) { u_int64_t offset; u_int64_t size; u_int64_t name; u_int32_t namesz; u_int32_t descsz; u_int32_t desc; char *n, *s; offset = elf_get_off(e, sh, SH_OFFSET); size = elf_get_size(e, sh, SH_SIZE); name = elf_get_word(e, sh, SH_NAME); n = (char *)e + offset; fprintf(out, "\nnote (%s):\n", shstrtab + name); while (n < ((char *)e + offset + size)) { namesz = elf_get_word(e, n, N_NAMESZ); descsz = elf_get_word(e, n, N_DESCSZ); s = n + sizeof(Elf_Note); desc = elf_get_word(e, n + sizeof(Elf_Note) + namesz, 0); fprintf(out, "\t%s %d\n", s, desc); n += sizeof(Elf_Note) + namesz + descsz; } } static u_int64_t elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member) { u_int64_t val; val = 0; switch (e->e_ident[EI_CLASS]) { case ELFCLASS32: val = ((uint8_t *)base)[elf32_offsets[member]]; break; case ELFCLASS64: val = ((uint8_t *)base)[elf64_offsets[member]]; break; case ELFCLASSNONE: errx(1, "invalid class"); } return val; } static u_int64_t elf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member) { u_int64_t val; val = 0; switch (e->e_ident[EI_CLASS]) { case ELFCLASS32: base = (char *)base + elf32_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be16dec(base); break; case ELFDATA2LSB: val = le16dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASS64: base = (char *)base + elf64_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be16dec(base); break; case ELFDATA2LSB: val = le16dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASSNONE: errx(1, "invalid class"); } return val; } #if 0 static u_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member) { u_int64_t val; val = 0; switch (e->e_ident[EI_CLASS]) { case ELFCLASS32: base = (char *)base + elf32_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be16dec(base); break; case ELFDATA2LSB: val = le16dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASS64: base = (char *)base + elf64_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be32dec(base); break; case ELFDATA2LSB: val = le32dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASSNONE: errx(1, "invalid class"); } return val; } #endif static u_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member) { u_int64_t val; val = 0; switch (e->e_ident[EI_CLASS]) { case ELFCLASS32: base = (char *)base + elf32_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be32dec(base); break; case ELFDATA2LSB: val = le32dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASS64: base = (char *)base + elf64_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be32dec(base); break; case ELFDATA2LSB: val = le32dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASSNONE: errx(1, "invalid class"); } return val; } static u_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member) { u_int64_t val; val = 0; switch (e->e_ident[EI_CLASS]) { case ELFCLASS32: base = (char *)base + elf32_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be32dec(base); break; case ELFDATA2LSB: val = le32dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASS64: base = (char *)base + elf64_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be64dec(base); break; case ELFDATA2LSB: val = le64dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASSNONE: errx(1, "invalid class"); } return val; } static void usage(void) { fprintf(stderr, "usage: elfdump -a | -cdeGhinprs [-w file] file\n"); exit(1); } Index: head/usr.bin/getopt/getopt.c =================================================================== --- head/usr.bin/getopt/getopt.c (revision 335394) +++ head/usr.bin/getopt/getopt.c (revision 335395) @@ -1,43 +1,43 @@ #include __FBSDID("$FreeBSD$"); /* * This material, written by Henry Spencer, was released by him * into the public domain and is thus not subject to any copyright. */ #include #include #include #include #include #include int main(int argc, char *argv[]) { int c; int status = 0; - if (caph_limit_stdio() < 0 || (cap_enter() < 0 && errno != ENOSYS)) + if (caph_limit_stdio() < 0 || caph_enter() < 0) err(1, "capsicum"); optind = 2; /* Past the program name and the option letters. */ while ((c = getopt(argc, argv, argv[1])) != -1) switch (c) { case '?': status = 1; /* getopt routine gave message */ break; default: if (optarg != NULL) printf(" -%c %s", c, optarg); else printf(" -%c", c); break; } printf(" --"); for (; optind < argc; optind++) printf(" %s", argv[optind]); printf("\n"); return status; } Index: head/usr.bin/hexdump/display.c =================================================================== --- head/usr.bin/hexdump/display.c (revision 335394) +++ head/usr.bin/hexdump/display.c (revision 335395) @@ -1,437 +1,437 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * 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. 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. */ #ifndef lint #if 0 static char sccsid[] = "@(#)display.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hexdump.h" enum _vflag vflag = FIRST; static off_t address; /* address/offset in stream */ static off_t eaddress; /* end address */ static void print(PR *, u_char *); static void noseek(void); void display(void) { FS *fs; FU *fu; PR *pr; int cnt; u_char *bp; off_t saveaddress; u_char savech, *savebp; savech = 0; while ((bp = get())) for (fs = fshead, savebp = bp, saveaddress = address; fs; fs = fs->nextfs, bp = savebp, address = saveaddress) for (fu = fs->nextfu; fu; fu = fu->nextfu) { if (fu->flags&F_IGNORE) break; for (cnt = fu->reps; cnt; --cnt) for (pr = fu->nextpr; pr; address += pr->bcnt, bp += pr->bcnt, pr = pr->nextpr) { if (eaddress && address >= eaddress && !(pr->flags & (F_TEXT|F_BPAD))) bpad(pr); if (cnt == 1 && pr->nospace) { savech = *pr->nospace; *pr->nospace = '\0'; } print(pr, bp); if (cnt == 1 && pr->nospace) *pr->nospace = savech; } } if (endfu) { /* * If eaddress not set, error or file size was multiple of * blocksize, and no partial block ever found. */ if (!eaddress) { if (!address) return; eaddress = address; } for (pr = endfu->nextpr; pr; pr = pr->nextpr) switch(pr->flags) { case F_ADDRESS: (void)printf(pr->fmt, (quad_t)eaddress); break; case F_TEXT: (void)printf("%s", pr->fmt); break; } } } static void print(PR *pr, u_char *bp) { long double ldbl; double f8; float f4; int16_t s2; int8_t s8; int32_t s4; u_int16_t u2; u_int32_t u4; u_int64_t u8; switch(pr->flags) { case F_ADDRESS: (void)printf(pr->fmt, (quad_t)address); break; case F_BPAD: (void)printf(pr->fmt, ""); break; case F_C: conv_c(pr, bp, eaddress ? eaddress - address : blocksize - address % blocksize); break; case F_CHAR: (void)printf(pr->fmt, *bp); break; case F_DBL: switch(pr->bcnt) { case 4: bcopy(bp, &f4, sizeof(f4)); (void)printf(pr->fmt, f4); break; case 8: bcopy(bp, &f8, sizeof(f8)); (void)printf(pr->fmt, f8); break; default: if (pr->bcnt == sizeof(long double)) { bcopy(bp, &ldbl, sizeof(ldbl)); (void)printf(pr->fmt, ldbl); } break; } break; case F_INT: switch(pr->bcnt) { case 1: (void)printf(pr->fmt, (quad_t)(signed char)*bp); break; case 2: bcopy(bp, &s2, sizeof(s2)); (void)printf(pr->fmt, (quad_t)s2); break; case 4: bcopy(bp, &s4, sizeof(s4)); (void)printf(pr->fmt, (quad_t)s4); break; case 8: bcopy(bp, &s8, sizeof(s8)); (void)printf(pr->fmt, s8); break; } break; case F_P: (void)printf(pr->fmt, isprint(*bp) ? *bp : '.'); break; case F_STR: (void)printf(pr->fmt, (char *)bp); break; case F_TEXT: (void)printf("%s", pr->fmt); break; case F_U: conv_u(pr, bp); break; case F_UINT: switch(pr->bcnt) { case 1: (void)printf(pr->fmt, (u_quad_t)*bp); break; case 2: bcopy(bp, &u2, sizeof(u2)); (void)printf(pr->fmt, (u_quad_t)u2); break; case 4: bcopy(bp, &u4, sizeof(u4)); (void)printf(pr->fmt, (u_quad_t)u4); break; case 8: bcopy(bp, &u8, sizeof(u8)); (void)printf(pr->fmt, u8); break; } break; } } void bpad(PR *pr) { static char const *spec = " -0+#"; char *p1, *p2; /* * Remove all conversion flags; '-' is the only one valid * with %s, and it's not useful here. */ pr->flags = F_BPAD; pr->cchar[0] = 's'; pr->cchar[1] = '\0'; for (p1 = pr->fmt; *p1 != '%'; ++p1); for (p2 = ++p1; *p1 && strchr(spec, *p1); ++p1); while ((*p2++ = *p1++)); } static char **_argv; u_char * get(void) { static int ateof = 1; static u_char *curp, *savp; int n; int need, nread; int valid_save = 0; u_char *tmpp; if (!curp) { if ((curp = calloc(1, blocksize)) == NULL) err(1, NULL); if ((savp = calloc(1, blocksize)) == NULL) err(1, NULL); } else { tmpp = curp; curp = savp; savp = tmpp; address += blocksize; valid_save = 1; } for (need = blocksize, nread = 0;;) { /* * if read the right number of bytes, or at EOF for one file, * and no other files are available, zero-pad the rest of the * block and set the end flag. */ if (!length || (ateof && !next((char **)NULL))) { if (odmode && address < skip) errx(1, "cannot skip past end of input"); if (need == blocksize) return((u_char *)NULL); /* * XXX bcmp() is not quite right in the presence * of multibyte characters. */ if (vflag != ALL && valid_save && bcmp(curp, savp, nread) == 0) { if (vflag != DUP) (void)printf("*\n"); return((u_char *)NULL); } bzero((char *)curp + nread, need); eaddress = address + nread; return(curp); } n = fread((char *)curp + nread, sizeof(u_char), length == -1 ? need : MIN(length, need), stdin); if (!n) { if (ferror(stdin)) warn("%s", _argv[-1]); ateof = 1; continue; } ateof = 0; if (length != -1) length -= n; if (!(need -= n)) { /* * XXX bcmp() is not quite right in the presence * of multibyte characters. */ if (vflag == ALL || vflag == FIRST || valid_save == 0 || bcmp(curp, savp, blocksize) != 0) { if (vflag == DUP || vflag == FIRST) vflag = WAIT; return(curp); } if (vflag == WAIT) (void)printf("*\n"); vflag = DUP; address += blocksize; need = blocksize; nread = 0; } else nread += n; } } size_t peek(u_char *buf, size_t nbytes) { size_t n, nread; int c; if (length != -1 && nbytes > (unsigned int)length) nbytes = length; nread = 0; while (nread < nbytes && (c = getchar()) != EOF) { *buf++ = c; nread++; } n = nread; while (n-- > 0) { c = *--buf; ungetc(c, stdin); } return (nread); } int next(char **argv) { static int done; int statok; if (argv) { _argv = argv; return(1); } for (;;) { if (*_argv) { done = 1; if (!(freopen(*_argv, "r", stdin))) { warn("%s", *_argv); exitval = 1; ++_argv; continue; } statok = 1; } else { if (done++) return(0); statok = 0; } if (caph_limit_stream(fileno(stdin), CAPH_READ) < 0) err(1, "unable to restrict %s", statok ? *_argv : "stdin"); /* * We've opened our last input file; enter capsicum sandbox. */ if (statok == 0 || *(_argv + 1) == NULL) { - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "unable to enter capability mode"); } if (skip) doskip(statok ? *_argv : "stdin", statok); if (*_argv) ++_argv; if (!skip) return(1); } /* NOTREACHED */ } void doskip(const char *fname, int statok) { int type; struct stat sb; if (statok) { if (fstat(fileno(stdin), &sb)) err(1, "%s", fname); if (S_ISREG(sb.st_mode) && skip > sb.st_size) { address += sb.st_size; skip -= sb.st_size; return; } } if (!statok || S_ISFIFO(sb.st_mode) || S_ISSOCK(sb.st_mode)) { noseek(); return; } if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) { if (ioctl(fileno(stdin), FIODTYPE, &type)) err(1, "%s", fname); /* * Most tape drives don't support seeking, * yet fseek() would succeed. */ if (type & D_TAPE) { noseek(); return; } } if (fseeko(stdin, skip, SEEK_SET)) { noseek(); return; } address += skip; skip = 0; } static void noseek(void) { int count; for (count = 0; count < skip; ++count) if (getchar() == EOF) break; address += count; skip -= count; } Index: head/usr.bin/iconv/iconv.c =================================================================== --- head/usr.bin/iconv/iconv.c (revision 335394) +++ head/usr.bin/iconv/iconv.c (revision 335395) @@ -1,243 +1,243 @@ /* $FreeBSD$ */ /* $NetBSD: iconv.c,v 1.16 2009/02/20 15:28:21 yamt Exp $ */ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c)2003 Citrus Project, * 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. * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int do_conv(FILE *, iconv_t, bool, bool); static int do_list(unsigned int, const char * const *, void *); static void usage(void) __dead2; static const struct option long_options[] = { {"from-code", required_argument, NULL, 'f'}, {"list", no_argument, NULL, 'l'}, {"silent", no_argument, NULL, 's'}, {"to-code", required_argument, NULL, 't'}, {NULL, no_argument, NULL, 0} }; static void usage(void) { (void)fprintf(stderr, "Usage:\t%1$s [-cs] -f -t [file ...]\n" "\t%1$s -f [-cs] [-t ] [file ...]\n" "\t%1$s -t [-cs] [-f ] [file ...]\n" "\t%1$s -l\n", getprogname()); exit(1); } #define INBUFSIZE 1024 #define OUTBUFSIZE (INBUFSIZE * 2) static int do_conv(FILE *fp, iconv_t cd, bool silent, bool hide_invalid) { char inbuf[INBUFSIZE], outbuf[OUTBUFSIZE], *in, *out; unsigned long long invalids; size_t inbytes, outbytes, ret; int arg = (int)hide_invalid; if (iconvctl(cd, ICONV_SET_DISCARD_ILSEQ, (void *)&arg) == -1) err(EXIT_FAILURE, "iconvctl(DISCARD_ILSEQ, %d)", arg); invalids = 0; while ((inbytes = fread(inbuf, 1, INBUFSIZE, fp)) > 0) { in = inbuf; while (inbytes > 0) { size_t inval; out = outbuf; outbytes = OUTBUFSIZE; ret = __iconv(cd, &in, &inbytes, &out, &outbytes, 0, &inval); invalids += inval; if (outbytes < OUTBUFSIZE) (void)fwrite(outbuf, 1, OUTBUFSIZE - outbytes, stdout); if (ret == (size_t)-1 && errno != E2BIG) { if (errno != EINVAL || in == inbuf) err(EXIT_FAILURE, "iconv()"); /* incomplete input character */ (void)memmove(inbuf, in, inbytes); ret = fread(inbuf + inbytes, 1, INBUFSIZE - inbytes, fp); if (ret == 0) { fflush(stdout); if (feof(fp)) errx(EXIT_FAILURE, "unexpected end of file; " "the last character is " "incomplete."); else err(EXIT_FAILURE, "fread()"); } in = inbuf; inbytes += ret; } } } /* reset the shift state of the output buffer */ outbytes = OUTBUFSIZE; out = outbuf; ret = iconv(cd, NULL, NULL, &out, &outbytes); if (ret == (size_t)-1) err(EXIT_FAILURE, "iconv()"); if (outbytes < OUTBUFSIZE) (void)fwrite(outbuf, 1, OUTBUFSIZE - outbytes, stdout); if (invalids > 0 && !silent) warnx("warning: invalid characters: %llu", invalids); return (invalids > 0); } static int do_list(unsigned int n, const char * const *list, void *data __unused) { unsigned int i; for(i = 0; i < n; i++) { printf("%s", list[i]); if (i < n - 1) printf(" "); } printf("\n"); return (1); } int main(int argc, char **argv) { iconv_t cd; FILE *fp; const char *opt_f, *opt_t; int ch, i, res; bool opt_c = false, opt_s = false; opt_f = opt_t = ""; setlocale(LC_ALL, ""); setprogname(argv[0]); while ((ch = getopt_long(argc, argv, "csLlf:t:", long_options, NULL)) != -1) { switch (ch) { case 'c': opt_c = true; break; case 's': opt_s = true; break; case 'l': /* list */ if (opt_s || opt_c || strcmp(opt_f, "") != 0 || strcmp(opt_t, "") != 0) { warnx("-l is not allowed with other flags."); usage(); } iconvlist(do_list, NULL); return (EXIT_SUCCESS); case 'f': /* from */ if (optarg != NULL) opt_f = optarg; break; case 't': /* to */ if (optarg != NULL) opt_t = optarg; break; default: usage(); } } argc -= optind; argv += optind; if ((strcmp(opt_f, "") == 0) && (strcmp(opt_t, "") == 0)) usage(); if (caph_limit_stdio() < 0) err(EXIT_FAILURE, "capsicum"); /* * Cache NLS data, for strerror, for err(3), before entering capability * mode. */ caph_cache_catpages(); /* * Cache iconv conversion handle before entering sandbox. */ cd = iconv_open(opt_t, opt_f); if (cd == (iconv_t)-1) err(EXIT_FAILURE, "iconv_open(%s, %s)", opt_t, opt_f); if (argc == 0) { - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(EXIT_FAILURE, "unable to enter capability mode"); res = do_conv(stdin, cd, opt_s, opt_c); } else { res = 0; for (i = 0; i < argc; i++) { fp = (strcmp(argv[i], "-") != 0) ? fopen(argv[i], "r") : stdin; if (fp == NULL) err(EXIT_FAILURE, "Cannot open `%s'", argv[i]); /* Enter Capsicum sandbox for final input file. */ - if (i + 1 == argc && cap_enter() < 0 && errno != ENOSYS) + if (i + 1 == argc && caph_enter() < 0) err(EXIT_FAILURE, "unable to enter capability mode"); res |= do_conv(fp, cd, opt_s, opt_c); (void)fclose(fp); /* Reset iconv descriptor state. */ (void)iconv(cd, NULL, NULL, NULL, NULL); } } iconv_close(cd); return (res == 0 ? EXIT_SUCCESS : EXIT_FAILURE); } Index: head/usr.bin/ident/ident.c =================================================================== --- head/usr.bin/ident/ident.c (revision 335394) +++ head/usr.bin/ident/ident.c (revision 335395) @@ -1,278 +1,278 @@ /*- * Copyright (c) 2015 Baptiste Daroussin * Copyright (c) 2015 Xin LI * * 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 * in this position and unchanged. * 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 AUTHOR(S) ``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(S) 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include typedef enum { /* state condition to transit to next state */ INIT, /* '$' */ DELIM_SEEN, /* letter */ KEYWORD, /* punctuation mark */ PUNC_SEEN, /* ':' -> _SVN; space -> TEXT */ PUNC_SEEN_SVN, /* space */ TEXT } analyzer_states; static int scan(FILE *fp, const char *name, bool quiet) { int c; bool hasid = false; bool subversion = false; analyzer_states state = INIT; struct sbuf *id = sbuf_new_auto(); locale_t l; l = newlocale(LC_ALL_MASK, "C", NULL); if (name != NULL) printf("%s:\n", name); while ((c = fgetc(fp)) != EOF) { switch (state) { case INIT: if (c == '$') { /* Transit to DELIM_SEEN if we see $ */ state = DELIM_SEEN; } else { /* Otherwise, stay in INIT state */ continue; } break; case DELIM_SEEN: if (isalpha_l(c, l)) { /* Transit to KEYWORD if we see letter */ sbuf_clear(id); sbuf_putc(id, '$'); sbuf_putc(id, c); state = KEYWORD; continue; } else if (c == '$') { /* Or, stay in DELIM_SEEN if more $ */ continue; } else { /* Otherwise, transit back to INIT */ state = INIT; } break; case KEYWORD: sbuf_putc(id, c); if (isalpha_l(c, l)) { /* * Stay in KEYWORD if additional letter is seen */ continue; } else if (c == ':') { /* * See ':' for the first time, transit to * PUNC_SEEN. */ state = PUNC_SEEN; subversion = false; } else if (c == '$') { /* * Incomplete ident. Go back to DELIM_SEEN * state because we see a '$' which could be * the beginning of a keyword. */ state = DELIM_SEEN; } else { /* * Go back to INIT state otherwise. */ state = INIT; } break; case PUNC_SEEN: case PUNC_SEEN_SVN: sbuf_putc(id, c); switch (c) { case ':': /* * If we see '::' (seen : in PUNC_SEEN), * activate subversion treatment and transit * to PUNC_SEEN_SVN state. * * If more than two :'s were seen, the ident * is invalid and we would therefore go back * to INIT state. */ if (state == PUNC_SEEN) { state = PUNC_SEEN_SVN; subversion = true; } else { state = INIT; } break; case ' ': /* * A space after ':' or '::' indicates we are at the * last component of potential ident. */ state = TEXT; break; default: /* All other characters are invalid */ state = INIT; break; } break; case TEXT: sbuf_putc(id, c); if (iscntrl_l(c, l)) { /* Control characters are not allowed in this state */ state = INIT; } else if (c == '$') { sbuf_finish(id); /* * valid ident should end with a space. * * subversion extension uses '#' to indicate that * the keyword expansion have exceeded the fixed * width, so it is also permitted if we are in * subversion mode. No length check is enforced * because GNU RCS ident(1) does not do it either. */ c = sbuf_data(id)[sbuf_len(id) - 2]; if (c == ' ' || (subversion && c == '#')) { printf(" %s\n", sbuf_data(id)); hasid = true; } state = INIT; } /* Other characters: stay in the state */ break; } } sbuf_delete(id); freelocale(l); if (!hasid) { if (!quiet) fprintf(stderr, "%s warning: no id keywords in %s\n", getprogname(), name ? name : "standard input"); return (EXIT_FAILURE); } return (EXIT_SUCCESS); } int main(int argc, char **argv) { bool quiet = false; int ch, i, *fds, fd; int ret = EXIT_SUCCESS; size_t nfds; FILE *fp; while ((ch = getopt(argc, argv, "qV")) != -1) { switch (ch) { case 'q': quiet = true; break; case 'V': /* Do nothing, compat with GNU rcs's ident */ return (EXIT_SUCCESS); default: errx(EXIT_FAILURE, "usage: %s [-q] [-V] [file...]", getprogname()); } } argc -= optind; argv += optind; if (caph_limit_stdio() < 0) err(EXIT_FAILURE, "unable to limit stdio"); if (argc == 0) { nfds = 1; fds = malloc(sizeof(*fds)); if (fds == NULL) err(EXIT_FAILURE, "unable to allocate fds array"); fds[0] = STDIN_FILENO; } else { nfds = argc; fds = malloc(sizeof(*fds) * nfds); if (fds == NULL) err(EXIT_FAILURE, "unable to allocate fds array"); for (i = 0; i < argc; i++) { fds[i] = fd = open(argv[i], O_RDONLY); if (fd < 0) { warn("%s", argv[i]); ret = EXIT_FAILURE; continue; } if (caph_limit_stream(fd, CAPH_READ) < 0) err(EXIT_FAILURE, "unable to limit fcntls/rights for %s", argv[i]); } } /* Enter Capsicum sandbox. */ - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(EXIT_FAILURE, "unable to enter capability mode"); for (i = 0; i < (int)nfds; i++) { if (fds[i] < 0) continue; fp = fdopen(fds[i], "r"); if (fp == NULL) { warn("%s", argv[i]); ret = EXIT_FAILURE; continue; } if (scan(fp, argc == 0 ? NULL : argv[i], quiet) != EXIT_SUCCESS) ret = EXIT_FAILURE; fclose(fp); } return (ret); } Index: head/usr.bin/indent/indent.c =================================================================== --- head/usr.bin/indent/indent.c (revision 335394) +++ head/usr.bin/indent/indent.c (revision 335395) @@ -1,1291 +1,1292 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 1985 Sun Microsystems, Inc. * Copyright (c) 1976 Board of Trustees of the University of Illinois. * Copyright (c) 1980, 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. */ #if 0 #ifndef lint static char sccsid[] = "@(#)indent.c 5.17 (Berkeley) 6/7/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include #include #include #include #include #include #include "indent_globs.h" #include "indent_codes.h" #include "indent.h" static void bakcopy(void); static void indent_declaration(int, int); const char *in_name = "Standard Input"; /* will always point to name of input * file */ const char *out_name = "Standard Output"; /* will always point to name * of output file */ const char *simple_backup_suffix = ".BAK"; /* Suffix to use for backup * files */ char bakfile[MAXPATHLEN] = ""; int main(int argc, char **argv) { cap_rights_t rights; int dec_ind; /* current indentation for declarations */ int di_stack[20]; /* a stack of structure indentation levels */ int force_nl; /* when true, code must be broken */ int hd_type = 0; /* used to store type of stmt for if (...), * for (...), etc */ int i; /* local loop counter */ int scase; /* set to true when we see a case, so we will * know what to do with the following colon */ int sp_sw; /* when true, we are in the expression of * if(...), while(...), etc. */ int squest; /* when this is positive, we have seen a ? * without the matching : in a ?: * construct */ const char *t_ptr; /* used for copying tokens */ int tabs_to_var; /* true if using tabs to indent to var name */ int type_code; /* the type of token, returned by lexi */ int last_else = 0; /* true iff last keyword was an else */ const char *profile_name = NULL; const char *envval = NULL; struct parser_state transient_state; /* a copy for lookup */ /*-----------------------------------------------*\ | INITIALIZATION | \*-----------------------------------------------*/ found_err = 0; ps.p_stack[0] = stmt; /* this is the parser's stack */ ps.last_nl = true; /* this is true if the last thing scanned was * a newline */ ps.last_token = semicolon; combuf = (char *) malloc(bufsize); if (combuf == NULL) err(1, NULL); labbuf = (char *) malloc(bufsize); if (labbuf == NULL) err(1, NULL); codebuf = (char *) malloc(bufsize); if (codebuf == NULL) err(1, NULL); tokenbuf = (char *) malloc(bufsize); if (tokenbuf == NULL) err(1, NULL); alloc_typenames(); l_com = combuf + bufsize - 5; l_lab = labbuf + bufsize - 5; l_code = codebuf + bufsize - 5; l_token = tokenbuf + bufsize - 5; combuf[0] = codebuf[0] = labbuf[0] = ' '; /* set up code, label, and * comment buffers */ combuf[1] = codebuf[1] = labbuf[1] = '\0'; opt.else_if = 1; /* Default else-if special processing to on */ s_lab = e_lab = labbuf + 1; s_code = e_code = codebuf + 1; s_com = e_com = combuf + 1; s_token = e_token = tokenbuf + 1; in_buffer = (char *) malloc(10); if (in_buffer == NULL) err(1, NULL); in_buffer_limit = in_buffer + 8; buf_ptr = buf_end = in_buffer; line_no = 1; had_eof = ps.in_decl = ps.decl_on_line = break_comma = false; sp_sw = force_nl = false; ps.in_or_st = false; ps.bl_line = true; dec_ind = 0; di_stack[ps.dec_nest = 0] = 0; ps.want_blank = ps.in_stmt = ps.ind_stmt = false; scase = ps.pcase = false; squest = 0; sc_end = NULL; bp_save = NULL; be_save = NULL; output = NULL; tabs_to_var = 0; envval = getenv("SIMPLE_BACKUP_SUFFIX"); if (envval) simple_backup_suffix = envval; /*--------------------------------------------------*\ | COMMAND LINE SCAN | \*--------------------------------------------------*/ #ifdef undef max_col = 78; /* -l78 */ lineup_to_parens = 1; /* -lp */ lineup_to_parens_always = 0; /* -nlpl */ ps.ljust_decl = 0; /* -ndj */ ps.com_ind = 33; /* -c33 */ star_comment_cont = 1; /* -sc */ ps.ind_size = 8; /* -i8 */ verbose = 0; ps.decl_indent = 16; /* -di16 */ ps.local_decl_indent = -1; /* if this is not set to some nonnegative value * by an arg, we will set this equal to * ps.decl_ind */ ps.indent_parameters = 1; /* -ip */ ps.decl_com_ind = 0; /* if this is not set to some positive value * by an arg, we will set this equal to * ps.com_ind */ btype_2 = 1; /* -br */ cuddle_else = 1; /* -ce */ ps.unindent_displace = 0; /* -d0 */ ps.case_indent = 0; /* -cli0 */ format_block_comments = 1; /* -fcb */ format_col1_comments = 1; /* -fc1 */ procnames_start_line = 1; /* -psl */ proc_calls_space = 0; /* -npcs */ comment_delimiter_on_blankline = 1; /* -cdb */ ps.leave_comma = 1; /* -nbc */ #endif for (i = 1; i < argc; ++i) if (strcmp(argv[i], "-npro") == 0) break; else if (argv[i][0] == '-' && argv[i][1] == 'P' && argv[i][2] != '\0') profile_name = argv[i]; /* non-empty -P (set profile) */ set_defaults(); if (i >= argc) set_profile(profile_name); for (i = 1; i < argc; ++i) { /* * look thru args (if any) for changes to defaults */ if (argv[i][0] != '-') {/* no flag on parameter */ if (input == NULL) { /* we must have the input file */ in_name = argv[i]; /* remember name of input file */ input = fopen(in_name, "r"); if (input == NULL) /* check for open error */ err(1, "%s", in_name); continue; } else if (output == NULL) { /* we have the output file */ out_name = argv[i]; /* remember name of output file */ if (strcmp(in_name, out_name) == 0) { /* attempt to overwrite * the file */ errx(1, "input and output files must be different"); } output = fopen(out_name, "w"); if (output == NULL) /* check for create error */ err(1, "%s", out_name); continue; } errx(1, "unknown parameter: %s", argv[i]); } else set_option(argv[i]); } /* end of for */ if (input == NULL) input = stdin; if (output == NULL) { if (input == stdin) output = stdout; else { out_name = in_name; bakcopy(); } } /* Restrict input/output descriptors and enter Capsicum sandbox. */ cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE); if (cap_rights_limit(fileno(output), &rights) < 0 && errno != ENOSYS) err(EXIT_FAILURE, "unable to limit rights for %s", out_name); cap_rights_init(&rights, CAP_FSTAT, CAP_READ); if (cap_rights_limit(fileno(input), &rights) < 0 && errno != ENOSYS) err(EXIT_FAILURE, "unable to limit rights for %s", in_name); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(EXIT_FAILURE, "unable to enter capability mode"); if (opt.com_ind <= 1) opt.com_ind = 2; /* don't put normal comments before column 2 */ if (opt.block_comment_max_col <= 0) opt.block_comment_max_col = opt.max_col; if (opt.local_decl_indent < 0) /* if not specified by user, set this */ opt.local_decl_indent = opt.decl_indent; if (opt.decl_com_ind <= 0) /* if not specified by user, set this */ opt.decl_com_ind = opt.ljust_decl ? (opt.com_ind <= 10 ? 2 : opt.com_ind - 8) : opt.com_ind; if (opt.continuation_indent == 0) opt.continuation_indent = opt.ind_size; fill_buffer(); /* get first batch of stuff into input buffer */ parse(semicolon); { char *p = buf_ptr; int col = 1; while (1) { if (*p == ' ') col++; else if (*p == '\t') col = opt.tabsize * (1 + (col - 1) / opt.tabsize) + 1; else break; p++; } if (col > opt.ind_size) ps.ind_level = ps.i_l_follow = col / opt.ind_size; } /* * START OF MAIN LOOP */ while (1) { /* this is the main loop. it will go until we * reach eof */ int comment_buffered = false; type_code = lexi(&ps); /* lexi reads one token. The actual * characters read are stored in "token". lexi * returns a code indicating the type of token */ /* * The following code moves newlines and comments following an if (), * while (), else, etc. up to the start of the following stmt to * a buffer. This allows proper handling of both kinds of brace * placement (-br, -bl) and cuddling "else" (-ce). */ while (ps.search_brace) { switch (type_code) { case newline: if (sc_end == NULL) { save_com = sc_buf; save_com[0] = save_com[1] = ' '; sc_end = &save_com[2]; } *sc_end++ = '\n'; /* * We may have inherited a force_nl == true from the previous * token (like a semicolon). But once we know that a newline * has been scanned in this loop, force_nl should be false. * * However, the force_nl == true must be preserved if newline * is never scanned in this loop, so this assignment cannot be * done earlier. */ force_nl = false; case form_feed: break; case comment: if (sc_end == NULL) { /* * Copy everything from the start of the line, because * pr_comment() will use that to calculate original * indentation of a boxed comment. */ memcpy(sc_buf, in_buffer, buf_ptr - in_buffer - 4); save_com = sc_buf + (buf_ptr - in_buffer - 4); save_com[0] = save_com[1] = ' '; sc_end = &save_com[2]; } comment_buffered = true; *sc_end++ = '/'; /* copy in start of comment */ *sc_end++ = '*'; for (;;) { /* loop until we get to the end of the comment */ *sc_end = *buf_ptr++; if (buf_ptr >= buf_end) fill_buffer(); if (*sc_end++ == '*' && *buf_ptr == '/') break; /* we are at end of comment */ if (sc_end >= &save_com[sc_size]) { /* check for temp buffer * overflow */ diag2(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever"); fflush(output); exit(1); } } *sc_end++ = '/'; /* add ending slash */ if (++buf_ptr >= buf_end) /* get past / in buffer */ fill_buffer(); break; case lbrace: /* * Put KNF-style lbraces before the buffered up tokens and * jump out of this loop in order to avoid copying the token * again under the default case of the switch below. */ if (sc_end != NULL && opt.btype_2) { save_com[0] = '{'; /* * Originally the lbrace may have been alone on its own * line, but it will be moved into "the else's line", so * if there was a newline resulting from the "{" before, * it must be scanned now and ignored. */ while (isspace((unsigned char)*buf_ptr)) { if (++buf_ptr >= buf_end) fill_buffer(); if (*buf_ptr == '\n') break; } goto sw_buffer; } /* FALLTHROUGH */ default: /* it is the start of a normal statement */ { int remove_newlines; remove_newlines = /* "} else" */ (type_code == sp_nparen && *token == 'e' && e_code != s_code && e_code[-1] == '}') /* "else if" */ || (type_code == sp_paren && *token == 'i' && last_else && opt.else_if); if (remove_newlines) force_nl = false; if (sc_end == NULL) { /* ignore buffering if * comment wasn't saved up */ ps.search_brace = false; goto check_type; } while (sc_end > save_com && isblank((unsigned char)sc_end[-1])) { sc_end--; } if (opt.swallow_optional_blanklines || (!comment_buffered && remove_newlines)) { force_nl = !remove_newlines; while (sc_end > save_com && sc_end[-1] == '\n') { sc_end--; } } if (force_nl) { /* if we should insert a nl here, put * it into the buffer */ force_nl = false; --line_no; /* this will be re-increased when the * newline is read from the buffer */ *sc_end++ = '\n'; *sc_end++ = ' '; if (opt.verbose) /* print error msg if the line was * not already broken */ diag2(0, "Line broken"); } for (t_ptr = token; *t_ptr; ++t_ptr) *sc_end++ = *t_ptr; sw_buffer: ps.search_brace = false; /* stop looking for start of * stmt */ bp_save = buf_ptr; /* save current input buffer */ be_save = buf_end; buf_ptr = save_com; /* fix so that subsequent calls to * lexi will take tokens out of * save_com */ *sc_end++ = ' ';/* add trailing blank, just in case */ buf_end = sc_end; sc_end = NULL; break; } } /* end of switch */ /* * We must make this check, just in case there was an unexpected * EOF. */ if (type_code != 0) { /* * The only intended purpose of calling lexi() below is to * categorize the next token in order to decide whether to * continue buffering forthcoming tokens. Once the buffering * is over, lexi() will be called again elsewhere on all of * the tokens - this time for normal processing. * * Calling it for this purpose is a bug, because lexi() also * changes the parser state and discards leading whitespace, * which is needed mostly for comment-related considerations. * * Work around the former problem by giving lexi() a copy of * the current parser state and discard it if the call turned * out to be just a look ahead. * * Work around the latter problem by copying all whitespace * characters into the buffer so that the later lexi() call * will read them. */ if (sc_end != NULL) { while (*buf_ptr == ' ' || *buf_ptr == '\t') { *sc_end++ = *buf_ptr++; if (sc_end >= &save_com[sc_size]) { errx(1, "input too long"); } } if (buf_ptr >= buf_end) { fill_buffer(); } } transient_state = ps; type_code = lexi(&transient_state); /* read another token */ if (type_code != newline && type_code != form_feed && type_code != comment && !transient_state.search_brace) { ps = transient_state; } } } /* end of while (search_brace) */ last_else = 0; check_type: if (type_code == 0) { /* we got eof */ if (s_lab != e_lab || s_code != e_code || s_com != e_com) /* must dump end of line */ dump_line(); if (ps.tos > 1) /* check for balanced braces */ diag2(1, "Stuff missing from end of file"); if (opt.verbose) { printf("There were %d output lines and %d comments\n", ps.out_lines, ps.out_coms); printf("(Lines with comments)/(Lines with code): %6.3f\n", (1.0 * ps.com_lines) / code_lines); } fflush(output); exit(found_err); } if ( (type_code != comment) && (type_code != newline) && (type_code != preesc) && (type_code != form_feed)) { if (force_nl && (type_code != semicolon) && (type_code != lbrace || !opt.btype_2)) { /* we should force a broken line here */ if (opt.verbose) diag2(0, "Line broken"); dump_line(); ps.want_blank = false; /* dont insert blank at line start */ force_nl = false; } ps.in_stmt = true; /* turn on flag which causes an extra level of * indentation. this is turned off by a ; or * '}' */ if (s_com != e_com) { /* the turkey has embedded a comment * in a line. fix it */ int len = e_com - s_com; CHECK_SIZE_CODE(len + 3); *e_code++ = ' '; memcpy(e_code, s_com, len); e_code += len; *e_code++ = ' '; *e_code = '\0'; /* null terminate code sect */ ps.want_blank = false; e_com = s_com; } } else if (type_code != comment) /* preserve force_nl thru a comment */ force_nl = false; /* cancel forced newline after newline, form * feed, etc */ /*-----------------------------------------------------*\ | do switch on type of token scanned | \*-----------------------------------------------------*/ CHECK_SIZE_CODE(3); /* maximum number of increments of e_code * before the next CHECK_SIZE_CODE or * dump_line() is 2. After that there's the * final increment for the null character. */ switch (type_code) { /* now, decide what to do with the token */ case form_feed: /* found a form feed in line */ ps.use_ff = true; /* a form feed is treated much like a newline */ dump_line(); ps.want_blank = false; break; case newline: if (ps.last_token != comma || ps.p_l_follow > 0 || !opt.leave_comma || ps.block_init || !break_comma || s_com != e_com) { dump_line(); ps.want_blank = false; } ++line_no; /* keep track of input line number */ break; case lparen: /* got a '(' or '[' */ /* count parens to make Healy happy */ if (++ps.p_l_follow == nitems(ps.paren_indents)) { diag3(0, "Reached internal limit of %d unclosed parens", nitems(ps.paren_indents)); ps.p_l_follow--; } if (*token == '[') /* not a function pointer declaration or a function call */; else if (ps.in_decl && !ps.block_init && !ps.dumped_decl_indent && ps.procname[0] == '\0' && ps.paren_level == 0) { /* function pointer declarations */ indent_declaration(dec_ind, tabs_to_var); ps.dumped_decl_indent = true; } else if (ps.want_blank && ((ps.last_token != ident && ps.last_token != funcname) || opt.proc_calls_space || /* offsetof (1) is never allowed a space; sizeof (2) gets * one iff -bs; all other keywords (>2) always get a space * before lparen */ ps.keyword + opt.Bill_Shannon > 2)) *e_code++ = ' '; ps.want_blank = false; *e_code++ = token[0]; ps.paren_indents[ps.p_l_follow - 1] = count_spaces_until(1, s_code, e_code) - 1; if (sp_sw && ps.p_l_follow == 1 && opt.extra_expression_indent && ps.paren_indents[0] < 2 * opt.ind_size) ps.paren_indents[0] = 2 * opt.ind_size; if (ps.in_or_st && *token == '(' && ps.tos <= 2) { /* * this is a kluge to make sure that declarations will be * aligned right if proc decl has an explicit type on it, i.e. * "int a(x) {..." */ parse(semicolon); /* I said this was a kluge... */ ps.in_or_st = false; /* turn off flag for structure decl or * initialization */ } /* parenthesized type following sizeof or offsetof is not a cast */ if (ps.keyword == 1 || ps.keyword == 2) ps.not_cast_mask |= 1 << ps.p_l_follow; break; case rparen: /* got a ')' or ']' */ if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.not_cast_mask) { ps.last_u_d = true; ps.cast_mask &= (1 << ps.p_l_follow) - 1; ps.want_blank = opt.space_after_cast; } else ps.want_blank = true; ps.not_cast_mask &= (1 << ps.p_l_follow) - 1; if (--ps.p_l_follow < 0) { ps.p_l_follow = 0; diag3(0, "Extra %c", *token); } if (e_code == s_code) /* if the paren starts the line */ ps.paren_level = ps.p_l_follow; /* then indent it */ *e_code++ = token[0]; if (sp_sw && (ps.p_l_follow == 0)) { /* check for end of if * (...), or some such */ sp_sw = false; force_nl = true;/* must force newline after if */ ps.last_u_d = true; /* inform lexi that a following * operator is unary */ ps.in_stmt = false; /* dont use stmt continuation * indentation */ parse(hd_type); /* let parser worry about if, or whatever */ } ps.search_brace = opt.btype_2; /* this should ensure that * constructs such as main(){...} * and int[]{...} have their braces * put in the right place */ break; case unary_op: /* this could be any unary operation */ if (!ps.dumped_decl_indent && ps.in_decl && !ps.block_init && ps.procname[0] == '\0' && ps.paren_level == 0) { /* pointer declarations */ /* * if this is a unary op in a declaration, we should indent * this token */ for (i = 0; token[i]; ++i) /* find length of token */; indent_declaration(dec_ind - i, tabs_to_var); ps.dumped_decl_indent = true; } else if (ps.want_blank) *e_code++ = ' '; { int len = e_token - s_token; CHECK_SIZE_CODE(len); memcpy(e_code, token, len); e_code += len; } ps.want_blank = false; break; case binary_op: /* any binary operation */ { int len = e_token - s_token; CHECK_SIZE_CODE(len + 1); if (ps.want_blank) *e_code++ = ' '; memcpy(e_code, token, len); e_code += len; } ps.want_blank = true; break; case postop: /* got a trailing ++ or -- */ *e_code++ = token[0]; *e_code++ = token[1]; ps.want_blank = true; break; case question: /* got a ? */ squest++; /* this will be used when a later colon * appears so we can distinguish the * ?: construct */ if (ps.want_blank) *e_code++ = ' '; *e_code++ = '?'; ps.want_blank = true; break; case casestmt: /* got word 'case' or 'default' */ scase = true; /* so we can process the later colon properly */ goto copy_id; case colon: /* got a ':' */ if (squest > 0) { /* it is part of the ?: construct */ --squest; if (ps.want_blank) *e_code++ = ' '; *e_code++ = ':'; ps.want_blank = true; break; } if (ps.in_or_st) { *e_code++ = ':'; ps.want_blank = false; break; } ps.in_stmt = false; /* seeing a label does not imply we are in a * stmt */ /* * turn everything so far into a label */ { int len = e_code - s_code; CHECK_SIZE_LAB(len + 3); memcpy(e_lab, s_code, len); e_lab += len; *e_lab++ = ':'; *e_lab = '\0'; e_code = s_code; } force_nl = ps.pcase = scase; /* ps.pcase will be used by * dump_line to decide how to * indent the label. force_nl * will force a case n: to be * on a line by itself */ scase = false; ps.want_blank = false; break; case semicolon: /* got a ';' */ if (ps.dec_nest == 0) ps.in_or_st = false;/* we are not in an initialization or * structure declaration */ scase = false; /* these will only need resetting in an error */ squest = 0; if (ps.last_token == rparen) ps.in_parameter_declaration = 0; ps.cast_mask = 0; ps.not_cast_mask = 0; ps.block_init = 0; ps.block_init_level = 0; ps.just_saw_decl--; if (ps.in_decl && s_code == e_code && !ps.block_init && !ps.dumped_decl_indent && ps.paren_level == 0) { /* indent stray semicolons in declarations */ indent_declaration(dec_ind - 1, tabs_to_var); ps.dumped_decl_indent = true; } ps.in_decl = (ps.dec_nest > 0); /* if we were in a first level * structure declaration, we * arent any more */ if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) { /* * This should be true iff there were unbalanced parens in the * stmt. It is a bit complicated, because the semicolon might * be in a for stmt */ diag2(1, "Unbalanced parens"); ps.p_l_follow = 0; if (sp_sw) { /* this is a check for an if, while, etc. with * unbalanced parens */ sp_sw = false; parse(hd_type); /* dont lose the if, or whatever */ } } *e_code++ = ';'; ps.want_blank = true; ps.in_stmt = (ps.p_l_follow > 0); /* we are no longer in the * middle of a stmt */ if (!sp_sw) { /* if not if for (;;) */ parse(semicolon); /* let parser know about end of stmt */ force_nl = true;/* force newline after an end of stmt */ } break; case lbrace: /* got a '{' */ ps.in_stmt = false; /* dont indent the {} */ if (!ps.block_init) force_nl = true;/* force other stuff on same line as '{' onto * new line */ else if (ps.block_init_level <= 0) ps.block_init_level = 1; else ps.block_init_level++; if (s_code != e_code && !ps.block_init) { if (!opt.btype_2) { dump_line(); ps.want_blank = false; } else if (ps.in_parameter_declaration && !ps.in_or_st) { ps.i_l_follow = 0; if (opt.function_brace_split) { /* dump the line prior * to the brace ... */ dump_line(); ps.want_blank = false; } else /* add a space between the decl and brace */ ps.want_blank = true; } } if (ps.in_parameter_declaration) prefix_blankline_requested = 0; if (ps.p_l_follow > 0) { /* check for preceding unbalanced * parens */ diag2(1, "Unbalanced parens"); ps.p_l_follow = 0; if (sp_sw) { /* check for unclosed if, for, etc. */ sp_sw = false; parse(hd_type); ps.ind_level = ps.i_l_follow; } } if (s_code == e_code) ps.ind_stmt = false; /* dont put extra indentation on line * with '{' */ if (ps.in_decl && ps.in_or_st) { /* this is either a structure * declaration or an init */ di_stack[ps.dec_nest] = dec_ind; if (++ps.dec_nest == nitems(di_stack)) { diag3(0, "Reached internal limit of %d struct levels", nitems(di_stack)); ps.dec_nest--; } /* ? dec_ind = 0; */ } else { ps.decl_on_line = false; /* we can't be in the middle of * a declaration, so don't do * special indentation of * comments */ if (opt.blanklines_after_declarations_at_proctop && ps.in_parameter_declaration) postfix_blankline_requested = 1; ps.in_parameter_declaration = 0; ps.in_decl = false; } dec_ind = 0; parse(lbrace); /* let parser know about this */ if (ps.want_blank) /* put a blank before '{' if '{' is not at * start of line */ *e_code++ = ' '; ps.want_blank = false; *e_code++ = '{'; ps.just_saw_decl = 0; break; case rbrace: /* got a '}' */ if (ps.p_stack[ps.tos] == decl && !ps.block_init) /* semicolons can be * omitted in * declarations */ parse(semicolon); if (ps.p_l_follow) {/* check for unclosed if, for, else. */ diag2(1, "Unbalanced parens"); ps.p_l_follow = 0; sp_sw = false; } ps.just_saw_decl = 0; ps.block_init_level--; if (s_code != e_code && !ps.block_init) { /* '}' must be first on * line */ if (opt.verbose) diag2(0, "Line broken"); dump_line(); } *e_code++ = '}'; ps.want_blank = true; ps.in_stmt = ps.ind_stmt = false; if (ps.dec_nest > 0) { /* we are in multi-level structure * declaration */ dec_ind = di_stack[--ps.dec_nest]; if (ps.dec_nest == 0 && !ps.in_parameter_declaration) ps.just_saw_decl = 2; ps.in_decl = true; } prefix_blankline_requested = 0; parse(rbrace); /* let parser know about this */ ps.search_brace = opt.cuddle_else && ps.p_stack[ps.tos] == ifhead && ps.il[ps.tos] >= ps.ind_level; if (ps.tos <= 1 && opt.blanklines_after_procs && ps.dec_nest <= 0) postfix_blankline_requested = 1; break; case swstmt: /* got keyword "switch" */ sp_sw = true; hd_type = swstmt; /* keep this for when we have seen the * expression */ goto copy_id; /* go move the token into buffer */ case sp_paren: /* token is if, while, for */ sp_sw = true; /* the interesting stuff is done after the * expression is scanned */ hd_type = (*token == 'i' ? ifstmt : (*token == 'w' ? whilestmt : forstmt)); /* * remember the type of header for later use by parser */ goto copy_id; /* copy the token into line */ case sp_nparen: /* got else, do */ ps.in_stmt = false; if (*token == 'e') { if (e_code != s_code && (!opt.cuddle_else || e_code[-1] != '}')) { if (opt.verbose) diag2(0, "Line broken"); dump_line();/* make sure this starts a line */ ps.want_blank = false; } force_nl = true;/* also, following stuff must go onto new line */ last_else = 1; parse(elselit); } else { if (e_code != s_code) { /* make sure this starts a line */ if (opt.verbose) diag2(0, "Line broken"); dump_line(); ps.want_blank = false; } force_nl = true;/* also, following stuff must go onto new line */ last_else = 0; parse(dolit); } goto copy_id; /* move the token into line */ case type_def: case storage: prefix_blankline_requested = 0; goto copy_id; case structure: if (ps.p_l_follow > 0) goto copy_id; case decl: /* we have a declaration type (int, etc.) */ parse(decl); /* let parser worry about indentation */ if (ps.last_token == rparen && ps.tos <= 1) { if (s_code != e_code) { dump_line(); ps.want_blank = 0; } } if (ps.in_parameter_declaration && opt.indent_parameters && ps.dec_nest == 0) { ps.ind_level = ps.i_l_follow = 1; ps.ind_stmt = 0; } ps.in_or_st = true; /* this might be a structure or initialization * declaration */ ps.in_decl = ps.decl_on_line = ps.last_token != type_def; if ( /* !ps.in_or_st && */ ps.dec_nest <= 0) ps.just_saw_decl = 2; prefix_blankline_requested = 0; for (i = 0; token[i++];); /* get length of token */ if (ps.ind_level == 0 || ps.dec_nest > 0) { /* global variable or struct member in local variable */ dec_ind = opt.decl_indent > 0 ? opt.decl_indent : i; tabs_to_var = (opt.use_tabs ? opt.decl_indent > 0 : 0); } else { /* local variable */ dec_ind = opt.local_decl_indent > 0 ? opt.local_decl_indent : i; tabs_to_var = (opt.use_tabs ? opt.local_decl_indent > 0 : 0); } goto copy_id; case funcname: case ident: /* got an identifier or constant */ if (ps.in_decl) { if (type_code == funcname) { ps.in_decl = false; if (opt.procnames_start_line && s_code != e_code) { *e_code = '\0'; dump_line(); } else if (ps.want_blank) { *e_code++ = ' '; } ps.want_blank = false; } else if (!ps.block_init && !ps.dumped_decl_indent && ps.paren_level == 0) { /* if we are in a declaration, we * must indent identifier */ indent_declaration(dec_ind, tabs_to_var); ps.dumped_decl_indent = true; ps.want_blank = false; } } else if (sp_sw && ps.p_l_follow == 0) { sp_sw = false; force_nl = true; ps.last_u_d = true; ps.in_stmt = false; parse(hd_type); } copy_id: { int len = e_token - s_token; CHECK_SIZE_CODE(len + 1); if (ps.want_blank) *e_code++ = ' '; memcpy(e_code, s_token, len); e_code += len; } if (type_code != funcname) ps.want_blank = true; break; case strpfx: { int len = e_token - s_token; CHECK_SIZE_CODE(len + 1); if (ps.want_blank) *e_code++ = ' '; memcpy(e_code, token, len); e_code += len; } ps.want_blank = false; break; case period: /* treat a period kind of like a binary * operation */ *e_code++ = '.'; /* move the period into line */ ps.want_blank = false; /* dont put a blank after a period */ break; case comma: ps.want_blank = (s_code != e_code); /* only put blank after comma * if comma does not start the * line */ if (ps.in_decl && ps.procname[0] == '\0' && !ps.block_init && !ps.dumped_decl_indent && ps.paren_level == 0) { /* indent leading commas and not the actual identifiers */ indent_declaration(dec_ind - 1, tabs_to_var); ps.dumped_decl_indent = true; } *e_code++ = ','; if (ps.p_l_follow == 0) { if (ps.block_init_level <= 0) ps.block_init = 0; if (break_comma && (!opt.leave_comma || count_spaces_until(compute_code_target(), s_code, e_code) > opt.max_col - opt.tabsize)) force_nl = true; } break; case preesc: /* got the character '#' */ if ((s_com != e_com) || (s_lab != e_lab) || (s_code != e_code)) dump_line(); CHECK_SIZE_LAB(1); *e_lab++ = '#'; /* move whole line to 'label' buffer */ { int in_comment = 0; int com_start = 0; char quote = 0; int com_end = 0; while (*buf_ptr == ' ' || *buf_ptr == '\t') { buf_ptr++; if (buf_ptr >= buf_end) fill_buffer(); } while (*buf_ptr != '\n' || (in_comment && !had_eof)) { CHECK_SIZE_LAB(2); *e_lab = *buf_ptr++; if (buf_ptr >= buf_end) fill_buffer(); switch (*e_lab++) { case BACKSLASH: if (!in_comment) { *e_lab++ = *buf_ptr++; if (buf_ptr >= buf_end) fill_buffer(); } break; case '/': if (*buf_ptr == '*' && !in_comment && !quote) { in_comment = 1; *e_lab++ = *buf_ptr++; com_start = e_lab - s_lab - 2; } break; case '"': if (quote == '"') quote = 0; break; case '\'': if (quote == '\'') quote = 0; break; case '*': if (*buf_ptr == '/' && in_comment) { in_comment = 0; *e_lab++ = *buf_ptr++; com_end = e_lab - s_lab; } break; } } while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t')) e_lab--; if (e_lab - s_lab == com_end && bp_save == NULL) { /* comment on preprocessor line */ if (sc_end == NULL) { /* if this is the first comment, * we must set up the buffer */ save_com = sc_buf; sc_end = &save_com[0]; } else { *sc_end++ = '\n'; /* add newline between * comments */ *sc_end++ = ' '; --line_no; } if (sc_end - save_com + com_end - com_start > sc_size) errx(1, "input too long"); memmove(sc_end, s_lab + com_start, com_end - com_start); sc_end += com_end - com_start; e_lab = s_lab + com_start; while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t')) e_lab--; bp_save = buf_ptr; /* save current input buffer */ be_save = buf_end; buf_ptr = save_com; /* fix so that subsequent calls to * lexi will take tokens out of * save_com */ *sc_end++ = ' '; /* add trailing blank, just in case */ buf_end = sc_end; sc_end = NULL; } CHECK_SIZE_LAB(1); *e_lab = '\0'; /* null terminate line */ ps.pcase = false; } if (strncmp(s_lab, "#if", 3) == 0) { /* also ifdef, ifndef */ if ((size_t)ifdef_level < nitems(state_stack)) { match_state[ifdef_level].tos = -1; state_stack[ifdef_level++] = ps; } else diag2(1, "#if stack overflow"); } else if (strncmp(s_lab, "#el", 3) == 0) { /* else, elif */ if (ifdef_level <= 0) diag2(1, s_lab[3] == 'i' ? "Unmatched #elif" : "Unmatched #else"); else { match_state[ifdef_level - 1] = ps; ps = state_stack[ifdef_level - 1]; } } else if (strncmp(s_lab, "#endif", 6) == 0) { if (ifdef_level <= 0) diag2(1, "Unmatched #endif"); else ifdef_level--; } else { struct directives { int size; const char *string; } recognized[] = { {7, "include"}, {6, "define"}, {5, "undef"}, {4, "line"}, {5, "error"}, {6, "pragma"} }; int d = nitems(recognized); while (--d >= 0) if (strncmp(s_lab + 1, recognized[d].string, recognized[d].size) == 0) break; if (d < 0) { diag2(1, "Unrecognized cpp directive"); break; } } if (opt.blanklines_around_conditional_compilation) { postfix_blankline_requested++; n_real_blanklines = 0; } else { postfix_blankline_requested = 0; prefix_blankline_requested = 0; } break; /* subsequent processing of the newline * character will cause the line to be printed */ case comment: /* we have gotten a / followed by * this is a biggie */ pr_comment(); break; } /* end of big switch stmt */ *e_code = '\0'; /* make sure code section is null terminated */ if (type_code != comment && type_code != newline && type_code != preesc) ps.last_token = type_code; } /* end of main while (1) loop */ } /* * copy input file to backup file if in_name is /blah/blah/blah/file, then * backup file will be ".Bfile" then make the backup file the input and * original input file the output */ static void bakcopy(void) { int n, bakchn; char buff[8 * 1024]; const char *p; /* construct file name .Bfile */ for (p = in_name; *p; p++); /* skip to end of string */ while (p > in_name && *p != '/') /* find last '/' */ p--; if (*p == '/') p++; sprintf(bakfile, "%s%s", p, simple_backup_suffix); /* copy in_name to backup file */ bakchn = creat(bakfile, 0600); if (bakchn < 0) err(1, "%s", bakfile); while ((n = read(fileno(input), buff, sizeof(buff))) > 0) if (write(bakchn, buff, n) != n) err(1, "%s", bakfile); if (n < 0) err(1, "%s", in_name); close(bakchn); fclose(input); /* re-open backup file as the input file */ input = fopen(bakfile, "r"); if (input == NULL) err(1, "%s", bakfile); /* now the original input file will be the output */ output = fopen(in_name, "w"); if (output == NULL) { unlink(bakfile); err(1, "%s", in_name); } } static void indent_declaration(int cur_dec_ind, int tabs_to_var) { int pos = e_code - s_code; char *startpos = e_code; /* * get the tab math right for indentations that are not multiples of tabsize */ if ((ps.ind_level * opt.ind_size) % opt.tabsize != 0) { pos += (ps.ind_level * opt.ind_size) % opt.tabsize; cur_dec_ind += (ps.ind_level * opt.ind_size) % opt.tabsize; } if (tabs_to_var) { int tpos; CHECK_SIZE_CODE(cur_dec_ind / opt.tabsize); while ((tpos = opt.tabsize * (1 + pos / opt.tabsize)) <= cur_dec_ind) { *e_code++ = '\t'; pos = tpos; } } CHECK_SIZE_CODE(cur_dec_ind - pos + 1); while (pos < cur_dec_ind) { *e_code++ = ' '; pos++; } if (e_code == startpos && ps.want_blank) { *e_code++ = ' '; ps.want_blank = false; } } Index: head/usr.bin/jot/jot.c =================================================================== --- head/usr.bin/jot/jot.c (revision 335394) +++ head/usr.bin/jot/jot.c (revision 335395) @@ -1,514 +1,514 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93"; #endif #endif #include __FBSDID("$FreeBSD$"); /* * jot - print sequential or random data * * Author: John Kunze, Office of Comp. Affairs, UCB */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* Defaults */ #define REPS_DEF 100 #define BEGIN_DEF 1 #define ENDER_DEF 100 #define STEP_DEF 1 /* Flags of options that have been set */ #define HAVE_STEP 1 #define HAVE_ENDER 2 #define HAVE_BEGIN 4 #define HAVE_REPS 8 #define is_default(s) (*(s) == 0 || strcmp((s), "-") == 0) static bool boring; static int prec = -1; static bool longdata; static bool intdata; static bool chardata; static bool nosign; static const char *sepstring = "\n"; static char format[BUFSIZ]; static void getformat(void); static int getprec(const char *); static int putdata(double, bool); static void usage(void); int main(int argc, char **argv) { cap_rights_t rights; bool have_format = false; bool infinity = false; bool nofinalnl = false; bool randomize = false; bool use_random = false; int ch; int mask = 0; int n = 0; double begin = BEGIN_DEF; double divisor; double ender = ENDER_DEF; double s = STEP_DEF; double x, y; long i; long reps = REPS_DEF; if (caph_limit_stdio() < 0) err(1, "unable to limit rights for stdio"); cap_rights_init(&rights); if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) err(1, "unable to limit rights for stdin"); /* * Cache NLS data, for strerror, for err(3), before entering capability * mode. */ caph_cache_catpages(); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "unable to enter capability mode"); while ((ch = getopt(argc, argv, "b:cnp:rs:w:")) != -1) switch (ch) { case 'b': boring = true; /* FALLTHROUGH */ case 'w': if (strlcpy(format, optarg, sizeof(format)) >= sizeof(format)) errx(1, "-%c word too long", ch); have_format = true; break; case 'c': chardata = true; break; case 'n': nofinalnl = true; break; case 'p': prec = atoi(optarg); if (prec < 0) errx(1, "bad precision value"); have_format = true; break; case 'r': randomize = true; break; case 's': sepstring = optarg; break; default: usage(); } argc -= optind; argv += optind; switch (argc) { /* examine args right to left, falling thru cases */ case 4: if (!is_default(argv[3])) { if (!sscanf(argv[3], "%lf", &s)) errx(1, "bad s value: %s", argv[3]); mask |= HAVE_STEP; if (randomize) use_random = true; } /* FALLTHROUGH */ case 3: if (!is_default(argv[2])) { if (!sscanf(argv[2], "%lf", &ender)) ender = argv[2][strlen(argv[2])-1]; mask |= HAVE_ENDER; if (prec < 0) n = getprec(argv[2]); } /* FALLTHROUGH */ case 2: if (!is_default(argv[1])) { if (!sscanf(argv[1], "%lf", &begin)) begin = argv[1][strlen(argv[1])-1]; mask |= HAVE_BEGIN; if (prec < 0) prec = getprec(argv[1]); if (n > prec) /* maximum precision */ prec = n; } /* FALLTHROUGH */ case 1: if (!is_default(argv[0])) { if (!sscanf(argv[0], "%ld", &reps)) errx(1, "bad reps value: %s", argv[0]); mask |= HAVE_REPS; } break; case 0: usage(); default: errx(1, "too many arguments. What do you mean by %s?", argv[4]); } getformat(); if (prec == -1) prec = 0; while (mask) /* 4 bit mask has 1's where last 4 args were given */ switch (mask) { /* fill in the 0's by default or computation */ case HAVE_STEP: case HAVE_ENDER: case HAVE_ENDER | HAVE_STEP: case HAVE_BEGIN: case HAVE_BEGIN | HAVE_STEP: reps = REPS_DEF; mask |= HAVE_REPS; break; case HAVE_BEGIN | HAVE_ENDER: s = ender > begin ? 1 : -1; mask |= HAVE_STEP; break; case HAVE_BEGIN | HAVE_ENDER | HAVE_STEP: if (randomize) reps = REPS_DEF; else if (s == 0.0) reps = 0; else reps = (ender - begin + s) / s; if (reps <= 0) errx(1, "impossible stepsize"); mask = 0; break; case HAVE_REPS: case HAVE_REPS | HAVE_STEP: begin = BEGIN_DEF; mask |= HAVE_BEGIN; break; case HAVE_REPS | HAVE_ENDER: s = STEP_DEF; mask = HAVE_REPS | HAVE_ENDER | HAVE_STEP; break; case HAVE_REPS | HAVE_ENDER | HAVE_STEP: if (randomize) begin = BEGIN_DEF; else if (reps == 0) errx(1, "must specify begin if reps == 0"); begin = ender - reps * s + s; mask = 0; break; case HAVE_REPS | HAVE_BEGIN: s = STEP_DEF; mask = HAVE_REPS | HAVE_BEGIN | HAVE_STEP; break; case HAVE_REPS | HAVE_BEGIN | HAVE_STEP: if (randomize) ender = ENDER_DEF; else ender = begin + reps * s - s; mask = 0; break; case HAVE_REPS | HAVE_BEGIN | HAVE_ENDER: if (reps == 0) errx(1, "infinite sequences cannot be bounded"); else if (reps == 1) s = 0.0; else s = (ender - begin) / (reps - 1); mask = 0; break; case HAVE_REPS | HAVE_BEGIN | HAVE_ENDER | HAVE_STEP: /* if reps given and implied, */ if (!randomize && s != 0.0) { long t = (ender - begin + s) / s; if (t <= 0) errx(1, "impossible stepsize"); if (t < reps) /* take lesser */ reps = t; } mask = 0; break; default: errx(1, "bad mask"); } if (reps == 0) infinity = true; if (randomize) { if (use_random) { srandom((unsigned long)s); divisor = (double)INT32_MAX + 1; } else divisor = (double)UINT32_MAX + 1; /* * Attempt to DWIM when the user has specified an * integer range within that of the random number * generator: distribute the numbers equally in * the range [begin .. ender]. Jot's default %.0f * format would make the appearance of the first and * last specified value half as likely as the rest. */ if (!have_format && prec == 0 && begin >= 0 && begin < divisor && ender >= 0 && ender < divisor) { if (begin <= ender) ender += 1; else begin += 1; nosign = true; intdata = true; (void)strlcpy(format, chardata ? "%c" : "%u", sizeof(format)); } x = ender - begin; for (i = 1; i <= reps || infinity; i++) { if (use_random) y = random() / divisor; else y = arc4random() / divisor; if (putdata(y * x + begin, !(reps - i))) errx(1, "range error in conversion"); } } else for (i = 1, x = begin; i <= reps || infinity; i++, x += s) if (putdata(x, !(reps - i))) errx(1, "range error in conversion"); if (!nofinalnl) putchar('\n'); exit(0); } /* * Send x to stdout using the specified format. * Last is true if this is the set's last value. * Return 0 if OK, or a positive number if the number passed was * outside the range specified by the various flags. */ static int putdata(double x, bool last) { if (boring) printf("%s", format); else if (longdata && nosign) { if (x <= (double)ULONG_MAX && x >= (double)0) printf(format, (unsigned long)x); else return (1); } else if (longdata) { if (x <= (double)LONG_MAX && x >= (double)LONG_MIN) printf(format, (long)x); else return (1); } else if (chardata || (intdata && !nosign)) { if (x <= (double)INT_MAX && x >= (double)INT_MIN) printf(format, (int)x); else return (1); } else if (intdata) { if (x <= (double)UINT_MAX && x >= (double)0) printf(format, (unsigned int)x); else return (1); } else printf(format, x); if (!last) fputs(sepstring, stdout); return (0); } static void usage(void) { fprintf(stderr, "%s\n%s\n", "usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision]", " [reps [begin [end [s]]]]"); exit(1); } /* * Return the number of digits following the number's decimal point. * Return 0 if no decimal point is found. */ static int getprec(const char *str) { const char *p; const char *q; for (p = str; *p; p++) if (*p == '.') break; if (!*p) return (0); for (q = ++p; *p; p++) if (!isdigit((unsigned char)*p)) break; return (p - q); } /* * Set format, intdata, chardata, longdata, and nosign * based on the command line arguments. */ static void getformat(void) { char *p, *p2; int dot, hash, space, sign, numbers = 0; size_t sz; if (boring) /* no need to bother */ return; for (p = format; *p; p++) /* look for '%' */ if (*p == '%') { if (p[1] == '%') p++; /* leave %% alone */ else break; } sz = sizeof(format) - strlen(format) - 1; if (!*p && !chardata) { if (snprintf(p, sz, "%%.%df", prec) >= (int)sz) errx(1, "-w word too long"); } else if (!*p && chardata) { if (strlcpy(p, "%c", sz) >= sz) errx(1, "-w word too long"); intdata = true; } else if (!*(p+1)) { if (sz <= 0) errx(1, "-w word too long"); strcat(format, "%"); /* cannot end in single '%' */ } else { /* * Allow conversion format specifiers of the form * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u} */ p2 = p++; dot = hash = space = sign = numbers = 0; while (!isalpha((unsigned char)*p)) { if (isdigit((unsigned char)*p)) { numbers++; p++; } else if ((*p == '#' && !(numbers|dot|sign|space| hash++)) || (*p == ' ' && !(numbers|dot|space++)) || ((*p == '+' || *p == '-') && !(numbers|dot|sign++)) || (*p == '.' && !(dot++))) p++; else goto fmt_broken; } if (*p == 'l') { longdata = true; if (*++p == 'l') { if (p[1] != '\0') p++; goto fmt_broken; } } switch (*p) { case 'o': case 'u': case 'x': case 'X': intdata = nosign = true; break; case 'd': case 'i': intdata = true; break; case 'D': if (!longdata) { intdata = true; break; } case 'O': case 'U': if (!longdata) { intdata = nosign = true; break; } case 'c': if (!(intdata | longdata)) { chardata = true; break; } case 'h': case 'n': case 'p': case 'q': case 's': case 'L': case '$': case '*': goto fmt_broken; case 'f': case 'e': case 'g': case 'E': case 'G': if (!longdata) break; /* FALLTHROUGH */ default: fmt_broken: *++p = '\0'; errx(1, "illegal or unsupported format '%s'", p2); /* NOTREACHED */ } while (*++p) if (*p == '%' && *(p+1) && *(p+1) != '%') errx(1, "too many conversions"); else if (*p == '%' && *(p+1) == '%') p++; else if (*p == '%' && !*(p+1)) { if (strlcat(format, "%", sizeof(format)) >= sizeof(format)) errx(1, "-w word too long"); break; } } } Index: head/usr.bin/kdump/kdump.c =================================================================== --- head/usr.bin/kdump/kdump.c (revision 335394) +++ head/usr.bin/kdump/kdump.c (revision 335395) @@ -1,2192 +1,2192 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1988, 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1988, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)kdump.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #define _WANT_KERNEL_ERRNO #ifdef __LP64__ #define _WANT_KEVENT32 #endif #define _WANT_FREEBSD11_KEVENT #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef WITH_CASPER #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ktrace.h" #ifdef WITH_CASPER #include #include #include #endif u_int abidump(struct ktr_header *); int fetchprocinfo(struct ktr_header *, u_int *); int fread_tail(void *, int, int); void dumpheader(struct ktr_header *); void ktrsyscall(struct ktr_syscall *, u_int); void ktrsysret(struct ktr_sysret *, u_int); void ktrnamei(char *, int); void hexdump(char *, int, int); void visdump(char *, int, int); void ktrgenio(struct ktr_genio *, int); void ktrpsig(struct ktr_psig *); void ktrcsw(struct ktr_csw *); void ktrcsw_old(struct ktr_csw_old *); void ktruser(int, void *); void ktrcaprights(cap_rights_t *); void ktritimerval(struct itimerval *it); void ktrsockaddr(struct sockaddr *); void ktrstat(struct stat *); void ktrstruct(char *, size_t); void ktrcapfail(struct ktr_cap_fail *); void ktrfault(struct ktr_fault *); void ktrfaultend(struct ktr_faultend *); void ktrkevent(struct kevent *); void ktrstructarray(struct ktr_struct_array *, size_t); void usage(void); #define TIMESTAMP_NONE 0x0 #define TIMESTAMP_ABSOLUTE 0x1 #define TIMESTAMP_ELAPSED 0x2 #define TIMESTAMP_RELATIVE 0x4 static int timestamp, decimal, fancy = 1, suppressdata, tail, threads, maxdata, resolv = 0, abiflag = 0, syscallno = 0; static const char *tracefile = DEF_TRACEFILE; static struct ktr_header ktr_header; #define TIME_FORMAT "%b %e %T %Y" #define eqs(s1, s2) (strcmp((s1), (s2)) == 0) #define print_number64(first,i,n,c) do { \ uint64_t __v; \ \ if (quad_align && (((ptrdiff_t)((i) - (first))) & 1) == 1) { \ (i)++; \ (n)--; \ } \ if (quad_slots == 2) \ __v = (uint64_t)(uint32_t)(i)[0] | \ ((uint64_t)(uint32_t)(i)[1]) << 32; \ else \ __v = (uint64_t)*(i); \ if (decimal) \ printf("%c%jd", (c), (intmax_t)__v); \ else \ printf("%c%#jx", (c), (uintmax_t)__v); \ (i) += quad_slots; \ (n) -= quad_slots; \ (c) = ','; \ } while (0) #define print_number(i,n,c) do { \ if (decimal) \ printf("%c%jd", c, (intmax_t)*i); \ else \ printf("%c%#jx", c, (uintmax_t)(u_register_t)*i); \ i++; \ n--; \ c = ','; \ } while (0) struct proc_info { TAILQ_ENTRY(proc_info) info; u_int sv_flags; pid_t pid; }; static TAILQ_HEAD(trace_procs, proc_info) trace_procs; #ifdef WITH_CASPER static cap_channel_t *cappwd, *capgrp; static int cappwdgrp_setup(cap_channel_t **cappwdp, cap_channel_t **capgrpp) { cap_channel_t *capcas, *cappwdloc, *capgrploc; const char *cmds[1], *fields[1]; capcas = cap_init(); if (capcas == NULL) { err(1, "unable to create casper process"); exit(1); } cappwdloc = cap_service_open(capcas, "system.pwd"); capgrploc = cap_service_open(capcas, "system.grp"); /* Casper capability no longer needed. */ cap_close(capcas); if (cappwdloc == NULL || capgrploc == NULL) { if (cappwdloc == NULL) warn("unable to open system.pwd service"); if (capgrploc == NULL) warn("unable to open system.grp service"); exit(1); } /* Limit system.pwd to only getpwuid() function and pw_name field. */ cmds[0] = "getpwuid"; if (cap_pwd_limit_cmds(cappwdloc, cmds, 1) < 0) err(1, "unable to limit system.pwd service"); fields[0] = "pw_name"; if (cap_pwd_limit_fields(cappwdloc, fields, 1) < 0) err(1, "unable to limit system.pwd service"); /* Limit system.grp to only getgrgid() function and gr_name field. */ cmds[0] = "getgrgid"; if (cap_grp_limit_cmds(capgrploc, cmds, 1) < 0) err(1, "unable to limit system.grp service"); fields[0] = "gr_name"; if (cap_grp_limit_fields(capgrploc, fields, 1) < 0) err(1, "unable to limit system.grp service"); *cappwdp = cappwdloc; *capgrpp = capgrploc; return (0); } #endif /* WITH_CASPER */ static void print_integer_arg(const char *(*decoder)(int), int value) { const char *str; str = decoder(value); if (str != NULL) printf("%s", str); else { if (decimal) printf("", value); else printf("", value); } } /* Like print_integer_arg but unknown values are treated as valid. */ static void print_integer_arg_valid(const char *(*decoder)(int), int value) { const char *str; str = decoder(value); if (str != NULL) printf("%s", str); else { if (decimal) printf("%d", value); else printf("%#x", value); } } static void print_mask_arg(bool (*decoder)(FILE *, int, int *), int value) { bool invalid; int rem; printf("%#x<", value); invalid = !decoder(stdout, value, &rem); printf(">"); if (invalid) printf("%u", rem); } static void print_mask_arg0(bool (*decoder)(FILE *, int, int *), int value) { bool invalid; int rem; if (value == 0) { printf("0"); return; } printf("%#x<", value); invalid = !decoder(stdout, value, &rem); printf(">"); if (invalid) printf("%u", rem); } static void decode_fileflags(fflags_t value) { bool invalid; fflags_t rem; if (value == 0) { printf("0"); return; } printf("%#x<", value); invalid = !sysdecode_fileflags(stdout, value, &rem); printf(">"); if (invalid) printf("%u", rem); } static void decode_filemode(int value) { bool invalid; int rem; if (value == 0) { printf("0"); return; } printf("%#o<", value); invalid = !sysdecode_filemode(stdout, value, &rem); printf(">"); if (invalid) printf("%u", rem); } static void print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), uint32_t value) { bool invalid; uint32_t rem; printf("%#x<", value); invalid = !decoder(stdout, value, &rem); printf(">"); if (invalid) printf("%u", rem); } static void print_mask_argul(bool (*decoder)(FILE *, u_long, u_long *), u_long value) { bool invalid; u_long rem; if (value == 0) { printf("0"); return; } printf("%#lx<", value); invalid = !decoder(stdout, value, &rem); printf(">"); if (invalid) printf("%lu", rem); } int main(int argc, char *argv[]) { int ch, ktrlen, size; void *m; int trpoints = ALL_POINTS; int drop_logged; pid_t pid = 0; u_int sv_flags; setlocale(LC_CTYPE, ""); timestamp = TIMESTAMP_NONE; while ((ch = getopt(argc,argv,"f:dElm:np:AHRrSsTt:")) != -1) switch (ch) { case 'A': abiflag = 1; break; case 'f': tracefile = optarg; break; case 'd': decimal = 1; break; case 'l': tail = 1; break; case 'm': maxdata = atoi(optarg); break; case 'n': fancy = 0; break; case 'p': pid = atoi(optarg); break; case 'r': resolv = 1; break; case 'S': syscallno = 1; break; case 's': suppressdata = 1; break; case 'E': timestamp |= TIMESTAMP_ELAPSED; break; case 'H': threads = 1; break; case 'R': timestamp |= TIMESTAMP_RELATIVE; break; case 'T': timestamp |= TIMESTAMP_ABSOLUTE; break; case 't': trpoints = getpoints(optarg); if (trpoints < 0) errx(1, "unknown trace point in %s", optarg); break; default: usage(); } if (argc > optind) usage(); m = malloc(size = 1025); if (m == NULL) errx(1, "%s", strerror(ENOMEM)); if (strcmp(tracefile, "-") != 0) if (!freopen(tracefile, "r", stdin)) err(1, "%s", tracefile); caph_cache_catpages(); caph_cache_tzdata(); #ifdef WITH_CASPER if (resolv != 0) { if (cappwdgrp_setup(&cappwd, &capgrp) < 0) { cappwd = NULL; capgrp = NULL; } } if (resolv == 0 || (cappwd != NULL && capgrp != NULL)) { - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "unable to enter capability mode"); } #else if (resolv == 0) { - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "unable to enter capability mode"); } #endif if (caph_limit_stdio() == -1) err(1, "unable to limit stdio"); TAILQ_INIT(&trace_procs); drop_logged = 0; while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) { if (ktr_header.ktr_type & KTR_DROP) { ktr_header.ktr_type &= ~KTR_DROP; if (!drop_logged && threads) { printf( "%6jd %6jd %-8.*s Events dropped.\n", (intmax_t)ktr_header.ktr_pid, ktr_header.ktr_tid > 0 ? (intmax_t)ktr_header.ktr_tid : 0, MAXCOMLEN, ktr_header.ktr_comm); drop_logged = 1; } else if (!drop_logged) { printf("%6jd %-8.*s Events dropped.\n", (intmax_t)ktr_header.ktr_pid, MAXCOMLEN, ktr_header.ktr_comm); drop_logged = 1; } } if (trpoints & (1< size) { m = realloc(m, ktrlen+1); if (m == NULL) errx(1, "%s", strerror(ENOMEM)); size = ktrlen; } if (ktrlen && fread_tail(m, ktrlen, 1) == 0) errx(1, "data too short"); if (fetchprocinfo(&ktr_header, (u_int *)m) != 0) continue; sv_flags = abidump(&ktr_header); if (pid && ktr_header.ktr_pid != pid && ktr_header.ktr_tid != pid) continue; if ((trpoints & (1<ktr_type) { case KTR_PROCCTOR: TAILQ_FOREACH(pi, &trace_procs, info) { if (pi->pid == kth->ktr_pid) { TAILQ_REMOVE(&trace_procs, pi, info); break; } } pi = malloc(sizeof(struct proc_info)); if (pi == NULL) errx(1, "%s", strerror(ENOMEM)); pi->sv_flags = *flags; pi->pid = kth->ktr_pid; TAILQ_INSERT_TAIL(&trace_procs, pi, info); return (1); case KTR_PROCDTOR: TAILQ_FOREACH(pi, &trace_procs, info) { if (pi->pid == kth->ktr_pid) { TAILQ_REMOVE(&trace_procs, pi, info); free(pi); break; } } return (1); } return (0); } u_int abidump(struct ktr_header *kth) { struct proc_info *pi; const char *abi; const char *arch; u_int flags = 0; TAILQ_FOREACH(pi, &trace_procs, info) { if (pi->pid == kth->ktr_pid) { flags = pi->sv_flags; break; } } if (abiflag == 0) return (flags); switch (flags & SV_ABI_MASK) { case SV_ABI_LINUX: abi = "L"; break; case SV_ABI_FREEBSD: abi = "F"; break; case SV_ABI_CLOUDABI: abi = "C"; break; default: abi = "U"; break; } if (flags & SV_LP64) arch = "64"; else if (flags & SV_ILP32) arch = "32"; else arch = "00"; printf("%s%s ", abi, arch); return (flags); } void dumpheader(struct ktr_header *kth) { static char unknown[64]; static struct timeval prevtime, prevtime_e; struct timeval temp; const char *type; const char *sign; switch (kth->ktr_type) { case KTR_SYSCALL: type = "CALL"; break; case KTR_SYSRET: type = "RET "; break; case KTR_NAMEI: type = "NAMI"; break; case KTR_GENIO: type = "GIO "; break; case KTR_PSIG: type = "PSIG"; break; case KTR_CSW: type = "CSW "; break; case KTR_USER: type = "USER"; break; case KTR_STRUCT: case KTR_STRUCT_ARRAY: type = "STRU"; break; case KTR_SYSCTL: type = "SCTL"; break; case KTR_PROCCTOR: /* FALLTHROUGH */ case KTR_PROCDTOR: return; case KTR_CAPFAIL: type = "CAP "; break; case KTR_FAULT: type = "PFLT"; break; case KTR_FAULTEND: type = "PRET"; break; default: sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type); type = unknown; } /* * The ktr_tid field was previously the ktr_buffer field, which held * the kernel pointer value for the buffer associated with data * following the record header. It now holds a threadid, but only * for trace files after the change. Older trace files still contain * kernel pointers. Detect this and suppress the results by printing * negative tid's as 0. */ if (threads) printf("%6jd %6jd %-8.*s ", (intmax_t)kth->ktr_pid, kth->ktr_tid > 0 ? (intmax_t)kth->ktr_tid : 0, MAXCOMLEN, kth->ktr_comm); else printf("%6jd %-8.*s ", (intmax_t)kth->ktr_pid, MAXCOMLEN, kth->ktr_comm); if (timestamp) { if (timestamp & TIMESTAMP_ABSOLUTE) { printf("%jd.%06ld ", (intmax_t)kth->ktr_time.tv_sec, kth->ktr_time.tv_usec); } if (timestamp & TIMESTAMP_ELAPSED) { if (prevtime_e.tv_sec == 0) prevtime_e = kth->ktr_time; timersub(&kth->ktr_time, &prevtime_e, &temp); printf("%jd.%06ld ", (intmax_t)temp.tv_sec, temp.tv_usec); } if (timestamp & TIMESTAMP_RELATIVE) { if (prevtime.tv_sec == 0) prevtime = kth->ktr_time; if (timercmp(&kth->ktr_time, &prevtime, <)) { timersub(&prevtime, &kth->ktr_time, &temp); sign = "-"; } else { timersub(&kth->ktr_time, &prevtime, &temp); sign = ""; } prevtime = kth->ktr_time; printf("%s%jd.%06ld ", sign, (intmax_t)temp.tv_sec, temp.tv_usec); } } printf("%s ", type); } #include static void ioctlname(unsigned long val) { const char *str; str = sysdecode_ioctlname(val); if (str != NULL) printf("%s", str); else if (decimal) printf("%lu", val); else printf("%#lx", val); } static enum sysdecode_abi syscallabi(u_int sv_flags) { if (sv_flags == 0) return (SYSDECODE_ABI_FREEBSD); switch (sv_flags & SV_ABI_MASK) { case SV_ABI_FREEBSD: return (SYSDECODE_ABI_FREEBSD); case SV_ABI_LINUX: #ifdef __LP64__ if (sv_flags & SV_ILP32) return (SYSDECODE_ABI_LINUX32); #endif return (SYSDECODE_ABI_LINUX); case SV_ABI_CLOUDABI: return (SYSDECODE_ABI_CLOUDABI64); default: return (SYSDECODE_ABI_UNKNOWN); } } static void syscallname(u_int code, u_int sv_flags) { const char *name; name = sysdecode_syscallname(syscallabi(sv_flags), code); if (name == NULL) printf("[%d]", code); else { printf("%s", name); if (syscallno) printf("[%d]", code); } } static void print_signal(int signo) { const char *signame; signame = sysdecode_signal(signo); if (signame != NULL) printf("%s", signame); else printf("SIG %d", signo); } void ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) { int narg = ktr->ktr_narg; register_t *ip, *first; intmax_t arg; int quad_align, quad_slots; syscallname(ktr->ktr_code, sv_flags); ip = first = &ktr->ktr_args[0]; if (narg) { char c = '('; if (fancy && (sv_flags == 0 || (sv_flags & SV_ABI_MASK) == SV_ABI_FREEBSD)) { quad_align = 0; if (sv_flags & SV_ILP32) { #ifdef __powerpc__ quad_align = 1; #endif quad_slots = 2; } else quad_slots = 1; switch (ktr->ktr_code) { case SYS_bindat: case SYS_chflagsat: case SYS_connectat: case SYS_faccessat: case SYS_fchmodat: case SYS_fchownat: case SYS_fstatat: case SYS_futimesat: case SYS_linkat: case SYS_mkdirat: case SYS_mkfifoat: case SYS_mknodat: case SYS_openat: case SYS_readlinkat: case SYS_renameat: case SYS_unlinkat: case SYS_utimensat: putchar('('); print_integer_arg_valid(sysdecode_atfd, *ip); c = ','; ip++; narg--; break; } switch (ktr->ktr_code) { case SYS_ioctl: { print_number(ip, narg, c); putchar(c); ioctlname(*ip); c = ','; ip++; narg--; break; } case SYS_ptrace: putchar('('); print_integer_arg(sysdecode_ptrace_request, *ip); c = ','; ip++; narg--; break; case SYS_access: case SYS_eaccess: case SYS_faccessat: print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_access_mode, *ip); ip++; narg--; break; case SYS_open: case SYS_openat: print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_open_flags, ip[0]); if ((ip[0] & O_CREAT) == O_CREAT) { putchar(','); decode_filemode(ip[1]); } ip += 2; narg -= 2; break; case SYS_wait4: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_mask_arg0(sysdecode_wait4_options, *ip); ip++; narg--; break; case SYS_wait6: putchar('('); print_integer_arg(sysdecode_idtype, *ip); c = ','; ip++; narg--; print_number64(first, ip, narg, c); print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_wait6_options, *ip); ip++; narg--; break; case SYS_chmod: case SYS_fchmod: case SYS_lchmod: case SYS_fchmodat: print_number(ip, narg, c); putchar(','); decode_filemode(*ip); ip++; narg--; break; case SYS_mknodat: print_number(ip, narg, c); putchar(','); decode_filemode(*ip); ip++; narg--; break; case SYS_getfsstat: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_integer_arg(sysdecode_getfsstat_mode, *ip); ip++; narg--; break; case SYS_mount: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_mount_flags, *ip); ip++; narg--; break; case SYS_unmount: print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_mount_flags, *ip); ip++; narg--; break; case SYS_recvmsg: case SYS_sendmsg: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_mask_arg0(sysdecode_msg_flags, *ip); ip++; narg--; break; case SYS_recvfrom: case SYS_sendto: print_number(ip, narg, c); print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_mask_arg0(sysdecode_msg_flags, *ip); ip++; narg--; break; case SYS_chflags: case SYS_chflagsat: case SYS_fchflags: case SYS_lchflags: print_number(ip, narg, c); putchar(','); decode_fileflags(*ip); ip++; narg--; break; case SYS_kill: print_number(ip, narg, c); putchar(','); print_signal(*ip); ip++; narg--; break; case SYS_reboot: putchar('('); print_mask_arg(sysdecode_reboot_howto, *ip); ip++; narg--; break; case SYS_umask: putchar('('); decode_filemode(*ip); ip++; narg--; break; case SYS_msync: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_msync_flags, *ip); ip++; narg--; break; #ifdef SYS_freebsd6_mmap case SYS_freebsd6_mmap: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_mmap_prot, *ip); putchar(','); ip++; narg--; print_mask_arg(sysdecode_mmap_flags, *ip); ip++; narg--; break; #endif case SYS_mmap: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_mmap_prot, *ip); putchar(','); ip++; narg--; print_mask_arg(sysdecode_mmap_flags, *ip); ip++; narg--; break; case SYS_mprotect: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_mmap_prot, *ip); ip++; narg--; break; case SYS_madvise: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_integer_arg(sysdecode_madvice, *ip); ip++; narg--; break; case SYS_pathconf: case SYS_lpathconf: case SYS_fpathconf: print_number(ip, narg, c); putchar(','); print_integer_arg(sysdecode_pathconf_name, *ip); ip++; narg--; break; case SYS_getpriority: case SYS_setpriority: putchar('('); print_integer_arg(sysdecode_prio_which, *ip); c = ','; ip++; narg--; break; case SYS_fcntl: print_number(ip, narg, c); putchar(','); print_integer_arg(sysdecode_fcntl_cmd, ip[0]); if (sysdecode_fcntl_arg_p(ip[0])) { putchar(','); if (ip[0] == F_SETFL) print_mask_arg( sysdecode_fcntl_fileflags, ip[1]); else sysdecode_fcntl_arg(stdout, ip[0], ip[1], decimal ? 10 : 16); } ip += 2; narg -= 2; break; case SYS_socket: { int sockdomain; putchar('('); sockdomain = *ip; print_integer_arg(sysdecode_socketdomain, sockdomain); ip++; narg--; putchar(','); print_mask_arg(sysdecode_socket_type, *ip); ip++; narg--; if (sockdomain == PF_INET || sockdomain == PF_INET6) { putchar(','); print_integer_arg(sysdecode_ipproto, *ip); ip++; narg--; } c = ','; break; } case SYS_setsockopt: case SYS_getsockopt: { const char *str; print_number(ip, narg, c); putchar(','); print_integer_arg_valid(sysdecode_sockopt_level, *ip); str = sysdecode_sockopt_name(ip[0], ip[1]); if (str != NULL) { printf(",%s", str); ip++; narg--; } ip++; narg--; break; } #ifdef SYS_freebsd6_lseek case SYS_freebsd6_lseek: print_number(ip, narg, c); /* Hidden 'pad' argument, not in lseek(2) */ print_number(ip, narg, c); print_number64(first, ip, narg, c); putchar(','); print_integer_arg(sysdecode_whence, *ip); ip++; narg--; break; #endif case SYS_lseek: print_number(ip, narg, c); print_number64(first, ip, narg, c); putchar(','); print_integer_arg(sysdecode_whence, *ip); ip++; narg--; break; case SYS_flock: print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_flock_operation, *ip); ip++; narg--; break; case SYS_mkfifo: case SYS_mkfifoat: case SYS_mkdir: case SYS_mkdirat: print_number(ip, narg, c); putchar(','); decode_filemode(*ip); ip++; narg--; break; case SYS_shutdown: print_number(ip, narg, c); putchar(','); print_integer_arg(sysdecode_shutdown_how, *ip); ip++; narg--; break; case SYS_socketpair: putchar('('); print_integer_arg(sysdecode_socketdomain, *ip); ip++; narg--; putchar(','); print_mask_arg(sysdecode_socket_type, *ip); ip++; narg--; c = ','; break; case SYS_getrlimit: case SYS_setrlimit: putchar('('); print_integer_arg(sysdecode_rlimit, *ip); ip++; narg--; c = ','; break; case SYS_getrusage: putchar('('); print_integer_arg(sysdecode_getrusage_who, *ip); ip++; narg--; c = ','; break; case SYS_quotactl: print_number(ip, narg, c); putchar(','); if (!sysdecode_quotactl_cmd(stdout, *ip)) { if (decimal) printf("", (int)*ip); else printf("", (int)*ip); } ip++; narg--; c = ','; break; case SYS_nfssvc: putchar('('); print_integer_arg(sysdecode_nfssvc_flags, *ip); ip++; narg--; c = ','; break; case SYS_rtprio: case SYS_rtprio_thread: putchar('('); print_integer_arg(sysdecode_rtprio_function, *ip); ip++; narg--; c = ','; break; case SYS___semctl: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_integer_arg(sysdecode_semctl_cmd, *ip); ip++; narg--; break; case SYS_semget: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_semget_flags, *ip); ip++; narg--; break; case SYS_msgctl: print_number(ip, narg, c); putchar(','); print_integer_arg(sysdecode_msgctl_cmd, *ip); ip++; narg--; break; case SYS_shmat: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_shmat_flags, *ip); ip++; narg--; break; case SYS_shmctl: print_number(ip, narg, c); putchar(','); print_integer_arg(sysdecode_shmctl_cmd, *ip); ip++; narg--; break; case SYS_shm_open: print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_open_flags, ip[0]); putchar(','); decode_filemode(ip[1]); ip += 2; narg -= 2; break; case SYS_minherit: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_integer_arg(sysdecode_minherit_inherit, *ip); ip++; narg--; break; case SYS_rfork: putchar('('); print_mask_arg(sysdecode_rfork_flags, *ip); ip++; narg--; c = ','; break; case SYS_lio_listio: putchar('('); print_integer_arg(sysdecode_lio_listio_mode, *ip); ip++; narg--; c = ','; break; case SYS_mlockall: putchar('('); print_mask_arg(sysdecode_mlockall_flags, *ip); ip++; narg--; break; case SYS_sched_setscheduler: print_number(ip, narg, c); putchar(','); print_integer_arg(sysdecode_scheduler_policy, *ip); ip++; narg--; break; case SYS_sched_get_priority_max: case SYS_sched_get_priority_min: putchar('('); print_integer_arg(sysdecode_scheduler_policy, *ip); ip++; narg--; break; case SYS_sendfile: print_number(ip, narg, c); print_number(ip, narg, c); print_number(ip, narg, c); print_number(ip, narg, c); print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_sendfile_flags, *ip); ip++; narg--; break; case SYS_kldsym: print_number(ip, narg, c); putchar(','); print_integer_arg(sysdecode_kldsym_cmd, *ip); ip++; narg--; break; case SYS_sigprocmask: putchar('('); print_integer_arg(sysdecode_sigprocmask_how, *ip); ip++; narg--; c = ','; break; case SYS___acl_get_file: case SYS___acl_set_file: case SYS___acl_get_fd: case SYS___acl_set_fd: case SYS___acl_delete_file: case SYS___acl_delete_fd: case SYS___acl_aclcheck_file: case SYS___acl_aclcheck_fd: case SYS___acl_get_link: case SYS___acl_set_link: case SYS___acl_delete_link: case SYS___acl_aclcheck_link: print_number(ip, narg, c); putchar(','); print_integer_arg(sysdecode_acltype, *ip); ip++; narg--; break; case SYS_sigaction: putchar('('); print_signal(*ip); ip++; narg--; c = ','; break; case SYS_extattrctl: print_number(ip, narg, c); putchar(','); print_integer_arg(sysdecode_extattrnamespace, *ip); ip++; narg--; break; case SYS_nmount: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_mount_flags, *ip); ip++; narg--; break; case SYS_thr_create: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_thr_create_flags, *ip); ip++; narg--; break; case SYS_thr_kill: print_number(ip, narg, c); putchar(','); print_signal(*ip); ip++; narg--; break; case SYS_kldunloadf: print_number(ip, narg, c); putchar(','); print_integer_arg(sysdecode_kldunload_flags, *ip); ip++; narg--; break; case SYS_linkat: case SYS_renameat: case SYS_symlinkat: print_number(ip, narg, c); putchar(','); print_integer_arg_valid(sysdecode_atfd, *ip); ip++; narg--; print_number(ip, narg, c); break; case SYS_cap_fcntls_limit: print_number(ip, narg, c); putchar(','); arg = *ip; ip++; narg--; print_mask_arg32(sysdecode_cap_fcntlrights, arg); break; case SYS_posix_fadvise: print_number(ip, narg, c); print_number(ip, narg, c); print_number(ip, narg, c); (void)putchar(','); print_integer_arg(sysdecode_fadvice, *ip); ip++; narg--; break; case SYS_procctl: putchar('('); print_integer_arg(sysdecode_idtype, *ip); c = ','; ip++; narg--; print_number64(first, ip, narg, c); putchar(','); print_integer_arg(sysdecode_procctl_cmd, *ip); ip++; narg--; break; case SYS__umtx_op: print_number(ip, narg, c); putchar(','); print_integer_arg(sysdecode_umtx_op, *ip); switch (*ip) { case UMTX_OP_CV_WAIT: ip++; narg--; putchar(','); print_mask_argul( sysdecode_umtx_cvwait_flags, *ip); break; case UMTX_OP_RW_RDLOCK: ip++; narg--; putchar(','); print_mask_argul( sysdecode_umtx_rwlock_flags, *ip); break; } ip++; narg--; break; case SYS_ftruncate: case SYS_truncate: print_number(ip, narg, c); print_number64(first, ip, narg, c); break; case SYS_fchownat: print_number(ip, narg, c); print_number(ip, narg, c); print_number(ip, narg, c); break; case SYS_fstatat: case SYS_utimensat: print_number(ip, narg, c); print_number(ip, narg, c); break; case SYS_unlinkat: print_number(ip, narg, c); break; case SYS_sysarch: putchar('('); print_integer_arg(sysdecode_sysarch_number, *ip); ip++; narg--; c = ','; break; } switch (ktr->ktr_code) { case SYS_chflagsat: case SYS_fchownat: case SYS_faccessat: case SYS_fchmodat: case SYS_fstatat: case SYS_linkat: case SYS_unlinkat: case SYS_utimensat: putchar(','); print_mask_arg0(sysdecode_atflags, *ip); ip++; narg--; break; } } while (narg > 0) { print_number(ip, narg, c); } putchar(')'); } putchar('\n'); } void ktrsysret(struct ktr_sysret *ktr, u_int sv_flags) { register_t ret = ktr->ktr_retval; int error = ktr->ktr_error; syscallname(ktr->ktr_code, sv_flags); printf(" "); if (error == 0) { if (fancy) { printf("%ld", (long)ret); if (ret < 0 || ret > 9) printf("/%#lx", (unsigned long)ret); } else { if (decimal) printf("%ld", (long)ret); else printf("%#lx", (unsigned long)ret); } } else if (error == ERESTART) printf("RESTART"); else if (error == EJUSTRETURN) printf("JUSTRETURN"); else { printf("-1 errno %d", sysdecode_freebsd_to_abi_errno( syscallabi(sv_flags), error)); if (fancy) printf(" %s", strerror(ktr->ktr_error)); } putchar('\n'); } void ktrnamei(char *cp, int len) { printf("\"%.*s\"\n", len, cp); } void hexdump(char *p, int len, int screenwidth) { int n, i; int width; width = 0; do { width += 2; i = 13; /* base offset */ i += (width / 2) + 1; /* spaces every second byte */ i += (width * 2); /* width of bytes */ i += 3; /* " |" */ i += width; /* each byte */ i += 1; /* "|" */ } while (i < screenwidth); width -= 2; for (n = 0; n < len; n += width) { for (i = n; i < n + width; i++) { if ((i % width) == 0) { /* beginning of line */ printf(" 0x%04x", i); } if ((i % 2) == 0) { printf(" "); } if (i < len) printf("%02x", p[i] & 0xff); else printf(" "); } printf(" |"); for (i = n; i < n + width; i++) { if (i >= len) break; if (p[i] >= ' ' && p[i] <= '~') printf("%c", p[i]); else printf("."); } printf("|\n"); } if ((i % width) != 0) printf("\n"); } void visdump(char *dp, int datalen, int screenwidth) { int col = 0; char *cp; int width; char visbuf[5]; printf(" \""); col = 8; for (;datalen > 0; datalen--, dp++) { vis(visbuf, *dp, VIS_CSTYLE, *(dp+1)); cp = visbuf; /* * Keep track of printables and * space chars (like fold(1)). */ if (col == 0) { putchar('\t'); col = 8; } switch(*cp) { case '\n': col = 0; putchar('\n'); continue; case '\t': width = 8 - (col&07); break; default: width = strlen(cp); } if (col + width > (screenwidth-2)) { printf("\\\n\t"); col = 8; } col += width; do { putchar(*cp++); } while (*cp); } if (col == 0) printf(" "); printf("\"\n"); } void ktrgenio(struct ktr_genio *ktr, int len) { int datalen = len - sizeof (struct ktr_genio); char *dp = (char *)ktr + sizeof (struct ktr_genio); static int screenwidth = 0; int i, binary; printf("fd %d %s %d byte%s\n", ktr->ktr_fd, ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen, datalen == 1 ? "" : "s"); if (suppressdata) return; if (screenwidth == 0) { struct winsize ws; if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 && ws.ws_col > 8) screenwidth = ws.ws_col; else screenwidth = 80; } if (maxdata && datalen > maxdata) datalen = maxdata; for (i = 0, binary = 0; i < datalen && binary == 0; i++) { if (dp[i] >= 32 && dp[i] < 127) continue; if (dp[i] == 10 || dp[i] == 13 || dp[i] == 0 || dp[i] == 9) continue; binary = 1; } if (binary) hexdump(dp, datalen, screenwidth); else visdump(dp, datalen, screenwidth); } void ktrpsig(struct ktr_psig *psig) { const char *str; print_signal(psig->signo); if (psig->action == SIG_DFL) { printf(" SIG_DFL"); } else { printf(" caught handler=0x%lx mask=0x%x", (u_long)psig->action, psig->mask.__bits[0]); } printf(" code="); str = sysdecode_sigcode(psig->signo, psig->code); if (str != NULL) printf("%s", str); else printf("", psig->code); putchar('\n'); } void ktrcsw_old(struct ktr_csw_old *cs) { printf("%s %s\n", cs->out ? "stop" : "resume", cs->user ? "user" : "kernel"); } void ktrcsw(struct ktr_csw *cs) { printf("%s %s \"%s\"\n", cs->out ? "stop" : "resume", cs->user ? "user" : "kernel", cs->wmesg); } void ktruser(int len, void *p) { unsigned char *cp; if (sysdecode_utrace(stdout, p, len)) { printf("\n"); return; } printf("%d ", len); cp = p; while (len--) if (decimal) printf(" %d", *cp++); else printf(" %02x", *cp++); printf("\n"); } void ktrcaprights(cap_rights_t *rightsp) { printf("cap_rights_t "); sysdecode_cap_rights(stdout, rightsp); printf("\n"); } static void ktrtimeval(struct timeval *tv) { printf("{%ld, %ld}", (long)tv->tv_sec, tv->tv_usec); } void ktritimerval(struct itimerval *it) { printf("itimerval { .interval = "); ktrtimeval(&it->it_interval); printf(", .value = "); ktrtimeval(&it->it_value); printf(" }\n"); } void ktrsockaddr(struct sockaddr *sa) { /* TODO: Support additional address families #include struct sockaddr_nb *nb; */ const char *str; char addr[64]; /* * note: ktrstruct() has already verified that sa points to a * buffer at least sizeof(struct sockaddr) bytes long and exactly * sa->sa_len bytes long. */ printf("struct sockaddr { "); str = sysdecode_sockaddr_family(sa->sa_family); if (str != NULL) printf("%s", str); else printf("", sa->sa_family); printf(", "); #define check_sockaddr_len(n) \ if (sa_##n.s##n##_len < sizeof(struct sockaddr_##n)) { \ printf("invalid"); \ break; \ } switch(sa->sa_family) { case AF_INET: { struct sockaddr_in sa_in; memset(&sa_in, 0, sizeof(sa_in)); memcpy(&sa_in, sa, sa->sa_len); check_sockaddr_len(in); inet_ntop(AF_INET, &sa_in.sin_addr, addr, sizeof addr); printf("%s:%u", addr, ntohs(sa_in.sin_port)); break; } case AF_INET6: { struct sockaddr_in6 sa_in6; memset(&sa_in6, 0, sizeof(sa_in6)); memcpy(&sa_in6, sa, sa->sa_len); check_sockaddr_len(in6); getnameinfo((struct sockaddr *)&sa_in6, sizeof(sa_in6), addr, sizeof(addr), NULL, 0, NI_NUMERICHOST); printf("[%s]:%u", addr, htons(sa_in6.sin6_port)); break; } case AF_UNIX: { struct sockaddr_un sa_un; memset(&sa_un, 0, sizeof(sa_un)); memcpy(&sa_un, sa, sa->sa_len); printf("%.*s", (int)sizeof(sa_un.sun_path), sa_un.sun_path); break; } default: printf("unknown address family"); } printf(" }\n"); } void ktrstat(struct stat *statp) { char mode[12], timestr[PATH_MAX + 4]; struct passwd *pwd; struct group *grp; struct tm *tm; /* * note: ktrstruct() has already verified that statp points to a * buffer exactly sizeof(struct stat) bytes long. */ printf("struct stat {"); printf("dev=%ju, ino=%ju, ", (uintmax_t)statp->st_dev, (uintmax_t)statp->st_ino); if (resolv == 0) printf("mode=0%jo, ", (uintmax_t)statp->st_mode); else { strmode(statp->st_mode, mode); printf("mode=%s, ", mode); } printf("nlink=%ju, ", (uintmax_t)statp->st_nlink); if (resolv == 0) { pwd = NULL; } else { #ifdef WITH_CASPER if (cappwd != NULL) pwd = cap_getpwuid(cappwd, statp->st_uid); else #endif pwd = getpwuid(statp->st_uid); } if (pwd == NULL) printf("uid=%ju, ", (uintmax_t)statp->st_uid); else printf("uid=\"%s\", ", pwd->pw_name); if (resolv == 0) { grp = NULL; } else { #ifdef WITH_CASPER if (capgrp != NULL) grp = cap_getgrgid(capgrp, statp->st_gid); else #endif grp = getgrgid(statp->st_gid); } if (grp == NULL) printf("gid=%ju, ", (uintmax_t)statp->st_gid); else printf("gid=\"%s\", ", grp->gr_name); printf("rdev=%ju, ", (uintmax_t)statp->st_rdev); printf("atime="); if (resolv == 0) printf("%jd", (intmax_t)statp->st_atim.tv_sec); else { tm = localtime(&statp->st_atim.tv_sec); strftime(timestr, sizeof(timestr), TIME_FORMAT, tm); printf("\"%s\"", timestr); } if (statp->st_atim.tv_nsec != 0) printf(".%09ld, ", statp->st_atim.tv_nsec); else printf(", "); printf("mtime="); if (resolv == 0) printf("%jd", (intmax_t)statp->st_mtim.tv_sec); else { tm = localtime(&statp->st_mtim.tv_sec); strftime(timestr, sizeof(timestr), TIME_FORMAT, tm); printf("\"%s\"", timestr); } if (statp->st_mtim.tv_nsec != 0) printf(".%09ld, ", statp->st_mtim.tv_nsec); else printf(", "); printf("ctime="); if (resolv == 0) printf("%jd", (intmax_t)statp->st_ctim.tv_sec); else { tm = localtime(&statp->st_ctim.tv_sec); strftime(timestr, sizeof(timestr), TIME_FORMAT, tm); printf("\"%s\"", timestr); } if (statp->st_ctim.tv_nsec != 0) printf(".%09ld, ", statp->st_ctim.tv_nsec); else printf(", "); printf("birthtime="); if (resolv == 0) printf("%jd", (intmax_t)statp->st_birthtim.tv_sec); else { tm = localtime(&statp->st_birthtim.tv_sec); strftime(timestr, sizeof(timestr), TIME_FORMAT, tm); printf("\"%s\"", timestr); } if (statp->st_birthtim.tv_nsec != 0) printf(".%09ld, ", statp->st_birthtim.tv_nsec); else printf(", "); printf("size=%jd, blksize=%ju, blocks=%jd, flags=0x%x", (uintmax_t)statp->st_size, (uintmax_t)statp->st_blksize, (intmax_t)statp->st_blocks, statp->st_flags); printf(" }\n"); } void ktrstruct(char *buf, size_t buflen) { char *name, *data; size_t namelen, datalen; int i; cap_rights_t rights; struct itimerval it; struct stat sb; struct sockaddr_storage ss; for (name = buf, namelen = 0; namelen < buflen && name[namelen] != '\0'; ++namelen) /* nothing */; if (namelen == buflen) goto invalid; if (name[namelen] != '\0') goto invalid; data = buf + namelen + 1; datalen = buflen - namelen - 1; if (datalen == 0) goto invalid; /* sanity check */ for (i = 0; i < (int)namelen; ++i) if (!isalpha(name[i])) goto invalid; if (strcmp(name, "caprights") == 0) { if (datalen != sizeof(cap_rights_t)) goto invalid; memcpy(&rights, data, datalen); ktrcaprights(&rights); } else if (strcmp(name, "itimerval") == 0) { if (datalen != sizeof(struct itimerval)) goto invalid; memcpy(&it, data, datalen); ktritimerval(&it); } else if (strcmp(name, "stat") == 0) { if (datalen != sizeof(struct stat)) goto invalid; memcpy(&sb, data, datalen); ktrstat(&sb); } else if (strcmp(name, "sockaddr") == 0) { if (datalen > sizeof(ss)) goto invalid; memcpy(&ss, data, datalen); if (datalen != ss.ss_len) goto invalid; ktrsockaddr((struct sockaddr *)&ss); } else { printf("unknown structure\n"); } return; invalid: printf("invalid record\n"); } void ktrcapfail(struct ktr_cap_fail *ktr) { switch (ktr->cap_type) { case CAPFAIL_NOTCAPABLE: /* operation on fd with insufficient capabilities */ printf("operation requires "); sysdecode_cap_rights(stdout, &ktr->cap_needed); printf(", descriptor holds "); sysdecode_cap_rights(stdout, &ktr->cap_held); break; case CAPFAIL_INCREASE: /* requested more capabilities than fd already has */ printf("attempt to increase capabilities from "); sysdecode_cap_rights(stdout, &ktr->cap_held); printf(" to "); sysdecode_cap_rights(stdout, &ktr->cap_needed); break; case CAPFAIL_SYSCALL: /* called restricted syscall */ printf("disallowed system call"); break; case CAPFAIL_LOOKUP: /* used ".." in strict-relative mode */ printf("restricted VFS lookup"); break; default: printf("unknown capability failure: "); sysdecode_cap_rights(stdout, &ktr->cap_needed); printf(" "); sysdecode_cap_rights(stdout, &ktr->cap_held); break; } printf("\n"); } void ktrfault(struct ktr_fault *ktr) { printf("0x%jx ", (uintmax_t)ktr->vaddr); print_mask_arg(sysdecode_vmprot, ktr->type); printf("\n"); } void ktrfaultend(struct ktr_faultend *ktr) { const char *str; str = sysdecode_vmresult(ktr->result); if (str != NULL) printf("%s", str); else printf("", ktr->result); printf("\n"); } void ktrkevent(struct kevent *kev) { printf("{ ident="); switch (kev->filter) { case EVFILT_READ: case EVFILT_WRITE: case EVFILT_VNODE: case EVFILT_PROC: case EVFILT_TIMER: case EVFILT_PROCDESC: case EVFILT_EMPTY: printf("%ju", (uintmax_t)kev->ident); break; case EVFILT_SIGNAL: print_signal(kev->ident); break; default: printf("%p", (void *)kev->ident); } printf(", filter="); print_integer_arg(sysdecode_kevent_filter, kev->filter); printf(", flags="); print_mask_arg0(sysdecode_kevent_flags, kev->flags); printf(", fflags="); sysdecode_kevent_fflags(stdout, kev->filter, kev->fflags, decimal ? 10 : 16); printf(", data=%#jx, udata=%p }", (uintmax_t)kev->data, kev->udata); } void ktrstructarray(struct ktr_struct_array *ksa, size_t buflen) { struct kevent kev; char *name, *data; size_t namelen, datalen; int i; bool first; buflen -= sizeof(*ksa); for (name = (char *)(ksa + 1), namelen = 0; namelen < buflen && name[namelen] != '\0'; ++namelen) /* nothing */; if (namelen == buflen) goto invalid; if (name[namelen] != '\0') goto invalid; /* sanity check */ for (i = 0; i < (int)namelen; ++i) if (!isalnum(name[i]) && name[i] != '_') goto invalid; data = name + namelen + 1; datalen = buflen - namelen - 1; printf("struct %s[] = { ", name); first = true; for (; datalen >= ksa->struct_size; data += ksa->struct_size, datalen -= ksa->struct_size) { if (!first) printf("\n "); else first = false; if (strcmp(name, "kevent") == 0) { if (ksa->struct_size != sizeof(kev)) goto bad_size; memcpy(&kev, data, sizeof(kev)); ktrkevent(&kev); } else if (strcmp(name, "kevent_freebsd11") == 0) { struct kevent_freebsd11 kev11; if (ksa->struct_size != sizeof(kev11)) goto bad_size; memcpy(&kev11, data, sizeof(kev11)); memset(&kev, 0, sizeof(kev)); kev.ident = kev11.ident; kev.filter = kev11.filter; kev.flags = kev11.flags; kev.fflags = kev11.fflags; kev.data = kev11.data; kev.udata = kev11.udata; ktrkevent(&kev); #ifdef _WANT_KEVENT32 } else if (strcmp(name, "kevent32") == 0) { struct kevent32 kev32; if (ksa->struct_size != sizeof(kev32)) goto bad_size; memcpy(&kev32, data, sizeof(kev32)); memset(&kev, 0, sizeof(kev)); kev.ident = kev32.ident; kev.filter = kev32.filter; kev.flags = kev32.flags; kev.fflags = kev32.fflags; #if BYTE_ORDER == BIG_ENDIAN kev.data = kev32.data2 | ((int64_t)kev32.data1 << 32); #else kev.data = kev32.data1 | ((int64_t)kev32.data2 << 32); #endif kev.udata = (void *)(uintptr_t)kev32.udata; ktrkevent(&kev); } else if (strcmp(name, "kevent32_freebsd11") == 0) { struct kevent32_freebsd11 kev32; if (ksa->struct_size != sizeof(kev32)) goto bad_size; memcpy(&kev32, data, sizeof(kev32)); memset(&kev, 0, sizeof(kev)); kev.ident = kev32.ident; kev.filter = kev32.filter; kev.flags = kev32.flags; kev.fflags = kev32.fflags; kev.data = kev32.data; kev.udata = (void *)(uintptr_t)kev32.udata; ktrkevent(&kev); #endif } else { printf(" }\n"); return; } } printf(" }\n"); return; invalid: printf("invalid record\n"); return; bad_size: printf(" }\n"); return; } void usage(void) { fprintf(stderr, "usage: kdump [-dEnlHRrSsTA] [-f trfile] " "[-m maxdata] [-p pid] [-t trstr]\n"); exit(1); } Index: head/usr.bin/ktrdump/ktrdump.c =================================================================== --- head/usr.bin/ktrdump/ktrdump.c (revision 335394) +++ head/usr.bin/ktrdump/ktrdump.c (revision 335395) @@ -1,360 +1,360 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2002 Jake Burkholder * Copyright (c) 2004 Robert Watson * 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. * * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SBUFLEN 128 #define USAGE \ "usage: ktrdump [-cfqrtH] [-i ktrfile] [-M core] [-N system] [-o outfile]\n" static void usage(void); static struct nlist nl[] = { { "_ktr_version" }, { "_ktr_entries" }, { "_ktr_idx" }, { "_ktr_buf" }, { NULL } }; static int cflag; static int fflag; static int Mflag; static int Nflag; static int qflag; static int rflag; static int tflag; static int iflag; static int hflag; static char corefile[PATH_MAX]; static char execfile[PATH_MAX]; static char outfile[PATH_MAX] = "stdout"; static char desc[SBUFLEN]; static char errbuf[_POSIX2_LINE_MAX]; static char fbuf[PATH_MAX]; static char obuf[PATH_MAX]; static char sbuf[KTR_PARMS][SBUFLEN]; /* * Reads the ktr trace buffer from kernel memory and prints the trace entries. */ int main(int ac, char **av) { u_long parms[KTR_PARMS]; struct ktr_entry *buf; uintmax_t tlast, tnow; unsigned long bufptr; cap_rights_t rights; struct stat sb; kvm_t *kd; FILE *out; char *p; int version; int entries; int count; int index, index2; int parm; int in; int c; int i = 0; /* * Parse commandline arguments. */ out = stdout; while ((c = getopt(ac, av, "cfqrtHe:i:m:M:N:o:")) != -1) switch (c) { case 'c': cflag = 1; break; case 'N': case 'e': if (strlcpy(execfile, optarg, sizeof(execfile)) >= sizeof(execfile)) errx(1, "%s: File name too long", optarg); Nflag = 1; break; case 'f': fflag = 1; break; case 'i': iflag = 1; if ((in = open(optarg, O_RDONLY)) == -1) err(1, "%s", optarg); cap_rights_init(&rights, CAP_FSTAT, CAP_MMAP_R); if (cap_rights_limit(in, &rights) < 0 && errno != ENOSYS) err(1, "unable to limit rights for %s", optarg); break; case 'M': case 'm': if (strlcpy(corefile, optarg, sizeof(corefile)) >= sizeof(corefile)) errx(1, "%s: File name too long", optarg); Mflag = 1; break; case 'o': if ((out = fopen(optarg, "w")) == NULL) err(1, "%s", optarg); strlcpy(outfile, optarg, sizeof(outfile)); break; case 'q': qflag++; break; case 'r': rflag = 1; break; case 't': tflag = 1; break; case 'H': hflag = 1; break; case '?': default: usage(); } ac -= optind; av += optind; if (ac != 0) usage(); cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE); if (cap_rights_limit(fileno(out), &rights) < 0 && errno != ENOSYS) err(1, "unable to limit rights for %s", outfile); /* * Open our execfile and corefile, resolve needed symbols and read in * the trace buffer. */ if ((kd = kvm_openfiles(Nflag ? execfile : NULL, Mflag ? corefile : NULL, NULL, O_RDONLY, errbuf)) == NULL) errx(1, "%s", errbuf); /* * Cache NLS data, for strerror, for err(3), before entering capability * mode. */ caph_cache_catpages(); count = kvm_nlist(kd, nl); if (count == -1) errx(1, "%s", kvm_geterr(kd)); if (count > 0) errx(1, "failed to resolve ktr symbols"); if (kvm_read(kd, nl[0].n_value, &version, sizeof(version)) == -1) errx(1, "%s", kvm_geterr(kd)); if (version != KTR_VERSION) errx(1, "ktr version mismatch"); /* * Enter Capsicum sandbox. * * kvm_nlist() above uses kldsym(2) for native kernels, and that isn't * allowed in the sandbox. */ - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "unable to enter capability mode"); if (iflag) { if (fstat(in, &sb) == -1) errx(1, "stat"); entries = sb.st_size / sizeof(*buf); index = 0; buf = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, in, 0); if (buf == MAP_FAILED) errx(1, "mmap"); } else { if (kvm_read(kd, nl[1].n_value, &entries, sizeof(entries)) == -1) errx(1, "%s", kvm_geterr(kd)); if ((buf = malloc(sizeof(*buf) * entries)) == NULL) err(1, NULL); if (kvm_read(kd, nl[2].n_value, &index, sizeof(index)) == -1 || kvm_read(kd, nl[3].n_value, &bufptr, sizeof(bufptr)) == -1 || kvm_read(kd, bufptr, buf, sizeof(*buf) * entries) == -1 || kvm_read(kd, nl[2].n_value, &index2, sizeof(index2)) == -1) errx(1, "%s", kvm_geterr(kd)); } /* * Print a nice header. */ if (!qflag) { fprintf(out, "%-6s ", "index"); if (cflag) fprintf(out, "%-3s ", "cpu"); if (tflag) fprintf(out, "%-16s ", "timestamp"); if (fflag) fprintf(out, "%-40s ", "file and line"); if (hflag) fprintf(out, "%-18s ", "tid"); fprintf(out, "%s", "trace"); fprintf(out, "\n"); fprintf(out, "------ "); if (cflag) fprintf(out, "--- "); if (tflag) fprintf(out, "---------------- "); if (fflag) fprintf(out, "---------------------------------------- "); if (hflag) fprintf(out, "------------------ "); fprintf(out, "----- "); fprintf(out, "\n"); } /* * Now tear through the trace buffer. */ if (!iflag) { i = index - 1; if (i < 0) i = entries - 1; } tlast = -1; for (;;) { if (buf[i].ktr_desc == NULL) break; if (kvm_read(kd, (u_long)buf[i].ktr_desc, desc, sizeof(desc)) == -1) errx(1, "%s", kvm_geterr(kd)); desc[sizeof(desc) - 1] = '\0'; parm = 0; for (p = desc; (c = *p++) != '\0';) { if (c != '%') continue; next: if ((c = *p++) == '\0') break; if (parm == KTR_PARMS) errx(1, "too many parameters in \"%s\"", desc); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '#': case '-': case ' ': case '+': case '\'': case 'h': case 'l': case 'j': case 't': case 'z': case 'q': case 'L': case '.': goto next; case 's': if (kvm_read(kd, (u_long)buf[i].ktr_parms[parm], sbuf[parm], sizeof(sbuf[parm])) == -1) strcpy(sbuf[parm], "(null)"); sbuf[parm][sizeof(sbuf[0]) - 1] = '\0'; parms[parm] = (u_long)sbuf[parm]; parm++; break; default: parms[parm] = buf[i].ktr_parms[parm]; parm++; break; } } fprintf(out, "%6d ", i); if (cflag) fprintf(out, "%3d ", buf[i].ktr_cpu); if (tflag) { tnow = (uintmax_t)buf[i].ktr_timestamp; if (rflag) { if (tlast == -1) tlast = tnow; fprintf(out, "%16ju ", !iflag ? tlast - tnow : tnow - tlast); tlast = tnow; } else fprintf(out, "%16ju ", tnow); } if (fflag) { if (kvm_read(kd, (u_long)buf[i].ktr_file, fbuf, sizeof(fbuf)) == -1) strcpy(fbuf, "(null)"); snprintf(obuf, sizeof(obuf), "%s:%d", fbuf, buf[i].ktr_line); fprintf(out, "%-40s ", obuf); } if (hflag) fprintf(out, "%p ", buf[i].ktr_thread); fprintf(out, desc, parms[0], parms[1], parms[2], parms[3], parms[4], parms[5]); fprintf(out, "\n"); if (!iflag) { /* * 'index' and 'index2' are the values of 'ktr_idx' * before and after the KTR buffer was copied into * 'buf'. Since the KTR entries between 'index' and * 'index2' were in flux while the KTR buffer was * being copied to userspace we don't dump them. */ if (i == index2) break; if (--i < 0) i = entries - 1; } else { if (++i == entries) break; } } return (0); } static void usage(void) { fprintf(stderr, USAGE); exit(1); } Index: head/usr.bin/lam/lam.c =================================================================== --- head/usr.bin/lam/lam.c (revision 335394) +++ head/usr.bin/lam/lam.c (revision 335395) @@ -1,249 +1,249 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)lam.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); /* * lam - laminate files * Author: John Kunze, UCB */ #include #include #include #include #include #include #include #include #include #define MAXOFILES 20 #define BIGBUFSIZ 5 * BUFSIZ static struct openfile { /* open file structure */ FILE *fp; /* file pointer */ short eof; /* eof flag */ short pad; /* pad flag for missing columns */ char eol; /* end of line character */ const char *sepstring; /* string to print before each line */ const char *format; /* printf(3) style string spec. */ } input[MAXOFILES]; static int morefiles; /* set by getargs(), changed by gatherline() */ static int nofinalnl; /* normally append \n to each output line */ static char line[BIGBUFSIZ]; static char *linep; static char *gatherline(struct openfile *); static void getargs(char *[]); static char *pad(struct openfile *); static void usage(void); int main(int argc, char *argv[]) { struct openfile *ip; if (argc == 1) usage(); if (caph_limit_stdio() == -1) err(1, "unable to limit stdio"); getargs(argv); if (!morefiles) usage(); /* * Cache NLS data, for strerror, for err(3), before entering capability * mode. */ caph_cache_catpages(); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "unable to enter capability mode"); for (;;) { linep = line; for (ip = input; ip->fp != NULL; ip++) linep = gatherline(ip); if (!morefiles) exit(0); fputs(line, stdout); fputs(ip->sepstring, stdout); if (!nofinalnl) putchar('\n'); } } static void getargs(char *av[]) { struct openfile *ip = input; char *p, *c; static char fmtbuf[BUFSIZ]; char *fmtp = fmtbuf; int P, S, F, T; cap_rights_t rights_ro; cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT); P = S = F = T = 0; /* capitalized options */ while ((p = *++av) != NULL) { if (*p != '-' || !p[1]) { if (++morefiles >= MAXOFILES) errx(1, "too many input files"); if (*p == '-') ip->fp = stdin; else if ((ip->fp = fopen(p, "r")) == NULL) { err(1, "%s", p); } if (cap_rights_limit(fileno(ip->fp), &rights_ro) < 0 && errno != ENOSYS) err(1, "unable to limit rights on: %s", p); ip->pad = P; if (!ip->sepstring) ip->sepstring = (S ? (ip-1)->sepstring : ""); if (!ip->format) ip->format = ((P || F) ? (ip-1)->format : "%s"); if (!ip->eol) ip->eol = (T ? (ip-1)->eol : '\n'); ip++; continue; } c = ++p; switch (tolower((unsigned char)*c)) { case 's': if (*++p || (p = *++av)) ip->sepstring = p; else usage(); S = (*c == 'S' ? 1 : 0); break; case 't': if (*++p || (p = *++av)) ip->eol = *p; else usage(); T = (*c == 'T' ? 1 : 0); nofinalnl = 1; break; case 'p': ip->pad = 1; P = (*c == 'P' ? 1 : 0); /* FALLTHROUGH */ case 'f': F = (*c == 'F' ? 1 : 0); if (*++p || (p = *++av)) { fmtp += strlen(fmtp) + 1; if (fmtp >= fmtbuf + sizeof(fmtbuf)) errx(1, "no more format space"); /* restrict format string to only valid width formatters */ if (strspn(p, "-.0123456789") != strlen(p)) errx(1, "invalid format string `%s'", p); if (snprintf(fmtp, fmtbuf + sizeof(fmtbuf) - fmtp, "%%%ss", p) >= fmtbuf + sizeof(fmtbuf) - fmtp) errx(1, "no more format space"); ip->format = fmtp; } else usage(); break; default: usage(); } } ip->fp = NULL; if (!ip->sepstring) ip->sepstring = ""; } static char * pad(struct openfile *ip) { char *lp = linep; strlcpy(lp, ip->sepstring, line + sizeof(line) - lp); lp += strlen(lp); if (ip->pad) { snprintf(lp, line + sizeof(line) - lp, ip->format, ""); lp += strlen(lp); } return (lp); } static char * gatherline(struct openfile *ip) { char s[BUFSIZ]; int c; char *p; char *lp = linep; char *end = s + sizeof(s) - 1; if (ip->eof) return (pad(ip)); for (p = s; (c = fgetc(ip->fp)) != EOF && p < end; p++) if ((*p = c) == ip->eol) break; *p = '\0'; if (c == EOF) { ip->eof = 1; if (ip->fp == stdin) fclose(stdin); morefiles--; return (pad(ip)); } strlcpy(lp, ip->sepstring, line + sizeof(line) - lp); lp += strlen(lp); snprintf(lp, line + sizeof(line) - lp, ip->format, s); lp += strlen(lp); return (lp); } static void usage(void) { fprintf(stderr, "%s\n%s\n", "usage: lam [ -f min.max ] [ -s sepstring ] [ -t c ] file ...", " lam [ -p min.max ] [ -s sepstring ] [ -t c ] file ..."); exit(1); } Index: head/usr.bin/last/last.c =================================================================== --- head/usr.bin/last/last.c (revision 335394) +++ head/usr.bin/last/last.c (revision 335395) @@ -1,573 +1,573 @@ /* * SPDX-License-Identifier: BSD-3-Clause * * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1987, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static const char sccsid[] = "@(#)last.c 8.2 (Berkeley) 4/2/94"; #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define NO 0 /* false/no */ #define YES 1 /* true/yes */ #define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; typedef struct arg { char *name; /* argument */ #define REBOOT_TYPE -1 #define HOST_TYPE -2 #define TTY_TYPE -3 #define USER_TYPE -4 int type; /* type of arg */ struct arg *next; /* linked list pointer */ } ARG; static ARG *arglist; /* head of linked list */ static SLIST_HEAD(, idtab) idlist; struct idtab { time_t logout; /* log out time */ char id[sizeof ((struct utmpx *)0)->ut_id]; /* identifier */ SLIST_ENTRY(idtab) list; }; static const char *crmsg; /* cause of last reboot */ static time_t currentout; /* current logout value */ static long maxrec; /* records to display */ static const char *file = NULL; /* utx.log file */ static int sflag = 0; /* show delta in seconds */ static int width = 5; /* show seconds in delta */ static int yflag; /* show year */ static int d_first; static int snapfound = 0; /* found snapshot entry? */ static time_t snaptime; /* if != 0, we will only * report users logged in * at this snapshot time */ static void addarg(int, char *); static time_t dateconv(char *); static void doentry(struct utmpx *); static void hostconv(char *); static void printentry(struct utmpx *, struct idtab *); static char *ttyconv(char *); static int want(struct utmpx *); static void usage(void); static void wtmp(void); static void usage(void) { (void)fprintf(stderr, "usage: last [-swy] [-d [[CC]YY][MMDD]hhmm[.SS]] [-f file] [-h host]\n" " [-n maxrec] [-t tty] [user ...]\n"); exit(1); } int main(int argc, char *argv[]) { int ch; char *p; (void) setlocale(LC_TIME, ""); d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); maxrec = -1; snaptime = 0; while ((ch = getopt(argc, argv, "0123456789d:f:h:n:st:wy")) != -1) switch (ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* * kludge: last was originally designed to take * a number after a dash. */ if (maxrec == -1) { p = strchr(argv[optind - 1], ch); if (p == NULL) p = strchr(argv[optind], ch); maxrec = atol(p); if (!maxrec) exit(0); } break; case 'd': snaptime = dateconv(optarg); break; case 'f': file = optarg; break; case 'h': hostconv(optarg); addarg(HOST_TYPE, optarg); break; case 'n': errno = 0; maxrec = strtol(optarg, &p, 10); if (p == optarg || *p != '\0' || errno != 0 || maxrec <= 0) errx(1, "%s: bad line count", optarg); break; case 's': sflag++; /* Show delta as seconds */ break; case 't': addarg(TTY_TYPE, ttyconv(optarg)); break; case 'w': width = 8; break; case 'y': yflag++; break; case '?': default: usage(); } if (caph_limit_stdio() < 0) err(1, "can't limit stdio rights"); caph_cache_catpages(); caph_cache_tzdata(); /* Cache UTX database. */ if (setutxdb(UTXDB_LOG, file) != 0) err(1, "%s", file != NULL ? file : "(default utx db)"); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "cap_enter"); if (sflag && width == 8) usage(); if (argc) { setlinebuf(stdout); for (argv += optind; *argv; ++argv) { if (strcmp(*argv, "reboot") == 0) addarg(REBOOT_TYPE, *argv); #define COMPATIBILITY #ifdef COMPATIBILITY /* code to allow "last p5" to work */ addarg(TTY_TYPE, ttyconv(*argv)); #endif addarg(USER_TYPE, *argv); } } wtmp(); exit(0); } /* * wtmp -- * read through the utx.log file */ static void wtmp(void) { struct utmpx *buf = NULL; struct utmpx *ut; static unsigned int amount = 0; time_t t; char ct[80]; struct tm *tm; SLIST_INIT(&idlist); (void)time(&t); /* Load the last entries from the file. */ while ((ut = getutxent()) != NULL) { if (amount % 128 == 0) { buf = realloc(buf, (amount + 128) * sizeof *ut); if (buf == NULL) err(1, "realloc"); } memcpy(&buf[amount++], ut, sizeof *ut); if (t > ut->ut_tv.tv_sec) t = ut->ut_tv.tv_sec; } endutxent(); /* Display them in reverse order. */ while (amount > 0) doentry(&buf[--amount]); free(buf); tm = localtime(&t); (void) strftime(ct, sizeof(ct), "%+", tm); printf("\n%s begins %s\n", ((file == NULL) ? "utx.log" : file), ct); } /* * doentry -- * process a single utx.log entry */ static void doentry(struct utmpx *bp) { struct idtab *tt; /* the machine stopped */ if (bp->ut_type == BOOT_TIME || bp->ut_type == SHUTDOWN_TIME) { /* everybody just logged out */ while ((tt = SLIST_FIRST(&idlist)) != NULL) { SLIST_REMOVE_HEAD(&idlist, list); free(tt); } currentout = -bp->ut_tv.tv_sec; crmsg = bp->ut_type != SHUTDOWN_TIME ? "crash" : "shutdown"; /* * if we're in snapshot mode, we want to exit if this * shutdown/reboot appears while we we are tracking the * active range */ if (snaptime && snapfound) exit(0); /* * don't print shutdown/reboot entries unless flagged for */ if (!snaptime && want(bp)) printentry(bp, NULL); return; } /* date got set */ if (bp->ut_type == OLD_TIME || bp->ut_type == NEW_TIME) { if (want(bp) && !snaptime) printentry(bp, NULL); return; } if (bp->ut_type != USER_PROCESS && bp->ut_type != DEAD_PROCESS) return; /* find associated identifier */ SLIST_FOREACH(tt, &idlist, list) if (!memcmp(tt->id, bp->ut_id, sizeof bp->ut_id)) break; if (tt == NULL) { /* add new one */ tt = malloc(sizeof(struct idtab)); if (tt == NULL) errx(1, "malloc failure"); tt->logout = currentout; memcpy(tt->id, bp->ut_id, sizeof bp->ut_id); SLIST_INSERT_HEAD(&idlist, tt, list); } /* * print record if not in snapshot mode and wanted * or in snapshot mode and in snapshot range */ if (bp->ut_type == USER_PROCESS && (want(bp) || (bp->ut_tv.tv_sec < snaptime && (tt->logout > snaptime || tt->logout < 1)))) { snapfound = 1; printentry(bp, tt); } tt->logout = bp->ut_tv.tv_sec; } /* * printentry -- * output an entry * * If `tt' is non-NULL, use it and `crmsg' to print the logout time or * logout type (crash/shutdown) as appropriate. */ static void printentry(struct utmpx *bp, struct idtab *tt) { char ct[80]; struct tm *tm; time_t delta; /* time difference */ time_t t; if (maxrec != -1 && !maxrec--) exit(0); t = bp->ut_tv.tv_sec; tm = localtime(&t); (void) strftime(ct, sizeof(ct), d_first ? (yflag ? "%a %e %b %Y %R" : "%a %e %b %R") : (yflag ? "%a %b %e %Y %R" : "%a %b %e %R"), tm); switch (bp->ut_type) { case BOOT_TIME: printf("%-42s", "boot time"); break; case SHUTDOWN_TIME: printf("%-42s", "shutdown time"); break; case OLD_TIME: printf("%-42s", "old time"); break; case NEW_TIME: printf("%-42s", "new time"); break; case USER_PROCESS: printf("%-10s %-8s %-22.22s", bp->ut_user, bp->ut_line, bp->ut_host); break; } printf(" %s%c", ct, tt == NULL ? '\n' : ' '); if (tt == NULL) return; if (!tt->logout) { puts(" still logged in"); return; } if (tt->logout < 0) { tt->logout = -tt->logout; printf("- %s", crmsg); } else { tm = localtime(&tt->logout); (void) strftime(ct, sizeof(ct), "%R", tm); printf("- %s", ct); } delta = tt->logout - bp->ut_tv.tv_sec; if (sflag) { printf(" (%8ld)\n", (long)delta); } else { tm = gmtime(&delta); (void) strftime(ct, sizeof(ct), width >= 8 ? "%T" : "%R", tm); if (delta < 86400) printf(" (%s)\n", ct); else printf(" (%ld+%s)\n", (long)delta / 86400, ct); } } /* * want -- * see if want this entry */ static int want(struct utmpx *bp) { ARG *step; if (snaptime) return (NO); if (!arglist) return (YES); for (step = arglist; step; step = step->next) switch(step->type) { case REBOOT_TYPE: if (bp->ut_type == BOOT_TIME || bp->ut_type == SHUTDOWN_TIME) return (YES); break; case HOST_TYPE: if (!strcasecmp(step->name, bp->ut_host)) return (YES); break; case TTY_TYPE: if (!strcmp(step->name, bp->ut_line)) return (YES); break; case USER_TYPE: if (!strcmp(step->name, bp->ut_user)) return (YES); break; } return (NO); } /* * addarg -- * add an entry to a linked list of arguments */ static void addarg(int type, char *arg) { ARG *cur; if ((cur = malloc(sizeof(ARG))) == NULL) errx(1, "malloc failure"); cur->next = arglist; cur->type = type; cur->name = arg; arglist = cur; } /* * hostconv -- * convert the hostname to search pattern; if the supplied host name * has a domain attached that is the same as the current domain, rip * off the domain suffix since that's what login(1) does. */ static void hostconv(char *arg) { static int first = 1; static char *hostdot, name[MAXHOSTNAMELEN]; char *argdot; if (!(argdot = strchr(arg, '.'))) return; if (first) { first = 0; if (gethostname(name, sizeof(name))) err(1, "gethostname"); hostdot = strchr(name, '.'); } if (hostdot && !strcasecmp(hostdot, argdot)) *argdot = '\0'; } /* * ttyconv -- * convert tty to correct name. */ static char * ttyconv(char *arg) { char *mval; /* * kludge -- we assume that all tty's end with * a two character suffix. */ if (strlen(arg) == 2) { /* either 6 for "ttyxx" or 8 for "console" */ if ((mval = malloc(8)) == NULL) errx(1, "malloc failure"); if (!strcmp(arg, "co")) (void)strcpy(mval, "console"); else { (void)strcpy(mval, "tty"); (void)strcpy(mval + 3, arg); } return (mval); } if (!strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1)) return (arg + 5); return (arg); } /* * dateconv -- * Convert the snapshot time in command line given in the format * [[CC]YY]MMDDhhmm[.SS]] to a time_t. * Derived from atime_arg1() in usr.bin/touch/touch.c */ static time_t dateconv(char *arg) { time_t timet; struct tm *t; int yearset; char *p; /* Start with the current time. */ if (time(&timet) < 0) err(1, "time"); if ((t = localtime(&timet)) == NULL) err(1, "localtime"); /* [[CC]YY]MMDDhhmm[.SS] */ if ((p = strchr(arg, '.')) == NULL) t->tm_sec = 0; /* Seconds defaults to 0. */ else { if (strlen(p + 1) != 2) goto terr; *p++ = '\0'; t->tm_sec = ATOI2(p); } yearset = 0; switch (strlen(arg)) { case 12: /* CCYYMMDDhhmm */ t->tm_year = ATOI2(arg); t->tm_year *= 100; yearset = 1; /* FALLTHROUGH */ case 10: /* YYMMDDhhmm */ if (yearset) { yearset = ATOI2(arg); t->tm_year += yearset; } else { yearset = ATOI2(arg); if (yearset < 69) t->tm_year = yearset + 2000; else t->tm_year = yearset + 1900; } t->tm_year -= 1900; /* Convert to UNIX time. */ /* FALLTHROUGH */ case 8: /* MMDDhhmm */ t->tm_mon = ATOI2(arg); --t->tm_mon; /* Convert from 01-12 to 00-11 */ t->tm_mday = ATOI2(arg); t->tm_hour = ATOI2(arg); t->tm_min = ATOI2(arg); break; case 4: /* hhmm */ t->tm_hour = ATOI2(arg); t->tm_min = ATOI2(arg); break; default: goto terr; } t->tm_isdst = -1; /* Figure out DST. */ timet = mktime(t); if (timet == -1) terr: errx(1, "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]"); return timet; } Index: head/usr.bin/locate/bigram/locate.bigram.c =================================================================== --- head/usr.bin/locate/bigram/locate.bigram.c (revision 335394) +++ head/usr.bin/locate/bigram/locate.bigram.c (revision 335395) @@ -1,120 +1,119 @@ /* * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 1995 Wolfram Schneider . Berlin. * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * James A. Woods. * * 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. * * $FreeBSD$ */ #if 0 #ifndef lint static char copyright[] = "@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)locate.bigram.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #endif /* * bigram < sorted_file_names | sort -nr | * awk 'NR <= 128 { printf $2 }' > bigrams * * List bigrams for 'updatedb' script. * Use 'code' to encode a file using this output. */ #include #include -#include #include #include #include /* for MAXPATHLEN */ #include "locate.h" u_char buf1[MAXPATHLEN] = " "; u_char buf2[MAXPATHLEN]; u_int bigram[UCHAR_MAX + 1][UCHAR_MAX + 1]; int main(void) { u_char *cp; u_char *oldpath = buf1, *path = buf2; u_int i, j; - if (caph_limit_stdio() < 0 || (cap_enter() < 0 && errno != ENOSYS)) + if (caph_limit_stdio() < 0 || caph_enter() < 0) err(1, "capsicum"); while (fgets(path, sizeof(buf2), stdin) != NULL) { /* * We don't need remove newline character '\n'. * '\n' is less than ASCII_MIN and will be later * ignored at output. */ /* skip longest common prefix */ for (cp = path; *cp == *oldpath; cp++, oldpath++) if (*cp == '\0') break; while (*cp != '\0' && *(cp + 1) != '\0') { bigram[(u_char)*cp][(u_char)*(cp + 1)]++; cp += 2; } /* swap pointers */ if (path == buf1) { path = buf2; oldpath = buf1; } else { path = buf1; oldpath = buf2; } } /* output, boundary check */ for (i = ASCII_MIN; i <= ASCII_MAX; i++) for (j = ASCII_MIN; j <= ASCII_MAX; j++) if (bigram[i][j] != 0) (void)printf("%4u %c%c\n", bigram[i][j], i, j); exit(0); } Index: head/usr.bin/logname/logname.c =================================================================== --- head/usr.bin/logname/logname.c (revision 335394) +++ head/usr.bin/logname/logname.c (revision 335395) @@ -1,73 +1,73 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1991, 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1991, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static const char sccsid[] = "@(#)logname.c 8.2 (Berkeley) 4/3/94"; #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include void usage(void); int main(int argc, char *argv[] __unused) { char *p; - if (caph_limit_stdio() < 0 || (cap_enter() < 0 && errno != ENOSYS)) + if (caph_limit_stdio() < 0 || caph_enter() < 0) err(1, "capsicum"); if (argc != 1) usage(); if ((p = getlogin()) == NULL) err(1, NULL); (void)printf("%s\n", p); exit(0); } void usage(void) { (void)fprintf(stderr, "usage: logname\n"); exit(1); } Index: head/usr.bin/ministat/ministat.c =================================================================== --- head/usr.bin/ministat/ministat.c (revision 335394) +++ head/usr.bin/ministat/ministat.c (revision 335395) @@ -1,664 +1,664 @@ /*- * SPDX-License-Identifier: Beerware * * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #define NSTUDENT 100 #define NCONF 6 static double const studentpct[] = { 80, 90, 95, 98, 99, 99.5 }; static double student[NSTUDENT + 1][NCONF] = { /* inf */ { 1.282, 1.645, 1.960, 2.326, 2.576, 3.090 }, /* 1. */ { 3.078, 6.314, 12.706, 31.821, 63.657, 318.313 }, /* 2. */ { 1.886, 2.920, 4.303, 6.965, 9.925, 22.327 }, /* 3. */ { 1.638, 2.353, 3.182, 4.541, 5.841, 10.215 }, /* 4. */ { 1.533, 2.132, 2.776, 3.747, 4.604, 7.173 }, /* 5. */ { 1.476, 2.015, 2.571, 3.365, 4.032, 5.893 }, /* 6. */ { 1.440, 1.943, 2.447, 3.143, 3.707, 5.208 }, /* 7. */ { 1.415, 1.895, 2.365, 2.998, 3.499, 4.782 }, /* 8. */ { 1.397, 1.860, 2.306, 2.896, 3.355, 4.499 }, /* 9. */ { 1.383, 1.833, 2.262, 2.821, 3.250, 4.296 }, /* 10. */ { 1.372, 1.812, 2.228, 2.764, 3.169, 4.143 }, /* 11. */ { 1.363, 1.796, 2.201, 2.718, 3.106, 4.024 }, /* 12. */ { 1.356, 1.782, 2.179, 2.681, 3.055, 3.929 }, /* 13. */ { 1.350, 1.771, 2.160, 2.650, 3.012, 3.852 }, /* 14. */ { 1.345, 1.761, 2.145, 2.624, 2.977, 3.787 }, /* 15. */ { 1.341, 1.753, 2.131, 2.602, 2.947, 3.733 }, /* 16. */ { 1.337, 1.746, 2.120, 2.583, 2.921, 3.686 }, /* 17. */ { 1.333, 1.740, 2.110, 2.567, 2.898, 3.646 }, /* 18. */ { 1.330, 1.734, 2.101, 2.552, 2.878, 3.610 }, /* 19. */ { 1.328, 1.729, 2.093, 2.539, 2.861, 3.579 }, /* 20. */ { 1.325, 1.725, 2.086, 2.528, 2.845, 3.552 }, /* 21. */ { 1.323, 1.721, 2.080, 2.518, 2.831, 3.527 }, /* 22. */ { 1.321, 1.717, 2.074, 2.508, 2.819, 3.505 }, /* 23. */ { 1.319, 1.714, 2.069, 2.500, 2.807, 3.485 }, /* 24. */ { 1.318, 1.711, 2.064, 2.492, 2.797, 3.467 }, /* 25. */ { 1.316, 1.708, 2.060, 2.485, 2.787, 3.450 }, /* 26. */ { 1.315, 1.706, 2.056, 2.479, 2.779, 3.435 }, /* 27. */ { 1.314, 1.703, 2.052, 2.473, 2.771, 3.421 }, /* 28. */ { 1.313, 1.701, 2.048, 2.467, 2.763, 3.408 }, /* 29. */ { 1.311, 1.699, 2.045, 2.462, 2.756, 3.396 }, /* 30. */ { 1.310, 1.697, 2.042, 2.457, 2.750, 3.385 }, /* 31. */ { 1.309, 1.696, 2.040, 2.453, 2.744, 3.375 }, /* 32. */ { 1.309, 1.694, 2.037, 2.449, 2.738, 3.365 }, /* 33. */ { 1.308, 1.692, 2.035, 2.445, 2.733, 3.356 }, /* 34. */ { 1.307, 1.691, 2.032, 2.441, 2.728, 3.348 }, /* 35. */ { 1.306, 1.690, 2.030, 2.438, 2.724, 3.340 }, /* 36. */ { 1.306, 1.688, 2.028, 2.434, 2.719, 3.333 }, /* 37. */ { 1.305, 1.687, 2.026, 2.431, 2.715, 3.326 }, /* 38. */ { 1.304, 1.686, 2.024, 2.429, 2.712, 3.319 }, /* 39. */ { 1.304, 1.685, 2.023, 2.426, 2.708, 3.313 }, /* 40. */ { 1.303, 1.684, 2.021, 2.423, 2.704, 3.307 }, /* 41. */ { 1.303, 1.683, 2.020, 2.421, 2.701, 3.301 }, /* 42. */ { 1.302, 1.682, 2.018, 2.418, 2.698, 3.296 }, /* 43. */ { 1.302, 1.681, 2.017, 2.416, 2.695, 3.291 }, /* 44. */ { 1.301, 1.680, 2.015, 2.414, 2.692, 3.286 }, /* 45. */ { 1.301, 1.679, 2.014, 2.412, 2.690, 3.281 }, /* 46. */ { 1.300, 1.679, 2.013, 2.410, 2.687, 3.277 }, /* 47. */ { 1.300, 1.678, 2.012, 2.408, 2.685, 3.273 }, /* 48. */ { 1.299, 1.677, 2.011, 2.407, 2.682, 3.269 }, /* 49. */ { 1.299, 1.677, 2.010, 2.405, 2.680, 3.265 }, /* 50. */ { 1.299, 1.676, 2.009, 2.403, 2.678, 3.261 }, /* 51. */ { 1.298, 1.675, 2.008, 2.402, 2.676, 3.258 }, /* 52. */ { 1.298, 1.675, 2.007, 2.400, 2.674, 3.255 }, /* 53. */ { 1.298, 1.674, 2.006, 2.399, 2.672, 3.251 }, /* 54. */ { 1.297, 1.674, 2.005, 2.397, 2.670, 3.248 }, /* 55. */ { 1.297, 1.673, 2.004, 2.396, 2.668, 3.245 }, /* 56. */ { 1.297, 1.673, 2.003, 2.395, 2.667, 3.242 }, /* 57. */ { 1.297, 1.672, 2.002, 2.394, 2.665, 3.239 }, /* 58. */ { 1.296, 1.672, 2.002, 2.392, 2.663, 3.237 }, /* 59. */ { 1.296, 1.671, 2.001, 2.391, 2.662, 3.234 }, /* 60. */ { 1.296, 1.671, 2.000, 2.390, 2.660, 3.232 }, /* 61. */ { 1.296, 1.670, 2.000, 2.389, 2.659, 3.229 }, /* 62. */ { 1.295, 1.670, 1.999, 2.388, 2.657, 3.227 }, /* 63. */ { 1.295, 1.669, 1.998, 2.387, 2.656, 3.225 }, /* 64. */ { 1.295, 1.669, 1.998, 2.386, 2.655, 3.223 }, /* 65. */ { 1.295, 1.669, 1.997, 2.385, 2.654, 3.220 }, /* 66. */ { 1.295, 1.668, 1.997, 2.384, 2.652, 3.218 }, /* 67. */ { 1.294, 1.668, 1.996, 2.383, 2.651, 3.216 }, /* 68. */ { 1.294, 1.668, 1.995, 2.382, 2.650, 3.214 }, /* 69. */ { 1.294, 1.667, 1.995, 2.382, 2.649, 3.213 }, /* 70. */ { 1.294, 1.667, 1.994, 2.381, 2.648, 3.211 }, /* 71. */ { 1.294, 1.667, 1.994, 2.380, 2.647, 3.209 }, /* 72. */ { 1.293, 1.666, 1.993, 2.379, 2.646, 3.207 }, /* 73. */ { 1.293, 1.666, 1.993, 2.379, 2.645, 3.206 }, /* 74. */ { 1.293, 1.666, 1.993, 2.378, 2.644, 3.204 }, /* 75. */ { 1.293, 1.665, 1.992, 2.377, 2.643, 3.202 }, /* 76. */ { 1.293, 1.665, 1.992, 2.376, 2.642, 3.201 }, /* 77. */ { 1.293, 1.665, 1.991, 2.376, 2.641, 3.199 }, /* 78. */ { 1.292, 1.665, 1.991, 2.375, 2.640, 3.198 }, /* 79. */ { 1.292, 1.664, 1.990, 2.374, 2.640, 3.197 }, /* 80. */ { 1.292, 1.664, 1.990, 2.374, 2.639, 3.195 }, /* 81. */ { 1.292, 1.664, 1.990, 2.373, 2.638, 3.194 }, /* 82. */ { 1.292, 1.664, 1.989, 2.373, 2.637, 3.193 }, /* 83. */ { 1.292, 1.663, 1.989, 2.372, 2.636, 3.191 }, /* 84. */ { 1.292, 1.663, 1.989, 2.372, 2.636, 3.190 }, /* 85. */ { 1.292, 1.663, 1.988, 2.371, 2.635, 3.189 }, /* 86. */ { 1.291, 1.663, 1.988, 2.370, 2.634, 3.188 }, /* 87. */ { 1.291, 1.663, 1.988, 2.370, 2.634, 3.187 }, /* 88. */ { 1.291, 1.662, 1.987, 2.369, 2.633, 3.185 }, /* 89. */ { 1.291, 1.662, 1.987, 2.369, 2.632, 3.184 }, /* 90. */ { 1.291, 1.662, 1.987, 2.368, 2.632, 3.183 }, /* 91. */ { 1.291, 1.662, 1.986, 2.368, 2.631, 3.182 }, /* 92. */ { 1.291, 1.662, 1.986, 2.368, 2.630, 3.181 }, /* 93. */ { 1.291, 1.661, 1.986, 2.367, 2.630, 3.180 }, /* 94. */ { 1.291, 1.661, 1.986, 2.367, 2.629, 3.179 }, /* 95. */ { 1.291, 1.661, 1.985, 2.366, 2.629, 3.178 }, /* 96. */ { 1.290, 1.661, 1.985, 2.366, 2.628, 3.177 }, /* 97. */ { 1.290, 1.661, 1.985, 2.365, 2.627, 3.176 }, /* 98. */ { 1.290, 1.661, 1.984, 2.365, 2.627, 3.175 }, /* 99. */ { 1.290, 1.660, 1.984, 2.365, 2.626, 3.175 }, /* 100. */ { 1.290, 1.660, 1.984, 2.364, 2.626, 3.174 } }; #define MAX_DS 8 static char symbol[MAX_DS] = { ' ', 'x', '+', '*', '%', '#', '@', 'O' }; struct dataset { char *name; double *points; unsigned lpoints; double sy, syy; unsigned n; }; static struct dataset * NewSet(void) { struct dataset *ds; ds = calloc(1, sizeof *ds); ds->lpoints = 100000; ds->points = calloc(sizeof *ds->points, ds->lpoints); return(ds); } static void AddPoint(struct dataset *ds, double a) { double *dp; if (ds->n >= ds->lpoints) { dp = ds->points; ds->lpoints *= 4; ds->points = calloc(sizeof *ds->points, ds->lpoints); memcpy(ds->points, dp, sizeof *dp * ds->n); free(dp); } ds->points[ds->n++] = a; ds->sy += a; ds->syy += a * a; } static double Min(struct dataset *ds) { return (ds->points[0]); } static double Max(struct dataset *ds) { return (ds->points[ds->n -1]); } static double Avg(struct dataset *ds) { return(ds->sy / ds->n); } static double Median(struct dataset *ds) { if ((ds->n % 2) == 0) return ((ds->points[ds->n / 2] + (ds->points[(ds->n / 2) - 1])) / 2); else return (ds->points[ds->n / 2]); } static double Var(struct dataset *ds) { /* * Due to limited precision it is possible that sy^2/n > syy, * but variance cannot actually be negative. */ if (ds->syy <= ds->sy * ds->sy / ds->n) return (0); return (ds->syy - ds->sy * ds->sy / ds->n) / (ds->n - 1.0); } static double Stddev(struct dataset *ds) { return sqrt(Var(ds)); } static void VitalsHead(void) { printf(" N Min Max Median Avg Stddev\n"); } static void Vitals(struct dataset *ds, int flag) { printf("%c %3d %13.8g %13.8g %13.8g %13.8g %13.8g", symbol[flag], ds->n, Min(ds), Max(ds), Median(ds), Avg(ds), Stddev(ds)); printf("\n"); } static void Relative(struct dataset *ds, struct dataset *rs, int confidx) { double spool, s, d, e, t; double re; int i; i = ds->n + rs->n - 2; if (i > NSTUDENT) t = student[0][confidx]; else t = student[i][confidx]; spool = (ds->n - 1) * Var(ds) + (rs->n - 1) * Var(rs); spool /= ds->n + rs->n - 2; spool = sqrt(spool); s = spool * sqrt(1.0 / ds->n + 1.0 / rs->n); d = Avg(ds) - Avg(rs); e = t * s; re = (ds->n - 1) * Var(ds) + (rs->n - 1) * Var(rs) * (Avg(ds) * Avg(ds)) / (Avg(rs) * Avg(rs)); re *= (ds->n + rs->n) / (ds->n * rs->n * (ds->n + rs->n - 2.0)); re = t * sqrt(re); if (fabs(d) > e) { printf("Difference at %.1f%% confidence\n", studentpct[confidx]); printf(" %g +/- %g\n", d, e); printf(" %g%% +/- %g%%\n", d * 100 / Avg(rs), re * 100 / Avg(rs)); printf(" (Student's t, pooled s = %g)\n", spool); } else { printf("No difference proven at %.1f%% confidence\n", studentpct[confidx]); } } struct plot { double min; double max; double span; int width; double x0, dx; int height; char *data; char **bar; int separate_bars; int num_datasets; }; static struct plot plot; static void SetupPlot(int width, int separate, int num_datasets) { struct plot *pl; pl = &plot; pl->width = width; pl->height = 0; pl->data = NULL; pl->bar = NULL; pl->separate_bars = separate; pl->num_datasets = num_datasets; pl->min = 999e99; pl->max = -999e99; } static void AdjPlot(double a) { struct plot *pl; pl = &plot; if (a < pl->min) pl->min = a; if (a > pl->max) pl->max = a; pl->span = pl->max - pl->min; pl->dx = pl->span / (pl->width - 1.0); pl->x0 = pl->min - .5 * pl->dx; } static void DimPlot(struct dataset *ds) { AdjPlot(Min(ds)); AdjPlot(Max(ds)); AdjPlot(Avg(ds) - Stddev(ds)); AdjPlot(Avg(ds) + Stddev(ds)); } static void PlotSet(struct dataset *ds, int val) { struct plot *pl; int i, j, m, x; unsigned n; int bar; pl = &plot; if (pl->span == 0) return; if (pl->separate_bars) bar = val-1; else bar = 0; if (pl->bar == NULL) pl->bar = calloc(sizeof(char *), pl->num_datasets); if (pl->bar[bar] == NULL) { pl->bar[bar] = malloc(pl->width); memset(pl->bar[bar], 0, pl->width); } m = 1; i = -1; j = 0; for (n = 0; n < ds->n; n++) { x = (ds->points[n] - pl->x0) / pl->dx; if (x == i) { j++; if (j > m) m = j; } else { j = 1; i = x; } } m += 1; if (m > pl->height) { pl->data = realloc(pl->data, pl->width * m); memset(pl->data + pl->height * pl->width, 0, (m - pl->height) * pl->width); } pl->height = m; i = -1; for (n = 0; n < ds->n; n++) { x = (ds->points[n] - pl->x0) / pl->dx; if (x == i) { j++; } else { j = 1; i = x; } pl->data[j * pl->width + x] |= val; } if (!isnan(Stddev(ds))) { x = ((Avg(ds) - Stddev(ds)) - pl->x0) / pl->dx; m = ((Avg(ds) + Stddev(ds)) - pl->x0) / pl->dx; pl->bar[bar][m] = '|'; pl->bar[bar][x] = '|'; for (i = x + 1; i < m; i++) if (pl->bar[bar][i] == 0) pl->bar[bar][i] = '_'; } x = (Median(ds) - pl->x0) / pl->dx; pl->bar[bar][x] = 'M'; x = (Avg(ds) - pl->x0) / pl->dx; pl->bar[bar][x] = 'A'; } static void DumpPlot(void) { struct plot *pl; int i, j, k; pl = &plot; if (pl->span == 0) { printf("[no plot, span is zero width]\n"); return; } putchar('+'); for (i = 0; i < pl->width; i++) putchar('-'); putchar('+'); putchar('\n'); for (i = 1; i < pl->height; i++) { putchar('|'); for (j = 0; j < pl->width; j++) { k = pl->data[(pl->height - i) * pl->width + j]; if (k >= 0 && k < MAX_DS) putchar(symbol[k]); else printf("[%02x]", k); } putchar('|'); putchar('\n'); } for (i = 0; i < pl->num_datasets; i++) { if (pl->bar[i] == NULL) continue; putchar('|'); for (j = 0; j < pl->width; j++) { k = pl->bar[i][j]; if (k == 0) k = ' '; putchar(k); } putchar('|'); putchar('\n'); } putchar('+'); for (i = 0; i < pl->width; i++) putchar('-'); putchar('+'); putchar('\n'); } static int dbl_cmp(const void *a, const void *b) { const double *aa = a; const double *bb = b; if (*aa < *bb) return (-1); else if (*aa > *bb) return (1); else return (0); } static struct dataset * ReadSet(FILE *f, const char *n, int column, const char *delim) { char buf[BUFSIZ], *p, *t; struct dataset *s; double d; int line; int i; s = NewSet(); s->name = strdup(n); line = 0; while (fgets(buf, sizeof buf, f) != NULL) { line++; i = strlen(buf); while (i > 0 && isspace(buf[i - 1])) buf[--i] = '\0'; for (i = 1, t = strtok(buf, delim); t != NULL && *t != '#'; i++, t = strtok(NULL, delim)) { if (i == column) break; } if (t == NULL || *t == '#') continue; d = strtod(t, &p); if (p != NULL && *p != '\0') errx(2, "Invalid data on line %d in %s", line, n); if (*buf != '\0') AddPoint(s, d); } if (s->n < 3) { fprintf(stderr, "Dataset %s must contain at least 3 data points\n", n); exit (2); } qsort(s->points, s->n, sizeof *s->points, dbl_cmp); return (s); } static void usage(char const *whine) { int i; fprintf(stderr, "%s\n", whine); fprintf(stderr, "Usage: ministat [-C column] [-c confidence] [-d delimiter(s)] [-Ans] [-w width] [file [file ...]]\n"); fprintf(stderr, "\tconfidence = {"); for (i = 0; i < NCONF; i++) { fprintf(stderr, "%s%g%%", i ? ", " : "", studentpct[i]); } fprintf(stderr, "}\n"); fprintf(stderr, "\t-A : print statistics only. suppress the graph.\n"); fprintf(stderr, "\t-C : column number to extract (starts and defaults to 1)\n"); fprintf(stderr, "\t-d : delimiter(s) string, default to \" \\t\"\n"); fprintf(stderr, "\t-n : print summary statistics only, no graph/test\n"); fprintf(stderr, "\t-s : print avg/median/stddev bars on separate lines\n"); fprintf(stderr, "\t-w : width of graph/test output (default 74 or terminal width)\n"); exit (2); } int main(int argc, char **argv) { const char *setfilenames[MAX_DS - 1]; struct dataset *ds[MAX_DS - 1]; FILE *setfiles[MAX_DS - 1]; int nds; double a; const char *delim = " \t"; char *p; int c, i, ci; int column = 1; int flag_s = 0; int flag_n = 0; int termwidth = 74; int suppress_plot = 0; if (isatty(STDOUT_FILENO)) { struct winsize wsz; if ((p = getenv("COLUMNS")) != NULL && *p != '\0') termwidth = atoi(p); else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &wsz) != -1 && wsz.ws_col > 0) termwidth = wsz.ws_col - 2; } ci = -1; while ((c = getopt(argc, argv, "AC:c:d:snw:")) != -1) switch (c) { case 'A': suppress_plot = 1; break; case 'C': column = strtol(optarg, &p, 10); if (p != NULL && *p != '\0') usage("Invalid column number."); if (column <= 0) usage("Column number should be positive."); break; case 'c': a = strtod(optarg, &p); if (p != NULL && *p != '\0') usage("Not a floating point number"); for (i = 0; i < NCONF; i++) if (a == studentpct[i]) ci = i; if (ci == -1) usage("No support for confidence level"); break; case 'd': if (*optarg == '\0') usage("Can't use empty delimiter string"); delim = optarg; break; case 'n': flag_n = 1; break; case 's': flag_s = 1; break; case 'w': termwidth = strtol(optarg, &p, 10); if (p != NULL && *p != '\0') usage("Invalid width, not a number."); if (termwidth < 0) usage("Unable to move beyond left margin."); break; default: usage("Unknown option"); break; } if (ci == -1) ci = 2; argc -= optind; argv += optind; if (argc == 0) { setfilenames[0] = ""; setfiles[0] = stdin; nds = 1; } else { if (argc > (MAX_DS - 1)) usage("Too many datasets."); nds = argc; for (i = 0; i < nds; i++) { setfilenames[i] = argv[i]; setfiles[i] = fopen(argv[i], "r"); if (setfiles[i] == NULL) err(2, "Cannot open %s", argv[i]); } } if (caph_limit_stdio() < 0) err(2, "capsicum"); for (i = 0; i < nds; i++) if (caph_limit_stream(fileno(setfiles[i]), CAPH_READ) < 0) err(2, "unable to limit rights for %s", setfilenames[i]); /* Enter Capsicum sandbox. */ - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(2, "unable to enter capability mode"); for (i = 0; i < nds; i++) { ds[i] = ReadSet(setfiles[i], setfilenames[i], column, delim); fclose(setfiles[i]); } for (i = 0; i < nds; i++) printf("%c %s\n", symbol[i+1], ds[i]->name); if (!flag_n && !suppress_plot) { SetupPlot(termwidth, flag_s, nds); for (i = 0; i < nds; i++) DimPlot(ds[i]); for (i = 0; i < nds; i++) PlotSet(ds[i], i + 1); DumpPlot(); } VitalsHead(); Vitals(ds[0], 1); for (i = 1; i < nds; i++) { Vitals(ds[i], i + 1); if (!flag_n) Relative(ds[i], ds[0], ci); } exit(0); } Index: head/usr.bin/pom/pom.c =================================================================== --- head/usr.bin/pom/pom.c (revision 335394) +++ head/usr.bin/pom/pom.c (revision 335395) @@ -1,253 +1,253 @@ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software posted to USENET. * * 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. */ #if 0 #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static const char sccsid[] = "@(#)pom.c 8.1 (Berkeley) 5/31/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); /* * Phase of the Moon. Calculates the current phase of the moon. * Based on routines from `Practical Astronomy with Your Calculator', * by Duffett-Smith. Comments give the section from the book that * particular piece of code was adapted from. * * -- Keith E. Brandt VIII 1984 * */ #include #include #include #include #include #include #include #include #include #include #include #ifndef PI #define PI 3.14159265358979323846 #endif #define EPOCH 85 #define EPSILONg 279.611371 /* solar ecliptic long at EPOCH */ #define RHOg 282.680403 /* solar ecliptic long of perigee at EPOCH */ #define ECCEN 0.01671542 /* solar orbit eccentricity */ #define lzero 18.251907 /* lunar mean long at EPOCH */ #define Pzero 192.917585 /* lunar mean long of perigee at EPOCH */ #define Nzero 55.204723 /* lunar mean long of node at EPOCH */ #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) static void adj360(double *); static double dtor(double); static double potm(double); static void usage(char *progname); int main(int argc, char **argv) { time_t tt; struct tm GMT, tmd; double days, today, tomorrow; int ch, cnt, pflag = 0; char *odate = NULL, *otime = NULL; char *progname = argv[0]; if (caph_limit_stdio() < 0) err(1, "unable to limit capabitilities for stdio"); caph_cache_catpages(); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "unable to enter capability mode"); while ((ch = getopt(argc, argv, "d:pt:")) != -1) switch (ch) { case 'd': odate = optarg; break; case 'p': pflag = 1; break; case 't': otime = optarg; break; default: usage(progname); } argc -= optind; argv += optind; if (argc) usage(progname); /* Adjust based on users preferences */ time(&tt); if (otime != NULL || odate != NULL) { /* Save today in case -d isn't specified */ localtime_r(&tt, &tmd); if (odate != NULL) { tmd.tm_year = strtol(odate, NULL, 10) - 1900; tmd.tm_mon = strtol(odate + 5, NULL, 10) - 1; tmd.tm_mday = strtol(odate + 8, NULL, 10); /* Use midnight as the middle of the night */ tmd.tm_hour = 0; tmd.tm_min = 0; tmd.tm_sec = 0; } if (otime != NULL) { tmd.tm_hour = strtol(otime, NULL, 10); tmd.tm_min = strtol(otime + 3, NULL, 10); tmd.tm_sec = strtol(otime + 6, NULL, 10); } tt = mktime(&tmd); } gmtime_r(&tt, &GMT); days = (GMT.tm_yday + 1) + ((GMT.tm_hour + (GMT.tm_min / 60.0) + (GMT.tm_sec / 3600.0)) / 24.0); for (cnt = EPOCH; cnt < GMT.tm_year; ++cnt) days += isleap(1900 + cnt) ? 366 : 365; today = potm(days) + .5; if (pflag) { (void)printf("%1.0f\n", today); return (0); } (void)printf("The Moon is "); if ((int)today == 100) (void)printf("Full\n"); else if (!(int)today) (void)printf("New\n"); else { tomorrow = potm(days + 1); if ((int)today == 50) (void)printf("%s\n", tomorrow > today ? "at the First Quarter" : "at the Last Quarter"); else { (void)printf("%s ", tomorrow > today ? "Waxing" : "Waning"); if (today > 50) (void)printf("Gibbous (%1.0f%% of Full)\n", today); else if (today < 50) (void)printf("Crescent (%1.0f%% of Full)\n", today); } } return 0; } /* * potm -- * return phase of the moon */ static double potm(double days) { double N, Msol, Ec, LambdaSol, l, Mm, Ev, Ac, A3, Mmprime; double A4, lprime, V, ldprime, D, Nm; N = 360 * days / 365.2422; /* sec 42 #3 */ adj360(&N); Msol = N + EPSILONg - RHOg; /* sec 42 #4 */ adj360(&Msol); Ec = 360 / PI * ECCEN * sin(dtor(Msol)); /* sec 42 #5 */ LambdaSol = N + Ec + EPSILONg; /* sec 42 #6 */ adj360(&LambdaSol); l = 13.1763966 * days + lzero; /* sec 61 #4 */ adj360(&l); Mm = l - (0.1114041 * days) - Pzero; /* sec 61 #5 */ adj360(&Mm); Nm = Nzero - (0.0529539 * days); /* sec 61 #6 */ adj360(&Nm); Ev = 1.2739 * sin(dtor(2*(l - LambdaSol) - Mm)); /* sec 61 #7 */ Ac = 0.1858 * sin(dtor(Msol)); /* sec 61 #8 */ A3 = 0.37 * sin(dtor(Msol)); Mmprime = Mm + Ev - Ac - A3; /* sec 61 #9 */ Ec = 6.2886 * sin(dtor(Mmprime)); /* sec 61 #10 */ A4 = 0.214 * sin(dtor(2 * Mmprime)); /* sec 61 #11 */ lprime = l + Ev + Ec - Ac + A4; /* sec 61 #12 */ V = 0.6583 * sin(dtor(2 * (lprime - LambdaSol))); /* sec 61 #13 */ ldprime = lprime + V; /* sec 61 #14 */ D = ldprime - LambdaSol; /* sec 63 #2 */ return(50 * (1 - cos(dtor(D)))); /* sec 63 #3 */ } /* * dtor -- * convert degrees to radians */ static double dtor(double deg) { return(deg * PI / 180); } /* * adj360 -- * adjust value so 0 <= deg <= 360 */ static void adj360(double *deg) { for (;;) if (*deg < 0) *deg += 360; else if (*deg > 360) *deg -= 360; else break; } static void usage(char *progname) { fprintf(stderr, "Usage: %s [-p] [-d yyyy.mm.dd] [-t hh:mm:ss]\n", progname); exit(EX_USAGE); } Index: head/usr.bin/primes/primes.c =================================================================== --- head/usr.bin/primes/primes.c (revision 335394) +++ head/usr.bin/primes/primes.c (revision 335395) @@ -1,331 +1,331 @@ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Landon Curt Noll. * * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)primes.c 8.5 (Berkeley) 5/10/95"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ /* * primes - generate a table of primes between two values * * By: Landon Curt Noll chongo@toad.com, ...!{sun,tolsoft}!hoptoad!chongo * * chongo /\oo/\ * * usage: * primes [-h] [start [stop]] * * Print primes >= start and < stop. If stop is omitted, * the value 4294967295 (2^32-1) is assumed. If start is * omitted, start is read from standard input. * * validation check: there are 664579 primes between 0 and 10^7 */ -#include +#include #include #include #include #include #include #include #include #include #include #include #include #include "primes.h" /* * Eratosthenes sieve table * * We only sieve the odd numbers. The base of our sieve windows are always * odd. If the base of table is 1, table[i] represents 2*i-1. After the * sieve, table[i] == 1 if and only if 2*i-1 is prime. * * We make TABSIZE large to reduce the overhead of inner loop setup. */ static char table[TABSIZE]; /* Eratosthenes sieve of odd numbers */ static int hflag; static void primes(ubig, ubig); static ubig read_num_buf(void); static void usage(void); int main(int argc, char *argv[]) { ubig start; /* where to start generating */ ubig stop; /* don't generate at or above this value */ int ch; char *p; /* Cache NLS data, for strerror, for err(3), before cap_enter. */ (void)catopen("libc", NL_CAT_LOCALE); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "cap_enter"); while ((ch = getopt(argc, argv, "h")) != -1) switch (ch) { case 'h': hflag++; break; case '?': default: usage(); } argc -= optind; argv += optind; start = 0; stop = (uint64_t)(-1); /* * Convert low and high args. Strtoumax(3) sets errno to * ERANGE if the number is too large, but, if there's * a leading minus sign it returns the negation of the * result of the conversion, which we'd rather disallow. */ switch (argc) { case 2: /* Start and stop supplied on the command line. */ if (argv[0][0] == '-' || argv[1][0] == '-') errx(1, "negative numbers aren't permitted."); errno = 0; start = strtoumax(argv[0], &p, 0); if (errno) err(1, "%s", argv[0]); if (*p != '\0') errx(1, "%s: illegal numeric format.", argv[0]); errno = 0; stop = strtoumax(argv[1], &p, 0); if (errno) err(1, "%s", argv[1]); if (*p != '\0') errx(1, "%s: illegal numeric format.", argv[1]); break; case 1: /* Start on the command line. */ if (argv[0][0] == '-') errx(1, "negative numbers aren't permitted."); errno = 0; start = strtoumax(argv[0], &p, 0); if (errno) err(1, "%s", argv[0]); if (*p != '\0') errx(1, "%s: illegal numeric format.", argv[0]); break; case 0: start = read_num_buf(); break; default: usage(); } if (start > stop) errx(1, "start value must be less than stop value."); primes(start, stop); return (0); } /* * read_num_buf -- * This routine returns a number n, where 0 <= n && n <= BIG. */ static ubig read_num_buf(void) { ubig val; char *p, buf[LINE_MAX]; /* > max number of digits. */ for (;;) { if (fgets(buf, sizeof(buf), stdin) == NULL) { if (ferror(stdin)) err(1, "stdin"); exit(0); } for (p = buf; isblank(*p); ++p); if (*p == '\n' || *p == '\0') continue; if (*p == '-') errx(1, "negative numbers aren't permitted."); errno = 0; val = strtoumax(buf, &p, 0); if (errno) err(1, "%s", buf); if (*p != '\n') errx(1, "%s: illegal numeric format.", buf); return (val); } } /* * primes - sieve and print primes from start up to and but not including stop */ static void primes(ubig start, ubig stop) { char *q; /* sieve spot */ ubig factor; /* index and factor */ char *tab_lim; /* the limit to sieve on the table */ const ubig *p; /* prime table pointer */ ubig fact_lim; /* highest prime for current block */ ubig mod; /* temp storage for mod */ /* * A number of systems can not convert double values into unsigned * longs when the values are larger than the largest signed value. * We don't have this problem, so we can go all the way to BIG. */ if (start < 3) { start = (ubig)2; } if (stop < 3) { stop = (ubig)2; } if (stop <= start) { return; } /* * be sure that the values are odd, or 2 */ if (start != 2 && (start&0x1) == 0) { ++start; } if (stop != 2 && (stop&0x1) == 0) { ++stop; } /* * quick list of primes <= pr_limit */ if (start <= *pr_limit) { /* skip primes up to the start value */ for (p = &prime[0], factor = prime[0]; factor < stop && p <= pr_limit; factor = *(++p)) { if (factor >= start) { printf(hflag ? "%" PRIx64 "\n" : "%" PRIu64 "\n", factor); } } /* return early if we are done */ if (p <= pr_limit) { return; } start = *pr_limit+2; } /* * we shall sieve a bytemap window, note primes and move the window * upward until we pass the stop point */ while (start < stop) { /* * factor out 3, 5, 7, 11 and 13 */ /* initial pattern copy */ factor = (start%(2*3*5*7*11*13))/2; /* starting copy spot */ memcpy(table, &pattern[factor], pattern_size-factor); /* main block pattern copies */ for (fact_lim=pattern_size-factor; fact_lim+pattern_size<=TABSIZE; fact_lim+=pattern_size) { memcpy(&table[fact_lim], pattern, pattern_size); } /* final block pattern copy */ memcpy(&table[fact_lim], pattern, TABSIZE-fact_lim); /* * sieve for primes 17 and higher */ /* note highest useful factor and sieve spot */ if (stop-start > TABSIZE+TABSIZE) { tab_lim = &table[TABSIZE]; /* sieve it all */ fact_lim = sqrt(start+1.0+TABSIZE+TABSIZE); } else { tab_lim = &table[(stop-start)/2]; /* partial sieve */ fact_lim = sqrt(stop+1.0); } /* sieve for factors >= 17 */ factor = 17; /* 17 is first prime to use */ p = &prime[7]; /* 19 is next prime, pi(19)=7 */ do { /* determine the factor's initial sieve point */ mod = start%factor; if (mod & 0x1) { q = &table[(factor-mod)/2]; } else { q = &table[mod ? factor-(mod/2) : 0]; } /* sive for our current factor */ for ( ; q < tab_lim; q += factor) { *q = '\0'; /* sieve out a spot */ } factor = *p++; } while (factor <= fact_lim); /* * print generated primes */ for (q = table; q < tab_lim; ++q, start+=2) { if (*q) { if (start > SIEVEMAX) { if (!isprime(start)) continue; } printf(hflag ? "%" PRIx64 "\n" : "%" PRIu64 "\n", start); } } } } static void usage(void) { fprintf(stderr, "usage: primes [-h] [start [stop]]\n"); exit(1); } Index: head/usr.bin/printenv/printenv.c =================================================================== --- head/usr.bin/printenv/printenv.c (revision 335394) +++ head/usr.bin/printenv/printenv.c (revision 335395) @@ -1,106 +1,106 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1987, 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1987, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #if 0 #ifndef lint static char sccsid[] = "@(#)printenv.c 8.2 (Berkeley) 5/4/95"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include void usage(void); extern char **environ; /* * printenv * * Bill Joy, UCB * February, 1979 */ int main(int argc, char *argv[]) { char *cp, **ep; size_t len; int ch; - if (caph_limit_stdio() < 0 || (cap_enter() < 0 && errno != ENOSYS)) + if (caph_limit_stdio() < 0 || caph_enter() < 0) err(1, "capsicum"); while ((ch = getopt(argc, argv, "")) != -1) switch(ch) { case '?': default: usage(); } argc -= optind; argv += optind; if (argc == 0) { for (ep = environ; *ep; ep++) (void)printf("%s\n", *ep); exit(0); } len = strlen(*argv); for (ep = environ; *ep; ep++) if (!memcmp(*ep, *argv, len)) { cp = *ep + len; if (*cp == '=') { (void)printf("%s\n", cp + 1); exit(0); } } exit(1); } void usage(void) { (void)fprintf(stderr, "usage: printenv [name]\n"); exit(1); } Index: head/usr.bin/rwho/rwho.c =================================================================== --- head/usr.bin/rwho/rwho.c (revision 335394) +++ head/usr.bin/rwho/rwho.c (revision 335395) @@ -1,249 +1,250 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1983, 1993 The Regents of the University of California. * Copyright (c) 2013 Mariusz Zaborski * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1983, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)rwho.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #define NUSERS 1000 #define WHDRSIZE (ssize_t)(sizeof(wd) - sizeof(wd.wd_we)) /* * this macro should be shared with ruptime. */ #define down(w,now) ((now) - (w)->wd_recvtime > 11 * 60) static DIR *dirp; static struct whod wd; static int nusers; static struct myutmp { char myhost[sizeof(wd.wd_hostname)]; int myidle; struct outmp myutmp; } myutmp[NUSERS]; static time_t now; static int aflg; static void usage(void); static int utmpcmp(const void *, const void *); int main(int argc, char *argv[]) { int ch; struct dirent *dp; int width; ssize_t cc; struct whod *w; struct whoent *we; struct myutmp *mp; cap_rights_t rights; int f, n, i; int d_first; int dfd; time_t ct; w = &wd; (void) setlocale(LC_TIME, ""); d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); while ((ch = getopt(argc, argv, "a")) != -1) { switch ((char)ch) { case 'a': aflg = 1; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (argc != 0) usage(); if (chdir(_PATH_RWHODIR) < 0) err(1, "chdir(%s)", _PATH_RWHODIR); if ((dirp = opendir(".")) == NULL) err(1, "opendir(%s)", _PATH_RWHODIR); dfd = dirfd(dirp); mp = myutmp; cap_rights_init(&rights, CAP_READ, CAP_LOOKUP); if (cap_rights_limit(dfd, &rights) < 0 && errno != ENOSYS) err(1, "cap_rights_limit failed: %s", _PATH_RWHODIR); /* * Cache files required for time(3) and localtime(3) before entering * capability mode. */ (void) time(&ct); (void) localtime(&ct); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "cap_enter"); (void) time(&now); cap_rights_init(&rights, CAP_READ); while ((dp = readdir(dirp)) != NULL) { if (dp->d_ino == 0 || strncmp(dp->d_name, "whod.", 5) != 0) continue; f = openat(dfd, dp->d_name, O_RDONLY); if (f < 0) continue; if (cap_rights_limit(f, &rights) < 0 && errno != ENOSYS) err(1, "cap_rights_limit failed: %s", dp->d_name); cc = read(f, (char *)&wd, sizeof(struct whod)); if (cc < WHDRSIZE) { (void) close(f); continue; } if (down(w, now) != 0) { (void) close(f); continue; } cc -= WHDRSIZE; we = w->wd_we; for (n = cc / sizeof(struct whoent); n > 0; n--) { if (aflg == 0 && we->we_idle >= 60 * 60) { we++; continue; } if (nusers >= NUSERS) errx(1, "too many users"); mp->myutmp = we->we_utmp; mp->myidle = we->we_idle; (void) strcpy(mp->myhost, w->wd_hostname); nusers++; we++; mp++; } (void) close(f); } qsort((char *)myutmp, nusers, sizeof(struct myutmp), utmpcmp); mp = myutmp; width = 0; for (i = 0; i < nusers; i++) { /* append one for the blank and use 8 for the out_line */ int j; j = strlen(mp->myhost) + 1 + sizeof(mp->myutmp.out_line); if (j > width) width = j; mp++; } mp = myutmp; for (i = 0; i < nusers; i++) { char buf[BUFSIZ], cbuf[80]; time_t t; t = _int_to_time(mp->myutmp.out_time); strftime(cbuf, sizeof(cbuf), d_first ? "%e %b %R" : "%b %e %R", localtime(&t)); (void) sprintf(buf, "%s:%-.*s", mp->myhost, (int)sizeof(mp->myutmp.out_line), mp->myutmp.out_line); printf("%-*.*s %-*s %s", (int)sizeof(mp->myutmp.out_name), (int)sizeof(mp->myutmp.out_name), mp->myutmp.out_name, width, buf, cbuf); mp->myidle /= 60; if (mp->myidle != 0) { if (aflg != 0) { if (mp->myidle >= 100 * 60) mp->myidle = 100 * 60 - 1; if (mp->myidle >= 60) printf(" %2d", mp->myidle / 60); else printf(" "); } else { printf(" "); } printf(":%02d", mp->myidle % 60); } printf("\n"); mp++; } exit(0); } static void usage(void) { fprintf(stderr, "usage: rwho [-a]\n"); exit(1); } #define MYUTMP(a) ((const struct myutmp *)(a)) static int utmpcmp(const void *u1, const void *u2) { int rc; rc = strncmp(MYUTMP(u1)->myutmp.out_name, MYUTMP(u2)->myutmp.out_name, sizeof(MYUTMP(u2)->myutmp.out_name)); if (rc != 0) return (rc); rc = strcmp(MYUTMP(u1)->myhost, MYUTMP(u2)->myhost); if (rc != 0) return (rc); return (strncmp(MYUTMP(u1)->myutmp.out_line, MYUTMP(u2)->myutmp.out_line, sizeof(MYUTMP(u2)->myutmp.out_line))); } Index: head/usr.bin/tee/tee.c =================================================================== --- head/usr.bin/tee/tee.c (revision 335394) +++ head/usr.bin/tee/tee.c (revision 335395) @@ -1,160 +1,160 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1988, 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1988, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)tee.c 8.1 (Berkeley) 6/6/93"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include typedef struct _list { struct _list *next; int fd; const char *name; } LIST; static LIST *head; static void add(int, const char *); static void usage(void); int main(int argc, char *argv[]) { LIST *p; int n, fd, rval, wval; char *bp; int append, ch, exitval; char *buf; #define BSIZE (8 * 1024) append = 0; while ((ch = getopt(argc, argv, "ai")) != -1) switch((char)ch) { case 'a': append = 1; break; case 'i': (void)signal(SIGINT, SIG_IGN); break; case '?': default: usage(); } argv += optind; argc -= optind; if ((buf = malloc(BSIZE)) == NULL) err(1, "malloc"); if (caph_limit_stdin() == -1 || caph_limit_stderr() == -1) err(EXIT_FAILURE, "unable to limit stdio"); add(STDOUT_FILENO, "stdout"); for (exitval = 0; *argv; ++argv) if ((fd = open(*argv, append ? O_WRONLY|O_CREAT|O_APPEND : O_WRONLY|O_CREAT|O_TRUNC, DEFFILEMODE)) < 0) { warn("%s", *argv); exitval = 1; } else add(fd, *argv); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(EXIT_FAILURE, "unable to enter capability mode"); while ((rval = read(STDIN_FILENO, buf, BSIZE)) > 0) for (p = head; p; p = p->next) { n = rval; bp = buf; do { if ((wval = write(p->fd, bp, n)) == -1) { warn("%s", p->name); exitval = 1; break; } bp += wval; } while (n -= wval); } if (rval < 0) err(1, "read"); exit(exitval); } static void usage(void) { (void)fprintf(stderr, "usage: tee [-ai] [file ...]\n"); exit(1); } static void add(int fd, const char *name) { LIST *p; cap_rights_t rights; if (fd == STDOUT_FILENO) { if (caph_limit_stdout() == -1) err(EXIT_FAILURE, "unable to limit stdout"); } else { cap_rights_init(&rights, CAP_WRITE, CAP_FSTAT); if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS) err(EXIT_FAILURE, "unable to limit rights"); } if ((p = malloc(sizeof(LIST))) == NULL) err(1, "malloc"); p->fd = fd; p->name = name; p->next = head; head = p; } Index: head/usr.bin/tr/tr.c =================================================================== --- head/usr.bin/tr/tr.c (revision 335394) +++ head/usr.bin/tr/tr.c (revision 335395) @@ -1,384 +1,384 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1988, 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 __FBSDID("$FreeBSD$"); #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1988, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif #ifndef lint static const char sccsid[] = "@(#)tr.c 8.2 (Berkeley) 5/4/95"; #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cmap.h" #include "cset.h" #include "extern.h" static STR s1 = { STRING1, NORMAL, 0, OOBCH, 0, { 0, OOBCH }, NULL, NULL }; static STR s2 = { STRING2, NORMAL, 0, OOBCH, 0, { 0, OOBCH }, NULL, NULL }; static struct cset *setup(char *, STR *, int, int); static void usage(void); int main(int argc, char **argv) { static int carray[NCHARS_SB]; struct cmap *map; struct cset *delete, *squeeze; int n, *p; int Cflag, cflag, dflag, sflag, isstring2; wint_t ch, cnt, lastch; (void)setlocale(LC_ALL, ""); if (caph_limit_stdio() == -1) err(1, "unable to limit stdio"); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "unable to enter capability mode"); Cflag = cflag = dflag = sflag = 0; while ((ch = getopt(argc, argv, "Ccdsu")) != -1) switch((char)ch) { case 'C': Cflag = 1; cflag = 0; break; case 'c': cflag = 1; Cflag = 0; break; case 'd': dflag = 1; break; case 's': sflag = 1; break; case 'u': setbuf(stdout, (char *)NULL); break; case '?': default: usage(); } argc -= optind; argv += optind; switch(argc) { case 0: default: usage(); /* NOTREACHED */ case 1: isstring2 = 0; break; case 2: isstring2 = 1; break; } /* * tr -ds [-Cc] string1 string2 * Delete all characters (or complemented characters) in string1. * Squeeze all characters in string2. */ if (dflag && sflag) { if (!isstring2) usage(); delete = setup(argv[0], &s1, cflag, Cflag); squeeze = setup(argv[1], &s2, 0, 0); for (lastch = OOBCH; (ch = getwchar()) != WEOF;) if (!cset_in(delete, ch) && (lastch != ch || !cset_in(squeeze, ch))) { lastch = ch; (void)putwchar(ch); } if (ferror(stdin)) err(1, NULL); exit(0); } /* * tr -d [-Cc] string1 * Delete all characters (or complemented characters) in string1. */ if (dflag) { if (isstring2) usage(); delete = setup(argv[0], &s1, cflag, Cflag); while ((ch = getwchar()) != WEOF) if (!cset_in(delete, ch)) (void)putwchar(ch); if (ferror(stdin)) err(1, NULL); exit(0); } /* * tr -s [-Cc] string1 * Squeeze all characters (or complemented characters) in string1. */ if (sflag && !isstring2) { squeeze = setup(argv[0], &s1, cflag, Cflag); for (lastch = OOBCH; (ch = getwchar()) != WEOF;) if (lastch != ch || !cset_in(squeeze, ch)) { lastch = ch; (void)putwchar(ch); } if (ferror(stdin)) err(1, NULL); exit(0); } /* * tr [-Ccs] string1 string2 * Replace all characters (or complemented characters) in string1 with * the character in the same position in string2. If the -s option is * specified, squeeze all the characters in string2. */ if (!isstring2) usage(); map = cmap_alloc(); if (map == NULL) err(1, NULL); squeeze = cset_alloc(); if (squeeze == NULL) err(1, NULL); s1.str = argv[0]; if (Cflag || cflag) { cmap_default(map, OOBCH); if ((s2.str = strdup(argv[1])) == NULL) errx(1, "strdup(argv[1])"); } else s2.str = argv[1]; if (!next(&s2)) errx(1, "empty string2"); /* * For -s result will contain only those characters defined * as the second characters in each of the toupper or tolower * pairs. */ /* If string2 runs out of characters, use the last one specified. */ while (next(&s1)) { again: if (s1.state == CCLASS_LOWER && s2.state == CCLASS_UPPER && s1.cnt == 1 && s2.cnt == 1) { do { ch = towupper(s1.lastch); cmap_add(map, s1.lastch, ch); if (sflag && iswupper(ch)) cset_add(squeeze, ch); if (!next(&s1)) goto endloop; } while (s1.state == CCLASS_LOWER && s1.cnt > 1); /* skip upper set */ do { if (!next(&s2)) break; } while (s2.state == CCLASS_UPPER && s2.cnt > 1); goto again; } else if (s1.state == CCLASS_UPPER && s2.state == CCLASS_LOWER && s1.cnt == 1 && s2.cnt == 1) { do { ch = towlower(s1.lastch); cmap_add(map, s1.lastch, ch); if (sflag && iswlower(ch)) cset_add(squeeze, ch); if (!next(&s1)) goto endloop; } while (s1.state == CCLASS_UPPER && s1.cnt > 1); /* skip lower set */ do { if (!next(&s2)) break; } while (s2.state == CCLASS_LOWER && s2.cnt > 1); goto again; } else { cmap_add(map, s1.lastch, s2.lastch); if (sflag) cset_add(squeeze, s2.lastch); } (void)next(&s2); } endloop: if (cflag || (Cflag && MB_CUR_MAX > 1)) { /* * This is somewhat tricky: since the character set is * potentially huge, we need to avoid allocating a map * entry for every character. Our strategy is to set the * default mapping to the last character of string #2 * (= the one that gets automatically repeated), then to * add back identity mappings for characters that should * remain unchanged. We don't waste space on identity mappings * for non-characters with the -C option; those are simulated * in the I/O loop. */ s2.str = argv[1]; s2.state = NORMAL; for (cnt = 0; cnt < WINT_MAX; cnt++) { if (Cflag && !iswrune(cnt)) continue; if (cmap_lookup(map, cnt) == OOBCH) { if (next(&s2)) { cmap_add(map, cnt, s2.lastch); if (sflag) cset_add(squeeze, s2.lastch); } } else cmap_add(map, cnt, cnt); if ((s2.state == EOS || s2.state == INFINITE) && cnt >= cmap_max(map)) break; } cmap_default(map, s2.lastch); } else if (Cflag) { for (p = carray, cnt = 0; cnt < NCHARS_SB; cnt++) { if (cmap_lookup(map, cnt) == OOBCH && iswrune(cnt)) *p++ = cnt; else cmap_add(map, cnt, cnt); } n = p - carray; if (Cflag && n > 1) (void)mergesort(carray, n, sizeof(*carray), charcoll); s2.str = argv[1]; s2.state = NORMAL; for (cnt = 0; cnt < n; cnt++) { (void)next(&s2); cmap_add(map, carray[cnt], s2.lastch); /* * Chars taken from s2 can be different this time * due to lack of complex upper/lower processing, * so fill string2 again to not miss some. */ if (sflag) cset_add(squeeze, s2.lastch); } } cset_cache(squeeze); cmap_cache(map); if (sflag) for (lastch = OOBCH; (ch = getwchar()) != WEOF;) { if (!Cflag || iswrune(ch)) ch = cmap_lookup(map, ch); if (lastch != ch || !cset_in(squeeze, ch)) { lastch = ch; (void)putwchar(ch); } } else while ((ch = getwchar()) != WEOF) { if (!Cflag || iswrune(ch)) ch = cmap_lookup(map, ch); (void)putwchar(ch); } if (ferror(stdin)) err(1, NULL); exit (0); } static struct cset * setup(char *arg, STR *str, int cflag, int Cflag) { struct cset *cs; cs = cset_alloc(); if (cs == NULL) err(1, NULL); str->str = arg; while (next(str)) cset_add(cs, str->lastch); if (Cflag) cset_addclass(cs, wctype("rune"), true); if (cflag || Cflag) cset_invert(cs); cset_cache(cs); return (cs); } int charcoll(const void *a, const void *b) { static char sa[2], sb[2]; sa[0] = *(const int *)a; sb[0] = *(const int *)b; return (strcoll(sa, sb)); } static void usage(void) { (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", "usage: tr [-Ccsu] string1 string2", " tr [-Ccu] -d string1", " tr [-Ccu] -s string1", " tr [-Ccu] -ds string1 string2"); exit(1); } Index: head/usr.bin/uniq/uniq.c =================================================================== --- head/usr.bin/uniq/uniq.c (revision 335394) +++ head/usr.bin/uniq/uniq.c (revision 335395) @@ -1,359 +1,360 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Case Larsen. * * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)uniq.c 8.3 (Berkeley) 5/4/95"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int cflag, dflag, uflag, iflag; static int numchars, numfields, repeats; static const struct option long_opts[] = { {"count", no_argument, NULL, 'c'}, {"repeated", no_argument, NULL, 'd'}, {"skip-fields", required_argument, NULL, 'f'}, {"ignore-case", no_argument, NULL, 'i'}, {"skip-chars", required_argument, NULL, 's'}, {"unique", no_argument, NULL, 'u'}, {NULL, no_argument, NULL, 0} }; static FILE *file(const char *, const char *); static wchar_t *convert(const char *); static int inlcmp(const char *, const char *); static void show(FILE *, const char *); static wchar_t *skip(wchar_t *); static void obsolete(char *[]); static void usage(void); static void strerror_init(void) { /* * Cache NLS data before entering capability mode. * XXXPJD: There should be strerror_init() and strsignal_init() in libc. */ (void)catopen("libc", NL_CAT_LOCALE); } int main (int argc, char *argv[]) { wchar_t *tprev, *tthis; FILE *ifp, *ofp; int ch, comp; size_t prevbuflen, thisbuflen, b1; char *prevline, *thisline, *p; const char *ifn; cap_rights_t rights; (void) setlocale(LC_ALL, ""); obsolete(argv); while ((ch = getopt_long(argc, argv, "+cdif:s:u", long_opts, NULL)) != -1) switch (ch) { case 'c': cflag = 1; break; case 'd': dflag = 1; break; case 'i': iflag = 1; break; case 'f': numfields = strtol(optarg, &p, 10); if (numfields < 0 || *p) errx(1, "illegal field skip value: %s", optarg); break; case 's': numchars = strtol(optarg, &p, 10); if (numchars < 0 || *p) errx(1, "illegal character skip value: %s", optarg); break; case 'u': uflag = 1; break; case '?': default: usage(); } argc -= optind; argv += optind; if (argc > 2) usage(); ifp = stdin; ifn = "stdin"; ofp = stdout; if (argc > 0 && strcmp(argv[0], "-") != 0) ifp = file(ifn = argv[0], "r"); cap_rights_init(&rights, CAP_FSTAT, CAP_READ); if (cap_rights_limit(fileno(ifp), &rights) < 0 && errno != ENOSYS) err(1, "unable to limit rights for %s", ifn); cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE); if (argc > 1) ofp = file(argv[1], "w"); else cap_rights_set(&rights, CAP_IOCTL); if (cap_rights_limit(fileno(ofp), &rights) < 0 && errno != ENOSYS) { err(1, "unable to limit rights for %s", argc > 1 ? argv[1] : "stdout"); } if (cap_rights_is_set(&rights, CAP_IOCTL)) { unsigned long cmd; cmd = TIOCGETA; /* required by isatty(3) in printf(3) */ if (cap_ioctls_limit(fileno(ofp), &cmd, 1) < 0 && errno != ENOSYS) { err(1, "unable to limit ioctls for %s", argc > 1 ? argv[1] : "stdout"); } } strerror_init(); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "unable to enter capability mode"); prevbuflen = thisbuflen = 0; prevline = thisline = NULL; if (getline(&prevline, &prevbuflen, ifp) < 0) { if (ferror(ifp)) err(1, "%s", ifn); exit(0); } tprev = convert(prevline); tthis = NULL; while (getline(&thisline, &thisbuflen, ifp) >= 0) { if (tthis != NULL) free(tthis); tthis = convert(thisline); if (tthis == NULL && tprev == NULL) comp = inlcmp(thisline, prevline); else if (tthis == NULL || tprev == NULL) comp = 1; else comp = wcscoll(tthis, tprev); if (comp) { /* If different, print; set previous to new value. */ show(ofp, prevline); p = prevline; b1 = prevbuflen; prevline = thisline; prevbuflen = thisbuflen; if (tprev != NULL) free(tprev); tprev = tthis; thisline = p; thisbuflen = b1; tthis = NULL; repeats = 0; } else ++repeats; } if (ferror(ifp)) err(1, "%s", ifn); show(ofp, prevline); exit(0); } static wchar_t * convert(const char *str) { size_t n; wchar_t *buf, *ret, *p; if ((n = mbstowcs(NULL, str, 0)) == (size_t)-1) return (NULL); if (SIZE_MAX / sizeof(*buf) < n + 1) errx(1, "conversion buffer length overflow"); if ((buf = malloc((n + 1) * sizeof(*buf))) == NULL) err(1, "malloc"); if (mbstowcs(buf, str, n + 1) != n) errx(1, "internal mbstowcs() error"); /* The last line may not end with \n. */ if (n > 0 && buf[n - 1] == L'\n') buf[n - 1] = L'\0'; /* If requested get the chosen fields + character offsets. */ if (numfields || numchars) { if ((ret = wcsdup(skip(buf))) == NULL) err(1, "wcsdup"); free(buf); } else ret = buf; if (iflag) { for (p = ret; *p != L'\0'; p++) *p = towlower(*p); } return (ret); } static int inlcmp(const char *s1, const char *s2) { int c1, c2; while (*s1 == *s2++) if (*s1++ == '\0') return (0); c1 = (unsigned char)*s1; c2 = (unsigned char)*(s2 - 1); /* The last line may not end with \n. */ if (c1 == '\n') c1 = '\0'; if (c2 == '\n') c2 = '\0'; return (c1 - c2); } /* * show -- * Output a line depending on the flags and number of repetitions * of the line. */ static void show(FILE *ofp, const char *str) { if ((dflag && repeats == 0) || (uflag && repeats > 0)) return; if (cflag) (void)fprintf(ofp, "%4d %s", repeats + 1, str); else (void)fprintf(ofp, "%s", str); } static wchar_t * skip(wchar_t *str) { int nchars, nfields; for (nfields = 0; *str != L'\0' && nfields++ != numfields; ) { while (iswblank(*str)) str++; while (*str != L'\0' && !iswblank(*str)) str++; } for (nchars = numchars; nchars-- && *str != L'\0'; ++str) ; return(str); } static FILE * file(const char *name, const char *mode) { FILE *fp; if ((fp = fopen(name, mode)) == NULL) err(1, "%s", name); return(fp); } static void obsolete(char *argv[]) { int len; char *ap, *p, *start; while ((ap = *++argv)) { /* Return if "--" or not an option of any form. */ if (ap[0] != '-') { if (ap[0] != '+') return; } else if (ap[1] == '-') return; if (!isdigit((unsigned char)ap[1])) continue; /* * Digit signifies an old-style option. Malloc space for dash, * new option and argument. */ len = strlen(ap); if ((start = p = malloc(len + 3)) == NULL) err(1, "malloc"); *p++ = '-'; *p++ = ap[0] == '+' ? 's' : 'f'; (void)strcpy(p, ap + 1); *argv = start; } } static void usage(void) { (void)fprintf(stderr, "usage: uniq [-c] [-d | -u] [-i] [-f fields] [-s chars] [input [output]]\n"); exit(1); } Index: head/usr.bin/units/units.c =================================================================== --- head/usr.bin/units/units.c (revision 335394) +++ head/usr.bin/units/units.c (revision 335395) @@ -1,895 +1,895 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * units.c Copyright (c) 1993 by Adrian Mariano (adrian@cam.cornell.edu) * * 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. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * Disclaimer: This software is provided by the author "as is". The author * shall not be liable for any damages caused in any way by this software. * * I would appreciate (though I do not require) receiving a copy of any * improvements you might make to this program. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include -#include +#include #ifndef UNITSFILE #define UNITSFILE "/usr/share/misc/definitions.units" #endif #define MAXUNITS 1000 #define MAXPREFIXES 100 #define MAXSUBUNITS 500 #define PRIMITIVECHAR '!' static const char *powerstring = "^"; static const char *numfmt = "%.8g"; static struct { char *uname; char *uval; } unittable[MAXUNITS]; struct unittype { char *numerator[MAXSUBUNITS]; char *denominator[MAXSUBUNITS]; double factor; double offset; int quantity; }; static struct { char *prefixname; char *prefixval; } prefixtable[MAXPREFIXES]; static char NULLUNIT[] = ""; #define SEPARATOR ":" static int unitcount; static int prefixcount; static bool verbose = false; static bool terse = false; static const char * outputformat; static const char * havestr; static const char * wantstr; static int addsubunit(char *product[], char *toadd); static int addunit(struct unittype *theunit, const char *toadd, int flip, int quantity); static void cancelunit(struct unittype * theunit); static int compare(const void *item1, const void *item2); static int compareproducts(char **one, char **two); static int compareunits(struct unittype * first, struct unittype * second); static int completereduce(struct unittype * unit); static char *dupstr(const char *str); static void initializeunit(struct unittype * theunit); static char *lookupunit(const char *unit); static void readunits(const char *userfile); static int reduceproduct(struct unittype * theunit, int flip); static int reduceunit(struct unittype * theunit); static void showanswer(struct unittype * have, struct unittype * want); static void showunit(struct unittype * theunit); static void sortunit(struct unittype * theunit); static void usage(void); static void zeroerror(void); static const char* promptstr = ""; static const char * prompt(EditLine *e __unused) { return promptstr; } static char * dupstr(const char *str) { char *ret; ret = strdup(str); if (!ret) err(3, "dupstr"); return (ret); } static void readunits(const char *userfile) { FILE *unitfile; char line[512], *lineptr; int len, linenum, i; cap_rights_t unitfilerights; unitcount = 0; linenum = 0; if (userfile) { unitfile = fopen(userfile, "r"); if (!unitfile) errx(1, "unable to open units file '%s'", userfile); } else { unitfile = fopen(UNITSFILE, "r"); if (!unitfile) { char *direc, *env; char filename[1000]; env = getenv("PATH"); if (env) { direc = strtok(env, SEPARATOR); while (direc) { snprintf(filename, sizeof(filename), "%s/%s", direc, UNITSFILE); unitfile = fopen(filename, "rt"); if (unitfile) break; direc = strtok(NULL, SEPARATOR); } } if (!unitfile) errx(1, "can't find units file '%s'", UNITSFILE); } } cap_rights_init(&unitfilerights, CAP_READ, CAP_FSTAT); if (cap_rights_limit(fileno(unitfile), &unitfilerights) < 0 && errno != ENOSYS) err(1, "cap_rights_limit() failed"); while (!feof(unitfile)) { if (!fgets(line, sizeof(line), unitfile)) break; linenum++; lineptr = line; if (*lineptr == '/' || *lineptr == '#') continue; lineptr += strspn(lineptr, " \n\t"); len = strcspn(lineptr, " \n\t"); lineptr[len] = 0; if (!strlen(lineptr)) continue; if (lineptr[strlen(lineptr) - 1] == '-') { /* it's a prefix */ if (prefixcount == MAXPREFIXES) { warnx("memory for prefixes exceeded in line %d", linenum); continue; } lineptr[strlen(lineptr) - 1] = 0; prefixtable[prefixcount].prefixname = dupstr(lineptr); for (i = 0; i < prefixcount; i++) if (!strcmp(prefixtable[i].prefixname, lineptr)) { warnx("redefinition of prefix '%s' on line %d ignored", lineptr, linenum); continue; } lineptr += len + 1; lineptr += strspn(lineptr, " \n\t"); len = strcspn(lineptr, "\n\t"); if (len == 0) { warnx("unexpected end of prefix on line %d", linenum); continue; } lineptr[len] = 0; prefixtable[prefixcount++].prefixval = dupstr(lineptr); } else { /* it's not a prefix */ if (unitcount == MAXUNITS) { warnx("memory for units exceeded in line %d", linenum); continue; } unittable[unitcount].uname = dupstr(lineptr); for (i = 0; i < unitcount; i++) if (!strcmp(unittable[i].uname, lineptr)) { warnx("redefinition of unit '%s' on line %d ignored", lineptr, linenum); continue; } lineptr += len + 1; lineptr += strspn(lineptr, " \n\t"); if (!strlen(lineptr)) { warnx("unexpected end of unit on line %d", linenum); continue; } len = strcspn(lineptr, "\n\t"); lineptr[len] = 0; unittable[unitcount++].uval = dupstr(lineptr); } } fclose(unitfile); } static void initializeunit(struct unittype * theunit) { theunit->numerator[0] = theunit->denominator[0] = NULL; theunit->factor = 1.0; theunit->offset = 0.0; theunit->quantity = 0; } static int addsubunit(char *product[], char *toadd) { char **ptr; for (ptr = product; *ptr && *ptr != NULLUNIT; ptr++); if (ptr >= product + MAXSUBUNITS) { warnx("memory overflow in unit reduction"); return 1; } if (!*ptr) *(ptr + 1) = NULL; *ptr = dupstr(toadd); return 0; } static void showunit(struct unittype * theunit) { char **ptr; int printedslash; int counter = 1; printf(numfmt, theunit->factor); if (theunit->offset) printf("&%.8g", theunit->offset); for (ptr = theunit->numerator; *ptr; ptr++) { if (ptr > theunit->numerator && **ptr && !strcmp(*ptr, *(ptr - 1))) counter++; else { if (counter > 1) printf("%s%d", powerstring, counter); if (**ptr) printf(" %s", *ptr); counter = 1; } } if (counter > 1) printf("%s%d", powerstring, counter); counter = 1; printedslash = 0; for (ptr = theunit->denominator; *ptr; ptr++) { if (ptr > theunit->denominator && **ptr && !strcmp(*ptr, *(ptr - 1))) counter++; else { if (counter > 1) printf("%s%d", powerstring, counter); if (**ptr) { if (!printedslash) printf(" /"); printedslash = 1; printf(" %s", *ptr); } counter = 1; } } if (counter > 1) printf("%s%d", powerstring, counter); printf("\n"); } void zeroerror(void) { warnx("unit reduces to zero"); } /* Adds the specified string to the unit. Flip is 0 for adding normally, 1 for adding reciprocal. Quantity is 1 if this is a quantity to be converted rather than a pure unit. Returns 0 for successful addition, nonzero on error. */ static int addunit(struct unittype * theunit, const char *toadd, int flip, int quantity) { char *scratch, *savescr; char *item; char *divider, *slash, *offset; int doingtop; if (!strlen(toadd)) return 1; savescr = scratch = dupstr(toadd); for (slash = scratch + 1; *slash; slash++) if (*slash == '-' && (tolower(*(slash - 1)) != 'e' || !strchr(".0123456789", *(slash + 1)))) *slash = ' '; slash = strchr(scratch, '/'); if (slash) *slash = 0; doingtop = 1; do { item = strtok(scratch, " *\t\n/"); while (item) { if (strchr("0123456789.", *item)) { /* item is a number */ double num, offsetnum; if (quantity) theunit->quantity = 1; offset = strchr(item, '&'); if (offset) { *offset = 0; offsetnum = atof(offset+1); } else offsetnum = 0.0; divider = strchr(item, '|'); if (divider) { *divider = 0; num = atof(item); if (!num) { zeroerror(); free(savescr); return 1; } if (doingtop ^ flip) { theunit->factor *= num; theunit->offset *= num; } else { theunit->factor /= num; theunit->offset /= num; } num = atof(divider + 1); if (!num) { zeroerror(); free(savescr); return 1; } if (doingtop ^ flip) { theunit->factor /= num; theunit->offset /= num; } else { theunit->factor *= num; theunit->offset *= num; } } else { num = atof(item); if (!num) { zeroerror(); free(savescr); return 1; } if (doingtop ^ flip) { theunit->factor *= num; theunit->offset *= num; } else { theunit->factor /= num; theunit->offset /= num; } } if (doingtop ^ flip) theunit->offset += offsetnum; } else { /* item is not a number */ int repeat = 1; if (strchr("23456789", item[strlen(item) - 1])) { repeat = item[strlen(item) - 1] - '0'; item[strlen(item) - 1] = 0; } for (; repeat; repeat--) { if (addsubunit(doingtop ^ flip ? theunit->numerator : theunit->denominator, item)) { free(savescr); return 1; } } } item = strtok(NULL, " *\t/\n"); } doingtop--; if (slash) { scratch = slash + 1; } else doingtop--; } while (doingtop >= 0); free(savescr); return 0; } static int compare(const void *item1, const void *item2) { return strcmp(*(const char * const *)item1, *(const char * const *)item2); } static void sortunit(struct unittype * theunit) { char **ptr; unsigned int count; for (count = 0, ptr = theunit->numerator; *ptr; ptr++, count++); qsort(theunit->numerator, count, sizeof(char *), compare); for (count = 0, ptr = theunit->denominator; *ptr; ptr++, count++); qsort(theunit->denominator, count, sizeof(char *), compare); } void cancelunit(struct unittype * theunit) { char **den, **num; int comp; den = theunit->denominator; num = theunit->numerator; while (*num && *den) { comp = strcmp(*den, *num); if (!comp) { /* if (*den!=NULLUNIT) free(*den); if (*num!=NULLUNIT) free(*num);*/ *den++ = NULLUNIT; *num++ = NULLUNIT; } else if (comp < 0) den++; else num++; } } /* Looks up the definition for the specified unit. Returns a pointer to the definition or a null pointer if the specified unit does not appear in the units table. */ static char buffer[100]; /* buffer for lookupunit answers with prefixes */ char * lookupunit(const char *unit) { int i; char *copy; for (i = 0; i < unitcount; i++) { if (!strcmp(unittable[i].uname, unit)) return unittable[i].uval; } if (unit[strlen(unit) - 1] == '^') { copy = dupstr(unit); copy[strlen(copy) - 1] = 0; for (i = 0; i < unitcount; i++) { if (!strcmp(unittable[i].uname, copy)) { strlcpy(buffer, copy, sizeof(buffer)); free(copy); return buffer; } } free(copy); } if (unit[strlen(unit) - 1] == 's') { copy = dupstr(unit); copy[strlen(copy) - 1] = 0; for (i = 0; i < unitcount; i++) { if (!strcmp(unittable[i].uname, copy)) { strlcpy(buffer, copy, sizeof(buffer)); free(copy); return buffer; } } if (copy[strlen(copy) - 1] == 'e') { copy[strlen(copy) - 1] = 0; for (i = 0; i < unitcount; i++) { if (!strcmp(unittable[i].uname, copy)) { strlcpy(buffer, copy, sizeof(buffer)); free(copy); return buffer; } } } free(copy); } for (i = 0; i < prefixcount; i++) { size_t len = strlen(prefixtable[i].prefixname); if (!strncmp(prefixtable[i].prefixname, unit, len)) { if (!strlen(unit + len) || lookupunit(unit + len)) { snprintf(buffer, sizeof(buffer), "%s %s", prefixtable[i].prefixval, unit + len); return buffer; } } } return 0; } /* reduces a product of symbolic units to primitive units. The three low bits are used to return flags: bit 0 (1) set on if reductions were performed without error. bit 1 (2) set on if no reductions are performed. bit 2 (4) set on if an unknown unit is discovered. */ #define ERROR 4 static int reduceproduct(struct unittype * theunit, int flip) { char *toadd; char **product; int didsomething = 2; if (flip) product = theunit->denominator; else product = theunit->numerator; for (; *product; product++) { for (;;) { if (!strlen(*product)) break; toadd = lookupunit(*product); if (!toadd) { printf("unknown unit '%s'\n", *product); return ERROR; } if (strchr(toadd, PRIMITIVECHAR)) break; didsomething = 1; if (*product != NULLUNIT) { free(*product); *product = NULLUNIT; } if (addunit(theunit, toadd, flip, 0)) return ERROR; } } return didsomething; } /* Reduces numerator and denominator of the specified unit. Returns 0 on success, or 1 on unknown unit error. */ static int reduceunit(struct unittype * theunit) { int ret; ret = 1; while (ret & 1) { ret = reduceproduct(theunit, 0) | reduceproduct(theunit, 1); if (ret & 4) return 1; } return 0; } static int compareproducts(char **one, char **two) { while (*one || *two) { if (!*one && *two != NULLUNIT) return 1; if (!*two && *one != NULLUNIT) return 1; if (*one == NULLUNIT) one++; else if (*two == NULLUNIT) two++; else if (strcmp(*one, *two)) return 1; else { one++; two++; } } return 0; } /* Return zero if units are compatible, nonzero otherwise */ static int compareunits(struct unittype * first, struct unittype * second) { return compareproducts(first->numerator, second->numerator) || compareproducts(first->denominator, second->denominator); } static int completereduce(struct unittype * unit) { if (reduceunit(unit)) return 1; sortunit(unit); cancelunit(unit); return 0; } static void showanswer(struct unittype * have, struct unittype * want) { double ans; char* oformat; if (compareunits(have, want)) { printf("conformability error\n"); if (verbose) printf("\t%s = ", havestr); else if (!terse) printf("\t"); showunit(have); if (!terse) { if (verbose) printf("\t%s = ", wantstr); else printf("\t"); showunit(want); } } else if (have->offset != want->offset) { if (want->quantity) printf("WARNING: conversion of non-proportional quantities.\n"); if (have->quantity) { asprintf(&oformat, "\t%s\n", outputformat); printf(oformat, (have->factor + have->offset-want->offset)/want->factor); free(oformat); } else { asprintf(&oformat, "\t (-> x*%sg %sg)\n\t (<- y*%sg %sg)\n", outputformat, outputformat, outputformat, outputformat); printf(oformat, have->factor / want->factor, (have->offset-want->offset)/want->factor, want->factor / have->factor, (want->offset - have->offset)/have->factor); } } else { ans = have->factor / want->factor; if (verbose) { printf("\t%s = ", havestr); printf(outputformat, ans); printf(" * %s", wantstr); printf("\n"); } else if (terse) { printf(outputformat, ans); printf("\n"); } else { printf("\t* "); printf(outputformat, ans); printf("\n"); } if (verbose) { printf("\t%s = (1 / ", havestr); printf(outputformat, 1/ans); printf(") * %s\n", wantstr); } else if (!terse) { printf("\t/ "); printf(outputformat, 1/ans); printf("\n"); } } } static void __dead2 usage(void) { fprintf(stderr, "usage: units [-f unitsfile] [-H historyfile] [-UVq] [from-unit to-unit]\n"); exit(3); } static struct option longopts[] = { {"help", no_argument, NULL, 'h'}, {"exponential", no_argument, NULL, 'e'}, {"file", required_argument, NULL, 'f'}, {"history", required_argument, NULL, 'H'}, {"output-format", required_argument, NULL, 'o'}, {"quiet", no_argument, NULL, 'q'}, {"terse", no_argument, NULL, 't'}, {"unitsfile", no_argument, NULL, 'U'}, {"verbose", no_argument, NULL, 'v'}, {"version", no_argument, NULL, 'V'}, { 0, 0, 0, 0 } }; int main(int argc, char **argv) { struct unittype have, want; int optchar; bool quiet; bool readfile; bool quit; History *inhistory; EditLine *el; HistEvent ev; int inputsz; char const * history_file; quiet = false; readfile = false; history_file = NULL; outputformat = numfmt; quit = false; while ((optchar = getopt_long(argc, argv, "+ehf:o:qtvH:UV", longopts, NULL)) != -1) { switch (optchar) { case 'e': outputformat = "%6e"; break; case 'f': readfile = true; if (strlen(optarg) == 0) readunits(NULL); else readunits(optarg); break; case 'H': history_file = optarg; break; case 'q': quiet = true; break; case 't': terse = true; break; case 'o': outputformat = optarg; break; case 'v': verbose = true; break; case 'V': fprintf(stderr, "FreeBSD units\n"); /* FALLTHROUGH */ case 'U': if (access(UNITSFILE, F_OK) == 0) printf("%s\n", UNITSFILE); else printf("Units data file not found"); exit(0); case 'h': /* FALLTHROUGH */ default: usage(); } } if (!readfile) readunits(NULL); if (optind == argc - 2) { - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "unable to enter capability mode"); havestr = argv[optind]; wantstr = argv[optind + 1]; initializeunit(&have); addunit(&have, havestr, 0, 1); completereduce(&have); initializeunit(&want); addunit(&want, wantstr, 0, 1); completereduce(&want); showanswer(&have, &want); } else { inhistory = history_init(); el = el_init(argv[0], stdin, stdout, stderr); el_set(el, EL_PROMPT, &prompt); el_set(el, EL_EDITOR, "emacs"); el_set(el, EL_SIGNAL, 1); el_set(el, EL_HIST, history, inhistory); el_source(el, NULL); history(inhistory, &ev, H_SETSIZE, 800); if (inhistory == 0) err(1, "Could not initialize history"); - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "unable to enter capability mode"); if (!quiet) printf("%d units, %d prefixes\n", unitcount, prefixcount); while (!quit) { do { initializeunit(&have); if (!quiet) promptstr = "You have: "; havestr = el_gets(el, &inputsz); if (havestr == NULL) { quit = true; break; } if (inputsz > 0) history(inhistory, &ev, H_ENTER, havestr); } while (addunit(&have, havestr, 0, 1) || completereduce(&have)); if (quit) { break; } do { initializeunit(&want); if (!quiet) promptstr = "You want: "; wantstr = el_gets(el, &inputsz); if (wantstr == NULL) { quit = true; break; } if (inputsz > 0) history(inhistory, &ev, H_ENTER, wantstr); } while (addunit(&want, wantstr, 0, 1) || completereduce(&want)); if (quit) { break; } showanswer(&have, &want); } history_end(inhistory); el_end(el); } return (0); } Index: head/usr.bin/write/write.c =================================================================== --- head/usr.bin/write/write.c (revision 335394) +++ head/usr.bin/write/write.c (revision 335395) @@ -1,361 +1,361 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Jef Poskanzer and Craig Leres of the Lawrence Berkeley Laboratory. * * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif #if 0 #ifndef lint static char sccsid[] = "@(#)write.c 8.1 (Berkeley) 6/6/93"; #endif #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void done(int); void do_write(int, char *, char *, const char *); static void usage(void); int term_chk(int, char *, int *, time_t *, int); void wr_fputs(wchar_t *s); void search_utmp(int, char *, char *, char *, uid_t); int utmp_chk(char *, char *); int main(int argc, char **argv) { unsigned long cmds[] = { TIOCGETA, TIOCGWINSZ, FIODGNAME }; cap_rights_t rights; struct passwd *pwd; time_t atime; uid_t myuid; int msgsok, myttyfd; char tty[MAXPATHLEN], *mytty; const char *login; int devfd; (void)setlocale(LC_CTYPE, ""); devfd = open(_PATH_DEV, O_RDONLY); if (devfd < 0) err(1, "open(/dev)"); cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_IOCTL, CAP_LOOKUP, CAP_PWRITE); if (cap_rights_limit(devfd, &rights) < 0 && errno != ENOSYS) err(1, "can't limit devfd rights"); /* * Can't use capsicum helpers here because we need the additional * FIODGNAME ioctl. */ cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_IOCTL, CAP_READ, CAP_WRITE); if ((cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) || (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS) || (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS) || (cap_ioctls_limit(STDIN_FILENO, cmds, nitems(cmds)) < 0 && errno != ENOSYS) || (cap_ioctls_limit(STDOUT_FILENO, cmds, nitems(cmds)) < 0 && errno != ENOSYS) || (cap_ioctls_limit(STDERR_FILENO, cmds, nitems(cmds)) < 0 && errno != ENOSYS) || (cap_fcntls_limit(STDIN_FILENO, CAP_FCNTL_GETFL) < 0 && errno != ENOSYS) || (cap_fcntls_limit(STDOUT_FILENO, CAP_FCNTL_GETFL) < 0 && errno != ENOSYS) || (cap_fcntls_limit(STDERR_FILENO, CAP_FCNTL_GETFL) < 0 && errno != ENOSYS)) err(1, "can't limit stdio rights"); caph_cache_catpages(); caph_cache_tzdata(); /* * Cache UTX database fds. */ setutxent(); /* * Determine our login name before we reopen() stdout * and before entering capability sandbox. */ myuid = getuid(); if ((login = getlogin()) == NULL) { if ((pwd = getpwuid(myuid))) login = pwd->pw_name; else login = "???"; } - if (cap_enter() < 0 && errno != ENOSYS) + if (caph_enter() < 0) err(1, "cap_enter"); while (getopt(argc, argv, "") != -1) usage(); argc -= optind; argv += optind; /* check that sender has write enabled */ if (isatty(fileno(stdin))) myttyfd = fileno(stdin); else if (isatty(fileno(stdout))) myttyfd = fileno(stdout); else if (isatty(fileno(stderr))) myttyfd = fileno(stderr); else errx(1, "can't find your tty"); if (!(mytty = ttyname(myttyfd))) errx(1, "can't find your tty's name"); if (!strncmp(mytty, _PATH_DEV, strlen(_PATH_DEV))) mytty += strlen(_PATH_DEV); if (term_chk(devfd, mytty, &msgsok, &atime, 1)) exit(1); if (!msgsok) errx(1, "you have write permission turned off"); /* check args */ switch (argc) { case 1: search_utmp(devfd, argv[0], tty, mytty, myuid); do_write(devfd, tty, mytty, login); break; case 2: if (!strncmp(argv[1], _PATH_DEV, strlen(_PATH_DEV))) argv[1] += strlen(_PATH_DEV); if (utmp_chk(argv[0], argv[1])) errx(1, "%s is not logged in on %s", argv[0], argv[1]); if (term_chk(devfd, argv[1], &msgsok, &atime, 1)) exit(1); if (myuid && !msgsok) errx(1, "%s has messages disabled on %s", argv[0], argv[1]); do_write(devfd, argv[1], mytty, login); break; default: usage(); } done(0); return (0); } static void usage(void) { (void)fprintf(stderr, "usage: write user [tty]\n"); exit(1); } /* * utmp_chk - checks that the given user is actually logged in on * the given tty */ int utmp_chk(char *user, char *tty) { struct utmpx lu, *u; strncpy(lu.ut_line, tty, sizeof lu.ut_line); setutxent(); while ((u = getutxline(&lu)) != NULL) if (u->ut_type == USER_PROCESS && strcmp(user, u->ut_user) == 0) { endutxent(); return(0); } endutxent(); return(1); } /* * search_utmp - search utmp for the "best" terminal to write to * * Ignores terminals with messages disabled, and of the rest, returns * the one with the most recent access time. Returns as value the number * of the user's terminals with messages enabled, or -1 if the user is * not logged in at all. * * Special case for writing to yourself - ignore the terminal you're * writing from, unless that's the only terminal with messages enabled. */ void search_utmp(int devfd, char *user, char *tty, char *mytty, uid_t myuid) { struct utmpx *u; time_t bestatime, atime; int nloggedttys, nttys, msgsok, user_is_me; nloggedttys = nttys = 0; bestatime = 0; user_is_me = 0; setutxent(); while ((u = getutxent()) != NULL) if (u->ut_type == USER_PROCESS && strcmp(user, u->ut_user) == 0) { ++nloggedttys; if (term_chk(devfd, u->ut_line, &msgsok, &atime, 0)) continue; /* bad term? skip */ if (myuid && !msgsok) continue; /* skip ttys with msgs off */ if (strcmp(u->ut_line, mytty) == 0) { user_is_me = 1; continue; /* don't write to yourself */ } ++nttys; if (atime > bestatime) { bestatime = atime; (void)strlcpy(tty, u->ut_line, MAXPATHLEN); } } endutxent(); if (nloggedttys == 0) errx(1, "%s is not logged in", user); if (nttys == 0) { if (user_is_me) { /* ok, so write to yourself! */ (void)strlcpy(tty, mytty, MAXPATHLEN); return; } errx(1, "%s has messages disabled", user); } else if (nttys > 1) { warnx("%s is logged in more than once; writing to %s", user, tty); } } /* * term_chk - check that a terminal exists, and get the message bit * and the access time */ int term_chk(int devfd, char *tty, int *msgsokP, time_t *atimeP, int showerror) { struct stat s; if (fstatat(devfd, tty, &s, 0) < 0) { if (showerror) warn("%s%s", _PATH_DEV, tty); return(1); } *msgsokP = (s.st_mode & (S_IWRITE >> 3)) != 0; /* group write bit */ *atimeP = s.st_atime; return(0); } /* * do_write - actually make the connection */ void do_write(int devfd, char *tty, char *mytty, const char *login) { char *nows; time_t now; char host[MAXHOSTNAMELEN]; wchar_t line[512]; int fd; fd = openat(devfd, tty, O_WRONLY); if (fd < 0) err(1, "openat(%s%s)", _PATH_DEV, tty); fclose(stdout); stdout = fdopen(fd, "w"); if (stdout == NULL) err(1, "%s%s", _PATH_DEV, tty); (void)signal(SIGINT, done); (void)signal(SIGHUP, done); /* print greeting */ if (gethostname(host, sizeof(host)) < 0) (void)strcpy(host, "???"); now = time((time_t *)NULL); nows = ctime(&now); nows[16] = '\0'; (void)printf("\r\n\007\007\007Message from %s@%s on %s at %s ...\r\n", login, host, mytty, nows + 11); while (fgetws(line, sizeof(line)/sizeof(wchar_t), stdin) != NULL) wr_fputs(line); } /* * done - cleanup and exit */ void done(int n __unused) { (void)printf("EOF\r\n"); exit(0); } /* * wr_fputs - like fputs(), but makes control characters visible and * turns \n into \r\n */ void wr_fputs(wchar_t *s) { #define PUTC(c) if (putwchar(c) == WEOF) err(1, NULL); for (; *s != L'\0'; ++s) { if (*s == L'\n') { PUTC(L'\r'); PUTC(L'\n'); } else if (iswprint(*s) || iswspace(*s)) { PUTC(*s); } else { wprintf(L"<0x%X>", *s); } } return; #undef PUTC } Index: head/usr.bin/yes/yes.c =================================================================== --- head/usr.bin/yes/yes.c (revision 335394) +++ head/usr.bin/yes/yes.c (revision 335395) @@ -1,88 +1,88 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1987, 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1987, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)yes.c 8.1 (Berkeley) 6/6/93"; #else static const char rcsid[] = "$FreeBSD$"; #endif #endif /* not lint */ #include #include #include #include #include int main(int argc, char **argv) { char buf[8192]; char y[2] = { 'y', '\n' }; char * exp = y; size_t buflen = 0; size_t explen = sizeof(y); size_t more; ssize_t ret; - if (caph_limit_stdio() < 0 || (cap_enter() < 0 && errno != ENOSYS)) + if (caph_limit_stdio() < 0 || caph_enter() < 0) err(1, "capsicum"); if (argc > 1) { exp = argv[1]; explen = strlen(exp) + 1; exp[explen - 1] = '\n'; } if (explen <= sizeof(buf)) { while (buflen < sizeof(buf) - explen) { memcpy(buf + buflen, exp, explen); buflen += explen; } exp = buf; explen = buflen; } more = explen; while ((ret = write(STDOUT_FILENO, exp + (explen - more), more)) > 0) if ((more -= ret) == 0) more = explen; err(1, "stdout"); /*NOTREACHED*/ } Index: head/usr.sbin/bhyve/bhyverun.c =================================================================== --- head/usr.sbin/bhyve/bhyverun.c (revision 335394) +++ head/usr.sbin/bhyve/bhyverun.c (revision 335395) @@ -1,1137 +1,1137 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2011 NetApp, Inc. * 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. * * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``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 NETAPP, INC 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. * * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #ifndef WITHOUT_CAPSICUM #include #endif #include #include #include #include #ifndef WITHOUT_CAPSICUM #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef WITHOUT_CAPSICUM #include #endif #include #include "bhyverun.h" #include "acpi.h" #include "atkbdc.h" #include "inout.h" #include "dbgport.h" #include "fwctl.h" #include "gdb.h" #include "ioapic.h" #include "mem.h" #include "mevent.h" #include "mptbl.h" #include "pci_emul.h" #include "pci_irq.h" #include "pci_lpc.h" #include "smbiostbl.h" #include "xmsr.h" #include "spinup_ap.h" #include "rtc.h" #define GUEST_NIO_PORT 0x488 /* guest upcalls via i/o port */ #define MB (1024UL * 1024) #define GB (1024UL * MB) typedef int (*vmexit_handler_t)(struct vmctx *, struct vm_exit *, int *vcpu); extern int vmexit_task_switch(struct vmctx *, struct vm_exit *, int *vcpu); char *vmname; int guest_ncpus; uint16_t cores, maxcpus, sockets, threads; char *guest_uuid_str; static int guest_vmexit_on_hlt, guest_vmexit_on_pause; static int virtio_msix = 1; static int x2apic_mode = 0; /* default is xAPIC */ static int strictio; static int strictmsr = 1; static int acpi; static char *progname; static const int BSP = 0; static cpuset_t cpumask; static void vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip); static struct vm_exit vmexit[VM_MAXCPU]; struct bhyvestats { uint64_t vmexit_bogus; uint64_t vmexit_reqidle; uint64_t vmexit_hlt; uint64_t vmexit_pause; uint64_t vmexit_mtrap; uint64_t vmexit_inst_emul; uint64_t cpu_switch_rotate; uint64_t cpu_switch_direct; } stats; struct mt_vmm_info { pthread_t mt_thr; struct vmctx *mt_ctx; int mt_vcpu; } mt_vmm_info[VM_MAXCPU]; static cpuset_t *vcpumap[VM_MAXCPU] = { NULL }; static void usage(int code) { fprintf(stderr, "Usage: %s [-abehuwxACHPSWY]\n" " %*s [-c [[cpus=]numcpus][,sockets=n][,cores=n][,threads=n]]\n" " %*s [-g ] [-l ]\n" " %*s [-m mem] [-p vcpu:hostcpu] [-s ] [-U uuid] \n" " -a: local apic is in xAPIC mode (deprecated)\n" " -A: create ACPI tables\n" " -c: number of cpus and/or topology specification\n" " -C: include guest memory in core file\n" " -e: exit on unhandled I/O access\n" " -g: gdb port\n" " -h: help\n" " -H: vmexit from the guest on hlt\n" " -l: LPC device configuration\n" " -m: memory size in MB\n" " -p: pin 'vcpu' to 'hostcpu'\n" " -P: vmexit from the guest on pause\n" " -s: PCI slot config\n" " -S: guest memory cannot be swapped\n" " -u: RTC keeps UTC time\n" " -U: uuid\n" " -w: ignore unimplemented MSRs\n" " -W: force virtio to use single-vector MSI\n" " -x: local apic is in x2APIC mode\n" " -Y: disable MPtable generation\n", progname, (int)strlen(progname), "", (int)strlen(progname), "", (int)strlen(progname), ""); exit(code); } /* * XXX This parser is known to have the following issues: * 1. It accepts null key=value tokens ",,". * 2. It accepts whitespace after = and before value. * 3. Values out of range of INT are silently wrapped. * 4. It doesn't check non-final values. * 5. The apparently bogus limits of UINT16_MAX are for future expansion. * * The acceptance of a null specification ('-c ""') is by design to match the * manual page syntax specification, this results in a topology of 1 vCPU. */ static int topology_parse(const char *opt) { uint64_t ncpus; int c, chk, n, s, t, tmp; char *cp, *str; bool ns, scts; c = 1, n = 1, s = 1, t = 1; ns = false, scts = false; str = strdup(opt); if (str == NULL) goto out; while ((cp = strsep(&str, ",")) != NULL) { if (sscanf(cp, "%i%n", &tmp, &chk) == 1) { n = tmp; ns = true; } else if (sscanf(cp, "cpus=%i%n", &tmp, &chk) == 1) { n = tmp; ns = true; } else if (sscanf(cp, "sockets=%i%n", &tmp, &chk) == 1) { s = tmp; scts = true; } else if (sscanf(cp, "cores=%i%n", &tmp, &chk) == 1) { c = tmp; scts = true; } else if (sscanf(cp, "threads=%i%n", &tmp, &chk) == 1) { t = tmp; scts = true; #ifdef notyet /* Do not expose this until vmm.ko implements it */ } else if (sscanf(cp, "maxcpus=%i%n", &tmp, &chk) == 1) { m = tmp; #endif /* Skip the empty argument case from -c "" */ } else if (cp[0] == '\0') continue; else goto out; /* Any trailing garbage causes an error */ if (cp[chk] != '\0') goto out; } free(str); str = NULL; /* * Range check 1 <= n <= UINT16_MAX all values */ if (n < 1 || s < 1 || c < 1 || t < 1 || n > UINT16_MAX || s > UINT16_MAX || c > UINT16_MAX || t > UINT16_MAX) return (-1); /* If only the cpus was specified, use that as sockets */ if (!scts) s = n; /* * Compute sockets * cores * threads avoiding overflow * The range check above insures these are 16 bit values * If n was specified check it against computed ncpus */ ncpus = (uint64_t)s * c * t; if (ncpus > UINT16_MAX || (ns && n != ncpus)) return (-1); guest_ncpus = ncpus; sockets = s; cores = c; threads = t; return(0); out: free(str); return (-1); } static int pincpu_parse(const char *opt) { int vcpu, pcpu; if (sscanf(opt, "%d:%d", &vcpu, &pcpu) != 2) { fprintf(stderr, "invalid format: %s\n", opt); return (-1); } if (vcpu < 0 || vcpu >= VM_MAXCPU) { fprintf(stderr, "vcpu '%d' outside valid range from 0 to %d\n", vcpu, VM_MAXCPU - 1); return (-1); } if (pcpu < 0 || pcpu >= CPU_SETSIZE) { fprintf(stderr, "hostcpu '%d' outside valid range from " "0 to %d\n", pcpu, CPU_SETSIZE - 1); return (-1); } if (vcpumap[vcpu] == NULL) { if ((vcpumap[vcpu] = malloc(sizeof(cpuset_t))) == NULL) { perror("malloc"); return (-1); } CPU_ZERO(vcpumap[vcpu]); } CPU_SET(pcpu, vcpumap[vcpu]); return (0); } void vm_inject_fault(void *arg, int vcpu, int vector, int errcode_valid, int errcode) { struct vmctx *ctx; int error, restart_instruction; ctx = arg; restart_instruction = 1; error = vm_inject_exception(ctx, vcpu, vector, errcode_valid, errcode, restart_instruction); assert(error == 0); } void * paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len) { return (vm_map_gpa(ctx, gaddr, len)); } int fbsdrun_vmexit_on_pause(void) { return (guest_vmexit_on_pause); } int fbsdrun_vmexit_on_hlt(void) { return (guest_vmexit_on_hlt); } int fbsdrun_virtio_msix(void) { return (virtio_msix); } static void * fbsdrun_start_thread(void *param) { char tname[MAXCOMLEN + 1]; struct mt_vmm_info *mtp; int vcpu; mtp = param; vcpu = mtp->mt_vcpu; snprintf(tname, sizeof(tname), "vcpu %d", vcpu); pthread_set_name_np(mtp->mt_thr, tname); gdb_cpu_add(vcpu); vm_loop(mtp->mt_ctx, vcpu, vmexit[vcpu].rip); /* not reached */ exit(1); return (NULL); } void fbsdrun_addcpu(struct vmctx *ctx, int fromcpu, int newcpu, uint64_t rip) { int error; assert(fromcpu == BSP); /* * The 'newcpu' must be activated in the context of 'fromcpu'. If * vm_activate_cpu() is delayed until newcpu's pthread starts running * then vmm.ko is out-of-sync with bhyve and this can create a race * with vm_suspend(). */ error = vm_activate_cpu(ctx, newcpu); if (error != 0) err(EX_OSERR, "could not activate CPU %d", newcpu); CPU_SET_ATOMIC(newcpu, &cpumask); /* * Set up the vmexit struct to allow execution to start * at the given RIP */ vmexit[newcpu].rip = rip; vmexit[newcpu].inst_length = 0; mt_vmm_info[newcpu].mt_ctx = ctx; mt_vmm_info[newcpu].mt_vcpu = newcpu; error = pthread_create(&mt_vmm_info[newcpu].mt_thr, NULL, fbsdrun_start_thread, &mt_vmm_info[newcpu]); assert(error == 0); } static int fbsdrun_deletecpu(struct vmctx *ctx, int vcpu) { if (!CPU_ISSET(vcpu, &cpumask)) { fprintf(stderr, "Attempting to delete unknown cpu %d\n", vcpu); exit(1); } CPU_CLR_ATOMIC(vcpu, &cpumask); return (CPU_EMPTY(&cpumask)); } static int vmexit_handle_notify(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu, uint32_t eax) { #if BHYVE_DEBUG /* * put guest-driven debug here */ #endif return (VMEXIT_CONTINUE); } static int vmexit_inout(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) { int error; int bytes, port, in, out; int vcpu; vcpu = *pvcpu; port = vme->u.inout.port; bytes = vme->u.inout.bytes; in = vme->u.inout.in; out = !in; /* Extra-special case of host notifications */ if (out && port == GUEST_NIO_PORT) { error = vmexit_handle_notify(ctx, vme, pvcpu, vme->u.inout.eax); return (error); } error = emulate_inout(ctx, vcpu, vme, strictio); if (error) { fprintf(stderr, "Unhandled %s%c 0x%04x at 0x%lx\n", in ? "in" : "out", bytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'), port, vmexit->rip); return (VMEXIT_ABORT); } else { return (VMEXIT_CONTINUE); } } static int vmexit_rdmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) { uint64_t val; uint32_t eax, edx; int error; val = 0; error = emulate_rdmsr(ctx, *pvcpu, vme->u.msr.code, &val); if (error != 0) { fprintf(stderr, "rdmsr to register %#x on vcpu %d\n", vme->u.msr.code, *pvcpu); if (strictmsr) { vm_inject_gp(ctx, *pvcpu); return (VMEXIT_CONTINUE); } } eax = val; error = vm_set_register(ctx, *pvcpu, VM_REG_GUEST_RAX, eax); assert(error == 0); edx = val >> 32; error = vm_set_register(ctx, *pvcpu, VM_REG_GUEST_RDX, edx); assert(error == 0); return (VMEXIT_CONTINUE); } static int vmexit_wrmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) { int error; error = emulate_wrmsr(ctx, *pvcpu, vme->u.msr.code, vme->u.msr.wval); if (error != 0) { fprintf(stderr, "wrmsr to register %#x(%#lx) on vcpu %d\n", vme->u.msr.code, vme->u.msr.wval, *pvcpu); if (strictmsr) { vm_inject_gp(ctx, *pvcpu); return (VMEXIT_CONTINUE); } } return (VMEXIT_CONTINUE); } static int vmexit_spinup_ap(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) { (void)spinup_ap(ctx, *pvcpu, vme->u.spinup_ap.vcpu, vme->u.spinup_ap.rip); return (VMEXIT_CONTINUE); } #define DEBUG_EPT_MISCONFIG #ifdef DEBUG_EPT_MISCONFIG #define EXIT_REASON_EPT_MISCONFIG 49 #define VMCS_GUEST_PHYSICAL_ADDRESS 0x00002400 #define VMCS_IDENT(x) ((x) | 0x80000000) static uint64_t ept_misconfig_gpa, ept_misconfig_pte[4]; static int ept_misconfig_ptenum; #endif static int vmexit_vmx(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { fprintf(stderr, "vm exit[%d]\n", *pvcpu); fprintf(stderr, "\treason\t\tVMX\n"); fprintf(stderr, "\trip\t\t0x%016lx\n", vmexit->rip); fprintf(stderr, "\tinst_length\t%d\n", vmexit->inst_length); fprintf(stderr, "\tstatus\t\t%d\n", vmexit->u.vmx.status); fprintf(stderr, "\texit_reason\t%u\n", vmexit->u.vmx.exit_reason); fprintf(stderr, "\tqualification\t0x%016lx\n", vmexit->u.vmx.exit_qualification); fprintf(stderr, "\tinst_type\t\t%d\n", vmexit->u.vmx.inst_type); fprintf(stderr, "\tinst_error\t\t%d\n", vmexit->u.vmx.inst_error); #ifdef DEBUG_EPT_MISCONFIG if (vmexit->u.vmx.exit_reason == EXIT_REASON_EPT_MISCONFIG) { vm_get_register(ctx, *pvcpu, VMCS_IDENT(VMCS_GUEST_PHYSICAL_ADDRESS), &ept_misconfig_gpa); vm_get_gpa_pmap(ctx, ept_misconfig_gpa, ept_misconfig_pte, &ept_misconfig_ptenum); fprintf(stderr, "\tEPT misconfiguration:\n"); fprintf(stderr, "\t\tGPA: %#lx\n", ept_misconfig_gpa); fprintf(stderr, "\t\tPTE(%d): %#lx %#lx %#lx %#lx\n", ept_misconfig_ptenum, ept_misconfig_pte[0], ept_misconfig_pte[1], ept_misconfig_pte[2], ept_misconfig_pte[3]); } #endif /* DEBUG_EPT_MISCONFIG */ return (VMEXIT_ABORT); } static int vmexit_svm(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { fprintf(stderr, "vm exit[%d]\n", *pvcpu); fprintf(stderr, "\treason\t\tSVM\n"); fprintf(stderr, "\trip\t\t0x%016lx\n", vmexit->rip); fprintf(stderr, "\tinst_length\t%d\n", vmexit->inst_length); fprintf(stderr, "\texitcode\t%#lx\n", vmexit->u.svm.exitcode); fprintf(stderr, "\texitinfo1\t%#lx\n", vmexit->u.svm.exitinfo1); fprintf(stderr, "\texitinfo2\t%#lx\n", vmexit->u.svm.exitinfo2); return (VMEXIT_ABORT); } static int vmexit_bogus(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { assert(vmexit->inst_length == 0); stats.vmexit_bogus++; return (VMEXIT_CONTINUE); } static int vmexit_reqidle(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { assert(vmexit->inst_length == 0); stats.vmexit_reqidle++; return (VMEXIT_CONTINUE); } static int vmexit_hlt(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { stats.vmexit_hlt++; /* * Just continue execution with the next instruction. We use * the HLT VM exit as a way to be friendly with the host * scheduler. */ return (VMEXIT_CONTINUE); } static int vmexit_pause(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { stats.vmexit_pause++; return (VMEXIT_CONTINUE); } static int vmexit_mtrap(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { assert(vmexit->inst_length == 0); stats.vmexit_mtrap++; gdb_cpu_mtrap(*pvcpu); return (VMEXIT_CONTINUE); } static int vmexit_inst_emul(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { int err, i; struct vie *vie; stats.vmexit_inst_emul++; vie = &vmexit->u.inst_emul.vie; err = emulate_mem(ctx, *pvcpu, vmexit->u.inst_emul.gpa, vie, &vmexit->u.inst_emul.paging); if (err) { if (err == ESRCH) { fprintf(stderr, "Unhandled memory access to 0x%lx\n", vmexit->u.inst_emul.gpa); } fprintf(stderr, "Failed to emulate instruction ["); for (i = 0; i < vie->num_valid; i++) { fprintf(stderr, "0x%02x%s", vie->inst[i], i != (vie->num_valid - 1) ? " " : ""); } fprintf(stderr, "] at 0x%lx\n", vmexit->rip); return (VMEXIT_ABORT); } return (VMEXIT_CONTINUE); } static pthread_mutex_t resetcpu_mtx = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t resetcpu_cond = PTHREAD_COND_INITIALIZER; static int vmexit_suspend(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { enum vm_suspend_how how; how = vmexit->u.suspended.how; fbsdrun_deletecpu(ctx, *pvcpu); if (*pvcpu != BSP) { pthread_mutex_lock(&resetcpu_mtx); pthread_cond_signal(&resetcpu_cond); pthread_mutex_unlock(&resetcpu_mtx); pthread_exit(NULL); } pthread_mutex_lock(&resetcpu_mtx); while (!CPU_EMPTY(&cpumask)) { pthread_cond_wait(&resetcpu_cond, &resetcpu_mtx); } pthread_mutex_unlock(&resetcpu_mtx); switch (how) { case VM_SUSPEND_RESET: exit(0); case VM_SUSPEND_POWEROFF: exit(1); case VM_SUSPEND_HALT: exit(2); case VM_SUSPEND_TRIPLEFAULT: exit(3); default: fprintf(stderr, "vmexit_suspend: invalid reason %d\n", how); exit(100); } return (0); /* NOTREACHED */ } static int vmexit_debug(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { gdb_cpu_suspend(*pvcpu); return (VMEXIT_CONTINUE); } static vmexit_handler_t handler[VM_EXITCODE_MAX] = { [VM_EXITCODE_INOUT] = vmexit_inout, [VM_EXITCODE_INOUT_STR] = vmexit_inout, [VM_EXITCODE_VMX] = vmexit_vmx, [VM_EXITCODE_SVM] = vmexit_svm, [VM_EXITCODE_BOGUS] = vmexit_bogus, [VM_EXITCODE_REQIDLE] = vmexit_reqidle, [VM_EXITCODE_RDMSR] = vmexit_rdmsr, [VM_EXITCODE_WRMSR] = vmexit_wrmsr, [VM_EXITCODE_MTRAP] = vmexit_mtrap, [VM_EXITCODE_INST_EMUL] = vmexit_inst_emul, [VM_EXITCODE_SPINUP_AP] = vmexit_spinup_ap, [VM_EXITCODE_SUSPENDED] = vmexit_suspend, [VM_EXITCODE_TASK_SWITCH] = vmexit_task_switch, [VM_EXITCODE_DEBUG] = vmexit_debug, }; static void vm_loop(struct vmctx *ctx, int vcpu, uint64_t startrip) { int error, rc; enum vm_exitcode exitcode; cpuset_t active_cpus; if (vcpumap[vcpu] != NULL) { error = pthread_setaffinity_np(pthread_self(), sizeof(cpuset_t), vcpumap[vcpu]); assert(error == 0); } error = vm_active_cpus(ctx, &active_cpus); assert(CPU_ISSET(vcpu, &active_cpus)); error = vm_set_register(ctx, vcpu, VM_REG_GUEST_RIP, startrip); assert(error == 0); while (1) { error = vm_run(ctx, vcpu, &vmexit[vcpu]); if (error != 0) break; exitcode = vmexit[vcpu].exitcode; if (exitcode >= VM_EXITCODE_MAX || handler[exitcode] == NULL) { fprintf(stderr, "vm_loop: unexpected exitcode 0x%x\n", exitcode); exit(1); } rc = (*handler[exitcode])(ctx, &vmexit[vcpu], &vcpu); switch (rc) { case VMEXIT_CONTINUE: break; case VMEXIT_ABORT: abort(); default: exit(1); } } fprintf(stderr, "vm_run error %d, errno %d\n", error, errno); } static int num_vcpus_allowed(struct vmctx *ctx) { int tmp, error; error = vm_get_capability(ctx, BSP, VM_CAP_UNRESTRICTED_GUEST, &tmp); /* * The guest is allowed to spinup more than one processor only if the * UNRESTRICTED_GUEST capability is available. */ if (error == 0) return (VM_MAXCPU); else return (1); } void fbsdrun_set_capabilities(struct vmctx *ctx, int cpu) { int err, tmp; if (fbsdrun_vmexit_on_hlt()) { err = vm_get_capability(ctx, cpu, VM_CAP_HALT_EXIT, &tmp); if (err < 0) { fprintf(stderr, "VM exit on HLT not supported\n"); exit(1); } vm_set_capability(ctx, cpu, VM_CAP_HALT_EXIT, 1); if (cpu == BSP) handler[VM_EXITCODE_HLT] = vmexit_hlt; } if (fbsdrun_vmexit_on_pause()) { /* * pause exit support required for this mode */ err = vm_get_capability(ctx, cpu, VM_CAP_PAUSE_EXIT, &tmp); if (err < 0) { fprintf(stderr, "SMP mux requested, no pause support\n"); exit(1); } vm_set_capability(ctx, cpu, VM_CAP_PAUSE_EXIT, 1); if (cpu == BSP) handler[VM_EXITCODE_PAUSE] = vmexit_pause; } if (x2apic_mode) err = vm_set_x2apic_state(ctx, cpu, X2APIC_ENABLED); else err = vm_set_x2apic_state(ctx, cpu, X2APIC_DISABLED); if (err) { fprintf(stderr, "Unable to set x2apic state (%d)\n", err); exit(1); } vm_set_capability(ctx, cpu, VM_CAP_ENABLE_INVPCID, 1); } static struct vmctx * do_open(const char *vmname) { struct vmctx *ctx; int error; bool reinit, romboot; #ifndef WITHOUT_CAPSICUM cap_rights_t rights; const cap_ioctl_t *cmds; size_t ncmds; #endif reinit = romboot = false; if (lpc_bootrom()) romboot = true; error = vm_create(vmname); if (error) { if (errno == EEXIST) { if (romboot) { reinit = true; } else { /* * The virtual machine has been setup by the * userspace bootloader. */ } } else { perror("vm_create"); exit(1); } } else { if (!romboot) { /* * If the virtual machine was just created then a * bootrom must be configured to boot it. */ fprintf(stderr, "virtual machine cannot be booted\n"); exit(1); } } ctx = vm_open(vmname); if (ctx == NULL) { perror("vm_open"); exit(1); } #ifndef WITHOUT_CAPSICUM cap_rights_init(&rights, CAP_IOCTL, CAP_MMAP_RW); if (cap_rights_limit(vm_get_device_fd(ctx), &rights) == -1 && errno != ENOSYS) errx(EX_OSERR, "Unable to apply rights for sandbox"); vm_get_ioctls(&ncmds); cmds = vm_get_ioctls(NULL); if (cmds == NULL) errx(EX_OSERR, "out of memory"); if (cap_ioctls_limit(vm_get_device_fd(ctx), cmds, ncmds) == -1 && errno != ENOSYS) errx(EX_OSERR, "Unable to apply rights for sandbox"); free((cap_ioctl_t *)cmds); #endif if (reinit) { error = vm_reinit(ctx); if (error) { perror("vm_reinit"); exit(1); } } error = vm_set_topology(ctx, sockets, cores, threads, maxcpus); if (error) errx(EX_OSERR, "vm_set_topology"); return (ctx); } int main(int argc, char *argv[]) { int c, error, dbg_port, gdb_port, err, bvmcons; int max_vcpus, mptgen, memflags; int rtc_localtime; bool gdb_stop; struct vmctx *ctx; uint64_t rip; size_t memsize; char *optstr; bvmcons = 0; progname = basename(argv[0]); dbg_port = 0; gdb_port = 0; gdb_stop = false; guest_ncpus = 1; sockets = cores = threads = 1; maxcpus = 0; memsize = 256 * MB; mptgen = 1; rtc_localtime = 1; memflags = 0; optstr = "abehuwxACHIPSWYp:g:G:c:s:m:l:U:"; while ((c = getopt(argc, argv, optstr)) != -1) { switch (c) { case 'a': x2apic_mode = 0; break; case 'A': acpi = 1; break; case 'b': bvmcons = 1; break; case 'p': if (pincpu_parse(optarg) != 0) { errx(EX_USAGE, "invalid vcpu pinning " "configuration '%s'", optarg); } break; case 'c': if (topology_parse(optarg) != 0) { errx(EX_USAGE, "invalid cpu topology " "'%s'", optarg); } break; case 'C': memflags |= VM_MEM_F_INCORE; break; case 'g': dbg_port = atoi(optarg); break; case 'G': if (optarg[0] == 'w') { gdb_stop = true; optarg++; } gdb_port = atoi(optarg); break; case 'l': if (lpc_device_parse(optarg) != 0) { errx(EX_USAGE, "invalid lpc device " "configuration '%s'", optarg); } break; case 's': if (pci_parse_slot(optarg) != 0) exit(1); else break; case 'S': memflags |= VM_MEM_F_WIRED; break; case 'm': error = vm_parse_memsize(optarg, &memsize); if (error) errx(EX_USAGE, "invalid memsize '%s'", optarg); break; case 'H': guest_vmexit_on_hlt = 1; break; case 'I': /* * The "-I" option was used to add an ioapic to the * virtual machine. * * An ioapic is now provided unconditionally for each * virtual machine and this option is now deprecated. */ break; case 'P': guest_vmexit_on_pause = 1; break; case 'e': strictio = 1; break; case 'u': rtc_localtime = 0; break; case 'U': guest_uuid_str = optarg; break; case 'w': strictmsr = 0; break; case 'W': virtio_msix = 0; break; case 'x': x2apic_mode = 1; break; case 'Y': mptgen = 0; break; case 'h': usage(0); default: usage(1); } } argc -= optind; argv += optind; if (argc != 1) usage(1); vmname = argv[0]; ctx = do_open(vmname); max_vcpus = num_vcpus_allowed(ctx); if (guest_ncpus > max_vcpus) { fprintf(stderr, "%d vCPUs requested but only %d available\n", guest_ncpus, max_vcpus); exit(1); } fbsdrun_set_capabilities(ctx, BSP); vm_set_memflags(ctx, memflags); err = vm_setup_memory(ctx, memsize, VM_MMAP_ALL); if (err) { fprintf(stderr, "Unable to setup memory (%d)\n", errno); exit(1); } error = init_msr(); if (error) { fprintf(stderr, "init_msr error %d", error); exit(1); } init_mem(); init_inout(); atkbdc_init(ctx); pci_irq_init(ctx); ioapic_init(ctx); rtc_init(ctx, rtc_localtime); sci_init(ctx); /* * Exit if a device emulation finds an error in its initilization */ if (init_pci(ctx) != 0) exit(1); if (dbg_port != 0) init_dbgport(dbg_port); if (gdb_port != 0) init_gdb(ctx, gdb_port, gdb_stop); if (bvmcons) init_bvmcons(); if (lpc_bootrom()) { if (vm_set_capability(ctx, BSP, VM_CAP_UNRESTRICTED_GUEST, 1)) { fprintf(stderr, "ROM boot failed: unrestricted guest " "capability not available\n"); exit(1); } error = vcpu_reset(ctx, BSP); assert(error == 0); } error = vm_get_register(ctx, BSP, VM_REG_GUEST_RIP, &rip); assert(error == 0); /* * build the guest tables, MP etc. */ if (mptgen) { error = mptable_build(ctx, guest_ncpus); if (error) exit(1); } error = smbios_build(ctx); assert(error == 0); if (acpi) { error = acpi_build(ctx, guest_ncpus); assert(error == 0); } if (lpc_bootrom()) fwctl_init(); #ifndef WITHOUT_CAPSICUM caph_cache_catpages(); if (caph_limit_stdout() == -1 || caph_limit_stderr() == -1) errx(EX_OSERR, "Unable to apply rights for sandbox"); - if (cap_enter() == -1 && errno != ENOSYS) + if (caph_enter() == -1) errx(EX_OSERR, "cap_enter() failed"); #endif /* * Change the proc title to include the VM name. */ setproctitle("%s", vmname); /* * Add CPU 0 */ fbsdrun_addcpu(ctx, BSP, BSP, rip); /* * Head off to the main event dispatch loop */ mevent_dispatch(); exit(1); } Index: head/usr.sbin/rwhod/rwhod.c =================================================================== --- head/usr.sbin/rwhod/rwhod.c (revision 335394) +++ head/usr.sbin/rwhod/rwhod.c (revision 335395) @@ -1,783 +1,784 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1983, 1993 The Regents of the University of California. * Copyright (c) 2013 Mariusz Zaborski * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1983, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #if 0 #ifndef lint static char sccsid[] = "@(#)rwhod.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define UNPRIV_USER "daemon" #define UNPRIV_GROUP "daemon" #define NO_MULTICAST 0 /* multicast modes */ #define PER_INTERFACE_MULTICAST 1 #define SCOPED_MULTICAST 2 #define MAX_MULTICAST_SCOPE 32 /* "site-wide", by convention */ #define INADDR_WHOD_GROUP (u_long)0xe0000103 /* 224.0.1.3 */ /* (belongs in protocols/rwhod.h) */ int insecure_mode; int quiet_mode; int iff_flag = IFF_POINTOPOINT; int multicast_mode = NO_MULTICAST; int multicast_scope; struct sockaddr_in multicast_addr = { sizeof(multicast_addr), AF_INET, 0, { 0 }, { 0 } }; /* * Sleep interval. Don't forget to change the down time check in ruptime * if this is changed. */ #define SL_INTERVAL (3 * 60) char myname[MAXHOSTNAMELEN]; /* * We communicate with each neighbor in a list constructed at the time we're * started up. Neighbors are currently directly connected via a hardware * interface. */ struct neighbor { struct neighbor *n_next; char *n_name; /* interface name */ struct sockaddr *n_addr; /* who to send to */ int n_addrlen; /* size of address */ int n_flags; /* should forward?, interface flags */ }; struct neighbor *neighbors; struct whod mywd; struct servent *sp; int s; int fdp; pid_t pid_child_receiver; #define WHDRSIZE (int)(sizeof(mywd) - sizeof(mywd.wd_we)) int configure(int so); void getboottime(int signo __unused); void receiver_process(void); void rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo); void run_as(uid_t *uid, gid_t *gid); void quit(const char *msg); void sender_process(void); int verify(char *name, int maxlen); static void usage(void); #ifdef DEBUG char *interval(int time, char *updown); void Sendto(int s, const void *buf, size_t cc, int flags, const struct sockaddr *to, int tolen); #define sendto Sendto #endif /* * This version of Berkeley's rwhod has been modified to use IP multicast * datagrams, under control of a new command-line option: * * rwhod -m causes rwhod to use IP multicast (instead of * broadcast or unicast) on all interfaces that have * the IFF_MULTICAST flag set in their "ifnet" structs * (excluding the loopback interface). The multicast * reports are sent with a time-to-live of 1, to prevent * forwarding beyond the directly-connected subnet(s). * * rwhod -m causes rwhod to send IP multicast datagrams with a * time-to-live of , via a SINGLE interface rather * than all interfaces. must be between 0 and * MAX_MULTICAST_SCOPE, defined below. Note that "-m 1" * is different than "-m", in that "-m 1" specifies * transmission on one interface only. * * When "-m" is used without a argument, the program accepts multicast * rwhod reports from all multicast-capable interfaces. If a argument * is given, it accepts multicast reports from only one interface, the one * on which reports are sent (which may be controlled via the host's routing * table). Regardless of the "-m" option, the program accepts broadcast or * unicast reports from all interfaces. Thus, this program will hear the * reports of old, non-multicasting rwhods, but, if multicasting is used, * those old rwhods won't hear the reports generated by this program. * * -- Steve Deering, Stanford University, February 1989 */ int main(int argc, char *argv[]) { int on; char *cp; struct sockaddr_in soin; uid_t unpriv_uid; gid_t unpriv_gid; on = 1; if (getuid()) errx(1, "not super user"); run_as(&unpriv_uid, &unpriv_gid); argv++; argc--; while (argc > 0 && *argv[0] == '-') { if (strcmp(*argv, "-m") == 0) { if (argc > 1 && isdigit(*(argv + 1)[0])) { argv++; argc--; multicast_mode = SCOPED_MULTICAST; multicast_scope = atoi(*argv); if (multicast_scope > MAX_MULTICAST_SCOPE) { errx(1, "ttl must not exceed %u", MAX_MULTICAST_SCOPE); } } else { multicast_mode = PER_INTERFACE_MULTICAST; } } else if (strcmp(*argv, "-i") == 0) { insecure_mode = 1; } else if (strcmp(*argv, "-l") == 0) { quiet_mode = 1; } else if (strcmp(*argv, "-p") == 0) { iff_flag = 0; } else { usage(); } argv++; argc--; } if (argc > 0) usage(); #ifndef DEBUG daemon(1, 0); #endif (void) signal(SIGHUP, getboottime); openlog("rwhod", LOG_PID | LOG_NDELAY, LOG_DAEMON); sp = getservbyname("who", "udp"); if (sp == NULL) { syslog(LOG_ERR, "who/udp: unknown service"); exit(1); } if (chdir(_PATH_RWHODIR) < 0) { syslog(LOG_ERR, "%s: %m", _PATH_RWHODIR); exit(1); } /* * Establish host name as returned by system. */ if (gethostname(myname, sizeof(myname) - 1) < 0) { syslog(LOG_ERR, "gethostname: %m"); exit(1); } if ((cp = strchr(myname, '.')) != NULL) *cp = '\0'; strlcpy(mywd.wd_hostname, myname, sizeof(mywd.wd_hostname)); getboottime(0); if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "socket: %m"); exit(1); } if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) { syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); exit(1); } memset(&soin, 0, sizeof(soin)); soin.sin_len = sizeof(soin); soin.sin_family = AF_INET; soin.sin_port = sp->s_port; if (bind(s, (struct sockaddr *)&soin, sizeof(soin)) < 0) { syslog(LOG_ERR, "bind: %m"); exit(1); } if (setgid(unpriv_gid) != 0) { syslog(LOG_ERR, "setgid: %m"); exit(1); } if (setgroups(1, &unpriv_gid) != 0) { /* XXX BOGUS groups[0] = egid */ syslog(LOG_ERR, "setgroups: %m"); exit(1); } if (setuid(unpriv_uid) != 0) { syslog(LOG_ERR, "setuid: %m"); exit(1); } if (!configure(s)) exit(1); if (!quiet_mode) { pid_child_receiver = pdfork(&fdp, 0); if (pid_child_receiver == 0) { receiver_process(); } else if (pid_child_receiver > 0) { sender_process(); } else if (pid_child_receiver == -1) { if (errno == ENOSYS) { syslog(LOG_ERR, "The pdfork(2) system call is not available - kernel too old."); } else { syslog(LOG_ERR, "pdfork: %m"); } exit(1); } } else { receiver_process(); } } static void usage(void) { fprintf(stderr, "usage: rwhod [-i] [-p] [-l] [-m [ttl]]\n"); exit(1); } void run_as(uid_t *uid, gid_t *gid) { struct passwd *pw; struct group *gr; pw = getpwnam(UNPRIV_USER); if (pw == NULL) { syslog(LOG_ERR, "getpwnam(%s): %m", UNPRIV_USER); exit(1); } *uid = pw->pw_uid; gr = getgrnam(UNPRIV_GROUP); if (gr == NULL) { syslog(LOG_ERR, "getgrnam(%s): %m", UNPRIV_GROUP); exit(1); } *gid = gr->gr_gid; } /* * Check out host name for unprintables * and other funnies before allowing a file * to be created. Sorry, but blanks aren't allowed. */ int verify(char *name, int maxlen) { int size; size = 0; while (*name != '\0' && size < maxlen - 1) { if (!isascii((unsigned char)*name) || !(isalnum((unsigned char)*name) || ispunct((unsigned char)*name))) { return (0); } name++; size++; } *name = '\0'; return (size > 0); } void receiver_process(void) { struct sockaddr_in from; struct stat st; cap_rights_t rights; char path[64]; int dirfd; struct whod wd; socklen_t len; int cc, whod; time_t t; len = sizeof(from); dirfd = open(".", O_RDONLY | O_DIRECTORY); if (dirfd < 0) { syslog(LOG_WARNING, "%s: %m", _PATH_RWHODIR); exit(1); } cap_rights_init(&rights, CAP_CREATE, CAP_FSTAT, CAP_FTRUNCATE, CAP_LOOKUP, CAP_SEEK, CAP_WRITE); if (cap_rights_limit(dirfd, &rights) < 0 && errno != ENOSYS) { syslog(LOG_WARNING, "cap_rights_limit: %m"); exit(1); } - if (cap_enter() < 0 && errno != ENOSYS) { + if (caph_enter() < 0) { syslog(LOG_ERR, "cap_enter: %m"); exit(1); } for (;;) { cc = recvfrom(s, &wd, sizeof(wd), 0, (struct sockaddr *)&from, &len); if (cc <= 0) { if (cc < 0 && errno != EINTR) syslog(LOG_WARNING, "recv: %m"); continue; } if (from.sin_port != sp->s_port && !insecure_mode) { syslog(LOG_WARNING, "%d: bad source port from %s", ntohs(from.sin_port), inet_ntoa(from.sin_addr)); continue; } if (cc < WHDRSIZE) { syslog(LOG_WARNING, "short packet from %s", inet_ntoa(from.sin_addr)); continue; } if (wd.wd_vers != WHODVERSION) continue; if (wd.wd_type != WHODTYPE_STATUS) continue; if (!verify(wd.wd_hostname, sizeof(wd.wd_hostname))) { syslog(LOG_WARNING, "malformed host name from %s", inet_ntoa(from.sin_addr)); continue; } (void) snprintf(path, sizeof(path), "whod.%s", wd.wd_hostname); /* * Rather than truncating and growing the file each time, * use ftruncate if size is less than previous size. */ whod = openat(dirfd, path, O_WRONLY | O_CREAT, 0644); if (whod < 0) { syslog(LOG_WARNING, "%s: %m", path); continue; } cap_rights_init(&rights, CAP_FSTAT, CAP_FTRUNCATE, CAP_WRITE); if (cap_rights_limit(whod, &rights) < 0 && errno != ENOSYS) { syslog(LOG_WARNING, "cap_rights_limit: %m"); exit(1); } #if ENDIAN != BIG_ENDIAN { struct whoent *we; int i, n; n = (cc - WHDRSIZE) / sizeof(struct whoent); /* undo header byte swapping before writing to file */ wd.wd_sendtime = ntohl(wd.wd_sendtime); for (i = 0; i < 3; i++) wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]); wd.wd_boottime = ntohl(wd.wd_boottime); we = wd.wd_we; for (i = 0; i < n; i++) { we->we_idle = ntohl(we->we_idle); we->we_utmp.out_time = ntohl(we->we_utmp.out_time); we++; } } #endif (void) time(&t); wd.wd_recvtime = _time_to_int(t); (void) write(whod, (char *)&wd, cc); if (fstat(whod, &st) < 0 || st.st_size > cc) ftruncate(whod, cc); (void) close(whod); } (void) close(dirfd); } void sender_process(void) { int sendcount; double avenrun[3]; time_t now; int i, cc, status; struct utmpx *ut; struct stat stb; struct neighbor *np; struct whoent *we, *wend; sendcount = 0; for (;;) { we = mywd.wd_we; now = time(NULL); if (sendcount % 10 == 0) getboottime(0); sendcount++; wend = &mywd.wd_we[1024 / sizeof(struct whoent)]; setutxent(); while ((ut = getutxent()) != NULL && we < wend) { if (ut->ut_type != USER_PROCESS) continue; strncpy(we->we_utmp.out_line, ut->ut_line, sizeof(we->we_utmp.out_line)); strncpy(we->we_utmp.out_name, ut->ut_user, sizeof(we->we_utmp.out_name)); we->we_utmp.out_time = htonl(_time_to_time32(ut->ut_tv.tv_sec)); we++; } endutxent(); if (chdir(_PATH_DEV) < 0) { syslog(LOG_ERR, "chdir(%s): %m", _PATH_DEV); exit(1); } wend = we; for (we = mywd.wd_we; we < wend; we++) { if (stat(we->we_utmp.out_line, &stb) >= 0) we->we_idle = htonl(now - stb.st_atime); } (void) getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); for (i = 0; i < 3; i++) mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100)); cc = (char *)wend - (char *)&mywd; mywd.wd_sendtime = htonl(_time_to_time32(time(NULL))); mywd.wd_vers = WHODVERSION; mywd.wd_type = WHODTYPE_STATUS; if (multicast_mode == SCOPED_MULTICAST) { (void) sendto(s, (char *)&mywd, cc, 0, (struct sockaddr *)&multicast_addr, sizeof(multicast_addr)); } else { for (np = neighbors; np != NULL; np = np->n_next) { if (multicast_mode == PER_INTERFACE_MULTICAST && (np->n_flags & IFF_MULTICAST) != 0) { /* * Select the outgoing interface for the * multicast. */ if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &(((struct sockaddr_in *)np->n_addr)->sin_addr), sizeof(struct in_addr)) < 0) { syslog(LOG_ERR, "setsockopt IP_MULTICAST_IF: %m"); exit(1); } (void) sendto(s, (char *)&mywd, cc, 0, (struct sockaddr *)&multicast_addr, sizeof(multicast_addr)); } else { (void) sendto(s, (char *)&mywd, cc, 0, np->n_addr, np->n_addrlen); } } } if (chdir(_PATH_RWHODIR) < 0) { syslog(LOG_ERR, "chdir(%s): %m", _PATH_RWHODIR); exit(1); } if (waitpid(pid_child_receiver, &status, WNOHANG) == pid_child_receiver) { break; } sleep(SL_INTERVAL); } } void getboottime(int signo __unused) { int mib[2]; size_t size; struct timeval tm; mib[0] = CTL_KERN; mib[1] = KERN_BOOTTIME; size = sizeof(tm); if (sysctl(mib, nitems(mib), &tm, &size, NULL, 0) == -1) { syslog(LOG_ERR, "cannot get boottime: %m"); exit(1); } mywd.wd_boottime = htonl(_time_to_time32(tm.tv_sec)); } void quit(const char *msg) { syslog(LOG_ERR, "%s", msg); exit(1); } void rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) { struct sockaddr *sa; int i; memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info)); for (i = 0; i < RTAX_MAX && cp < cplim; i++) { if ((rtinfo->rti_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)cp; rtinfo->rti_info[i] = sa; cp += SA_SIZE(sa); } } /* * Figure out device configuration and select * networks which deserve status information. */ int configure(int so) { struct neighbor *np; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr_dl *sdl; size_t needed; int mib[6], flags, lflags, len; char *buf, *lim, *next; struct rt_addrinfo info; flags = 0; if (multicast_mode != NO_MULTICAST) { multicast_addr.sin_addr.s_addr = htonl(INADDR_WHOD_GROUP); multicast_addr.sin_port = sp->s_port; } if (multicast_mode == SCOPED_MULTICAST) { struct ip_mreq mreq; unsigned char ttl; mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP); mreq.imr_interface.s_addr = htonl(INADDR_ANY); if (setsockopt(so, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { syslog(LOG_ERR, "setsockopt IP_ADD_MEMBERSHIP: %m"); return (0); } ttl = multicast_scope; if (setsockopt(so, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) { syslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL: %m"); return (0); } return (1); } mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET; mib[4] = NET_RT_IFLIST; mib[5] = 0; if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) quit("route-sysctl-estimate"); if ((buf = malloc(needed)) == NULL) quit("malloc"); if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) quit("actual retrieval of interface table"); lim = buf + needed; sdl = NULL; /* XXX just to keep gcc -Wall happy */ for (next = buf; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *)next; if (ifm->ifm_type == RTM_IFINFO) { sdl = (struct sockaddr_dl *)(ifm + 1); flags = ifm->ifm_flags; continue; } if ((flags & IFF_UP) == 0) continue; lflags = IFF_BROADCAST | iff_flag; if (multicast_mode == PER_INTERFACE_MULTICAST) lflags |= IFF_MULTICAST; if ((flags & lflags) == 0) continue; if (ifm->ifm_type != RTM_NEWADDR) quit("out of sync parsing NET_RT_IFLIST"); ifam = (struct ifa_msghdr *)ifm; info.rti_addrs = ifam->ifam_addrs; rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info); /* gag, wish we could get rid of Internet dependencies */ #define dstaddr info.rti_info[RTAX_BRD] #define ifaddr info.rti_info[RTAX_IFA] #define IPADDR_SA(x) ((struct sockaddr_in *)(x))->sin_addr.s_addr #define PORT_SA(x) ((struct sockaddr_in *)(x))->sin_port if (dstaddr == 0 || dstaddr->sa_family != AF_INET) continue; PORT_SA(dstaddr) = sp->s_port; for (np = neighbors; np != NULL; np = np->n_next) { if (memcmp(sdl->sdl_data, np->n_name, sdl->sdl_nlen) == 0 && IPADDR_SA(np->n_addr) == IPADDR_SA(dstaddr)) { break; } } if (np != NULL) continue; len = sizeof(*np) + dstaddr->sa_len + sdl->sdl_nlen + 1; np = malloc(len); if (np == NULL) quit("malloc of neighbor structure"); memset(np, 0, len); np->n_flags = flags; np->n_addr = (struct sockaddr *)(np + 1); np->n_addrlen = dstaddr->sa_len; np->n_name = np->n_addrlen + (char *)np->n_addr; memcpy((char *)np->n_addr, (char *)dstaddr, np->n_addrlen); memcpy(np->n_name, sdl->sdl_data, sdl->sdl_nlen); if (multicast_mode == PER_INTERFACE_MULTICAST && (flags & IFF_MULTICAST) != 0 && (flags & IFF_LOOPBACK) == 0) { struct ip_mreq mreq; memcpy((char *)np->n_addr, (char *)ifaddr, np->n_addrlen); mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP); mreq.imr_interface.s_addr = ((struct sockaddr_in *)np->n_addr)->sin_addr.s_addr; if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { syslog(LOG_ERR, "setsockopt IP_ADD_MEMBERSHIP: %m"); #if 0 /* Fall back to broadcast on this if. */ np->n_flags &= ~IFF_MULTICAST; #else free(np); continue; #endif } } np->n_next = neighbors; neighbors = np; } free(buf); return (1); } #ifdef DEBUG void Sendto(int s, const void *buf, size_t cc, int flags, const struct sockaddr *to, int tolen) { struct whod *w; struct whoent *we; struct sockaddr_in *sin; w = (struct whod *)buf; sin = (struct sockaddr_in *)to; printf("sendto %x.%d\n", ntohl(sin->sin_addr.s_addr), ntohs(sin->sin_port)); printf("hostname %s %s\n", w->wd_hostname, interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), " up")); printf("load %4.2f, %4.2f, %4.2f\n", ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0, ntohl(w->wd_loadav[2]) / 100.0); cc -= WHDRSIZE; for (we = w->wd_we, cc /= sizeof(struct whoent); cc > 0; cc--, we++) { time_t t = _time32_to_time(ntohl(we->we_utmp.out_time)); printf("%-8.8s %s:%s %.12s", we->we_utmp.out_name, w->wd_hostname, we->we_utmp.out_line, ctime(&t) + 4); we->we_idle = ntohl(we->we_idle) / 60; if (we->we_idle != 0) { if (we->we_idle >= 100 * 60) we->we_idle = 100 * 60 - 1; if (we->we_idle >= 60) printf(" %2d", we->we_idle / 60); else printf(" "); printf(":%02d", we->we_idle % 60); } printf("\n"); } } char * interval(int time, char *updown) { static char resbuf[32]; int days, hours, minutes; if (time < 0 || time > 3 * 30 * 24 * 60 * 60) { (void) sprintf(resbuf, " %s ??:??", updown); return (resbuf); } minutes = (time + 59) / 60; /* round to minutes */ hours = minutes / 60; minutes %= 60; days = hours / 24; hours %= 24; if (days > 0) { (void) sprintf(resbuf, "%s %2d+%02d:%02d", updown, days, hours, minutes); } else { (void) sprintf(resbuf, "%s %2d:%02d", updown, hours, minutes); } return (resbuf); } #endif