aboutsummaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/beep/Makefile2
-rw-r--r--usr.bin/calendar/calendars/calendar.freebsd2
-rw-r--r--usr.bin/getconf/sysconf.gperf1
-rw-r--r--usr.bin/lsvfs/lsvfs.c51
-rw-r--r--usr.bin/lzmainfo/Makefile2
-rw-r--r--usr.bin/mandoc/Makefile3
-rw-r--r--usr.bin/mdo/mdo.c857
-rw-r--r--usr.bin/mididump/Makefile2
-rw-r--r--usr.bin/netstat/if.c3
-rw-r--r--usr.bin/sockstat/main.c194
-rw-r--r--usr.bin/sockstat/sockstat.112
-rwxr-xr-xusr.bin/tail/tests/tail_test.sh2
-rw-r--r--usr.bin/tcopy/tcopy.cc4
-rw-r--r--usr.bin/xz/Makefile2
-rw-r--r--usr.bin/xzdec/Makefile2
15 files changed, 1005 insertions, 134 deletions
diff --git a/usr.bin/beep/Makefile b/usr.bin/beep/Makefile
index 1f2548c24819..79735e6f354a 100644
--- a/usr.bin/beep/Makefile
+++ b/usr.bin/beep/Makefile
@@ -1,3 +1,5 @@
+PACKAGE=sound
+
PROG= beep
MAN= beep.1
LIBADD= m
diff --git a/usr.bin/calendar/calendars/calendar.freebsd b/usr.bin/calendar/calendars/calendar.freebsd
index 1ca63b371f65..b6e18083e24b 100644
--- a/usr.bin/calendar/calendars/calendar.freebsd
+++ b/usr.bin/calendar/calendars/calendar.freebsd
@@ -146,6 +146,7 @@
03/29 Dave Cottlehuber <dch@FreeBSD.org> born in Christchurch, New Zealand, 1973
03/29 Thierry Thomas <thierry@FreeBSD.org> born in Luxeuil les Bains, France, 1961
03/30 Po-Chuan Hsieh <sunpoet@FreeBSD.org> born in Taipei, Taiwan, Republic of China, 1978
+03/31 Vladlen Popolitov <vladlen@FreeBSD.org> born in Lipetsk region, USSR, 1969
04/01 Matthew Jacob <mjacob@FreeBSD.org> born in San Francisco, California, United States, 1958
04/01 Alexander V. Chernikov <melifaro@FreeBSD.org> born in Moscow, Russian Federation, 1984
04/01 Bill Fenner <fenner@FreeBSD.org> born in Bellefonte, Pennsylvania, United States, 1971
@@ -479,6 +480,7 @@
12/05 Ivan Voras <ivoras@FreeBSD.org> born in Slavonski Brod, Croatia, 1981
12/06 Stefan Farfeleder <stefanf@FreeBSD.org> born in Wien, Austria, 1980
12/08 Michael Tuexen <tuexen@FreeBSD.org> born in Oldenburg, Germany, 1966
+12/09 Tiago Gasiba <tiga@FreeBSD.org> born in Porto, Portugal, 1978
12/10 Hiroki Tagato <tagattie@FreeBSD.org> born in Shiga, Japan, 1971
12/11 Ganael Laplanche <martymac@FreeBSD.org> born in Reims, France, 1980
12/11 Koichiro Iwao <meta@FreeBSD.org> born in Oita, Japan, 1987
diff --git a/usr.bin/getconf/sysconf.gperf b/usr.bin/getconf/sysconf.gperf
index baf341c8962b..2bd75dd47851 100644
--- a/usr.bin/getconf/sysconf.gperf
+++ b/usr.bin/getconf/sysconf.gperf
@@ -47,6 +47,7 @@ OPEN_MAX, _SC_OPEN_MAX
PAGESIZE, _SC_PAGESIZE
PAGE_SIZE, _SC_PAGESIZE
PASS_MAX, _SC_PASS_MAX
+PHYS_PAGES, _SC_PHYS_PAGES
PTHREAD_DESTRUCTOR_ITERATIONS, _SC_THREAD_DESTRUCTOR_ITERATIONS
PTHREAD_KEYS_MAX, _SC_THREAD_KEYS_MAX
PTHREAD_STACK_MIN, _SC_THREAD_STACK_MIN
diff --git a/usr.bin/lsvfs/lsvfs.c b/usr.bin/lsvfs/lsvfs.c
index 5477d96434ac..8925b8988cd3 100644
--- a/usr.bin/lsvfs/lsvfs.c
+++ b/usr.bin/lsvfs/lsvfs.c
@@ -5,10 +5,12 @@
*
*/
+#include <sys/capsicum.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/sysctl.h>
+#include <capsicum_helpers.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
@@ -38,41 +40,42 @@ static const char *fmt_flags(int);
int
main(int argc, char **argv)
{
- struct xvfsconf vfc, *xvfsp;
+ struct xvfsconf *xvfsp;
size_t cnt, buflen;
int rv = 0;
argc--, argv++;
+ if (sysctlbyname("vfs.conflist", NULL, &buflen, NULL, 0) < 0)
+ err(EXIT_FAILURE, "sysctl(vfs.conflist)");
+ if ((xvfsp = malloc(buflen)) == NULL)
+ errx(EXIT_FAILURE, "malloc failed");
+ if (sysctlbyname("vfs.conflist", xvfsp, &buflen, NULL, 0) < 0)
+ err(EXIT_FAILURE, "sysctl(vfs.conflist)");
+ cnt = buflen / sizeof(struct xvfsconf);
+
+ caph_cache_catpages();
+ if (caph_enter() != 0)
+ err(EXIT_FAILURE, "failed to enter capability mode");
+
printf(HDRFMT, "Filesystem", "Num", "Refs", "Flags");
fputs(DASHES, stdout);
- if (argc > 0) {
- for (; argc > 0; argc--, argv++) {
- if (getvfsbyname(*argv, &vfc) == 0) {
- printf(FMT, vfc.vfc_name, vfc.vfc_typenum,
- vfc.vfc_refcount, fmt_flags(vfc.vfc_flags));
- } else {
- warnx("VFS %s unknown or not loaded", *argv);
- rv++;
+ for (size_t i = 0; i < cnt; i++) {
+ if (argc > 0) {
+ int j;
+ for (j = 0; j < argc; j++) {
+ if (strcmp(argv[j], xvfsp[i].vfc_name) == 0)
+ break;
}
+ if (j == argc)
+ continue;
}
- } else {
- if (sysctlbyname("vfs.conflist", NULL, &buflen, NULL, 0) < 0)
- err(EXIT_FAILURE, "sysctl(vfs.conflist)");
- if ((xvfsp = malloc(buflen)) == NULL)
- errx(EXIT_FAILURE, "malloc failed");
- if (sysctlbyname("vfs.conflist", xvfsp, &buflen, NULL, 0) < 0)
- err(EXIT_FAILURE, "sysctl(vfs.conflist)");
- cnt = buflen / sizeof(struct xvfsconf);
-
- for (size_t i = 0; i < cnt; i++) {
- printf(FMT, xvfsp[i].vfc_name, xvfsp[i].vfc_typenum,
- xvfsp[i].vfc_refcount,
- fmt_flags(xvfsp[i].vfc_flags));
- }
- free(xvfsp);
+
+ printf(FMT, xvfsp[i].vfc_name, xvfsp[i].vfc_typenum,
+ xvfsp[i].vfc_refcount, fmt_flags(xvfsp[i].vfc_flags));
}
+ free(xvfsp);
return (rv);
}
diff --git a/usr.bin/lzmainfo/Makefile b/usr.bin/lzmainfo/Makefile
index afde07163a01..e537e4c86083 100644
--- a/usr.bin/lzmainfo/Makefile
+++ b/usr.bin/lzmainfo/Makefile
@@ -1,3 +1,5 @@
+PACKAGE=xz
+
PROG= lzmainfo
XZDIR= ${SRCTOP}/contrib/xz/src
diff --git a/usr.bin/mandoc/Makefile b/usr.bin/mandoc/Makefile
index 2c7c3ed85040..181d4e16c8ee 100644
--- a/usr.bin/mandoc/Makefile
+++ b/usr.bin/mandoc/Makefile
@@ -60,8 +60,7 @@ LIB_SRCS= ${LIBMAN_SRCS} \
mandoc_xr.c \
msec.c \
preconv.c \
- read.c \
- compat_recallocarray.c \
+ read.c
HTML_SRCS= eqn_html.c \
html.c \
diff --git a/usr.bin/mdo/mdo.c b/usr.bin/mdo/mdo.c
index 8435fc17f26f..3eb5d4e5c23f 100644
--- a/usr.bin/mdo/mdo.c
+++ b/usr.bin/mdo/mdo.c
@@ -1,13 +1,24 @@
/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
* Copyright(c) 2024 Baptiste Daroussin <bapt@FreeBSD.org>
+ * Copyright (c) 2025 Kushagra Srivastava <kushagra1403@gmail.com>
+ * Copyright (c) 2025 The FreeBSD Foundation
*
- * SPDX-License-Identifier: BSD-2-Clause
+ * Portions of this software were developed by Olivier Certner
+ * <olce@FreeBSD.org> at Kumacom SARL under sponsorship from the FreeBSD
+ * Foundation.
*/
+#include <sys/errno.h>
#include <sys/limits.h>
+#include <sys/types.h>
#include <sys/ucred.h>
+#include <assert.h>
#include <err.h>
+#include <getopt.h>
+#include <grp.h>
#include <paths.h>
#include <pwd.h>
#include <stdbool.h>
@@ -16,84 +27,848 @@
#include <string.h>
#include <unistd.h>
+
static void
usage(void)
{
- fprintf(stderr, "usage: mdo [-u username] [-i] [--] [command [args]]\n");
- exit(EXIT_FAILURE);
+ fprintf(stderr,
+ "Usage: mdo [options] [--] [command [args...]]\n"
+ "\n"
+ "Options:\n"
+ " -u <user> Target user (name or UID; name sets groups)\n"
+ " -k Keep current user, allows selective overrides "
+ "(implies -i)\n"
+ " -i Keep current groups, unless explicitly overridden\n"
+ " -g <group> Override primary group (name or GID)\n"
+ " -G <g1,g2,...> Set supplementary groups (name or GID list)\n"
+ " -s <mods> Modify supplementary groups using:\n"
+ " @ (first) to reset, +group to add, -group to remove\n"
+ "\n"
+ "Advanced UID/GID overrides:\n"
+ " --euid <uid> Set effective UID\n"
+ " --ruid <uid> Set real UID\n"
+ " --svuid <uid> Set saved UID\n"
+ " --egid <gid> Set effective GID\n"
+ " --rgid <gid> Set real GID\n"
+ " --svgid <gid> Set saved GID\n"
+ "\n"
+ " -h Show this help message\n"
+ "\n"
+ "Examples:\n"
+ " mdo -u alice id\n"
+ " mdo -u 1001 -g wheel -G staff,operator sh\n"
+ " mdo -u bob -s +wheel,+operator id\n"
+ " mdo -k --ruid 1002 --egid 1004 id\n"
+ );
+ exit(1);
+}
+
+struct alloc {
+ void *start;
+ size_t size;
+};
+
+static const struct alloc ALLOC_INITIALIZER = {
+ .start = NULL,
+ .size = 0,
+};
+
+/*
+ * The default value should cover almost all cases.
+ *
+ * For getpwnam_r(), we assume:
+ * - 88 bytes for 'struct passwd'
+ * - Less than 16 bytes for the user name
+ * - A typical shadow hash of 106 bytes
+ * - Less than 16 bytes for the login class name
+ * - Less than 64 bytes for GECOS info
+ * - Less than 128 bytes for the home directory
+ * - Less than 32 bytes for the shell path
+ * Total: 256 + 88 + 106 = 450.
+ *
+ * For getgrnam_r(), we assume:
+ * - 32 bytes for 'struct group'
+ * - Less than 16 bytes for the group name
+ * - Some hash of 106 bytes
+ * - No more than 16 members, each of less than 16 bytes (=> 256 bytes)
+ * Total: 256 + 32 + 16 + 106 = 410.
+ *
+ * We thus choose 512 (leeway, power of 2).
+ */
+static const size_t ALLOC_FIRST_SIZE = 512;
+
+static bool
+alloc_is_empty(const struct alloc *const alloc)
+{
+ if (alloc->size == 0) {
+ assert(alloc->start == NULL);
+ return (true);
+ } else {
+ assert(alloc->start != NULL);
+ return (false);
+ }
+}
+
+static void
+alloc_realloc(struct alloc *const alloc)
+{
+ const size_t old_size = alloc->size;
+ size_t new_size;
+
+ if (old_size == 0) {
+ assert(alloc->start == NULL);
+ new_size = ALLOC_FIRST_SIZE;
+ } else if (old_size < PAGE_SIZE)
+ new_size = 2 * old_size;
+ else
+ /*
+ * We never allocate more than a page at a time when reaching
+ * a page (except perhaps for the first increment, up to two).
+ * Use roundup2() to be immune to previous cases' changes. */
+ new_size = roundup2(old_size, PAGE_SIZE) + PAGE_SIZE;
+
+ alloc->start = realloc(alloc->start, new_size);
+ if (alloc->start == NULL)
+ errx(EXIT_FAILURE,
+ "cannot realloc allocation (old size: %zu, new: %zu)",
+ old_size, new_size);
+ alloc->size = new_size;
+}
+
+static void
+alloc_free(struct alloc *const alloc)
+{
+ if (!alloc_is_empty(alloc)) {
+ free(alloc->start);
+ *alloc = ALLOC_INITIALIZER;
+ }
+}
+
+struct alloc_wrap_data {
+ int (*func)(void *data, const struct alloc *alloc);
+};
+
+/*
+ * Wraps functions needing a backing allocation.
+ *
+ * Uses 'alloc' as the starting allocation, and may extend it as necessary.
+ * 'alloc' is never freed, even on failure of the wrapped function.
+ *
+ * The function is expected to return ERANGE if and only if the provided
+ * allocation is not big enough. All other values are passed through.
+ */
+static int
+alloc_wrap(struct alloc_wrap_data *const data, struct alloc *alloc)
+{
+ int error;
+
+ /* Avoid a systematic ERANGE on first iteration. */
+ if (alloc_is_empty(alloc))
+ alloc_realloc(alloc);
+
+ for (;;) {
+ error = data->func(data, alloc);
+ if (error != ERANGE)
+ break;
+ alloc_realloc(alloc);
+ }
+
+ return (error);
+}
+
+struct getpwnam_wrapper_data {
+ struct alloc_wrap_data wrapped;
+ const char *name;
+ struct passwd **pwdp;
+};
+
+static int
+wrapped_getpwnam_r(void *data, const struct alloc *alloc)
+{
+ struct passwd *const pwd = alloc->start;
+ struct passwd *result;
+ struct getpwnam_wrapper_data *d = data;
+ int error;
+
+ assert(alloc->size >= sizeof(*pwd));
+
+ error = getpwnam_r(d->name, pwd, (char *)(pwd + 1),
+ alloc->size - sizeof(*pwd), &result);
+
+ if (error == 0) {
+ if (result == NULL)
+ error = ENOENT;
+ } else
+ assert(result == NULL);
+ *d->pwdp = result;
+ return (error);
+}
+
+/*
+ * Wraps getpwnam_r(), automatically dealing with memory allocation.
+ *
+ * 'alloc' may be any allocation (even empty), and will be extended as
+ * necessary. It is not freed on error.
+ *
+ * On success, '*pwdp' is filled with a pointer to the returned 'struct passwd',
+ * and on failure, is set to NULL.
+ */
+static int
+alloc_getpwnam(const char *name, struct passwd **pwdp,
+ struct alloc *const alloc)
+{
+ struct getpwnam_wrapper_data data;
+
+ data.wrapped.func = wrapped_getpwnam_r;
+ data.name = name;
+ data.pwdp = pwdp;
+ return (alloc_wrap((struct alloc_wrap_data *)&data, alloc));
+}
+
+struct getgrnam_wrapper_data {
+ struct alloc_wrap_data wrapped;
+ const char *name;
+ struct group **grpp;
+};
+
+static int
+wrapped_getgrnam_r(void *data, const struct alloc *alloc)
+{
+ struct group *grp = alloc->start;
+ struct group *result;
+ struct getgrnam_wrapper_data *d = data;
+ int error;
+
+ assert(alloc->size >= sizeof(*grp));
+
+ error = getgrnam_r(d->name, grp, (char *)(grp + 1),
+ alloc->size - sizeof(*grp), &result);
+
+ if (error == 0) {
+ if (result == NULL)
+ error = ENOENT;
+ } else
+ assert(result == NULL);
+ *d->grpp = result;
+ return (error);
+}
+
+/*
+ * Wraps getgrnam_r(), automatically dealing with memory allocation.
+ *
+ * 'alloc' may be any allocation (even empty), and will be extended as
+ * necessary. It is not freed on error.
+ *
+ * On success, '*grpp' is filled with a pointer to the returned 'struct group',
+ * and on failure, is set to NULL.
+ */
+static int
+alloc_getgrnam(const char *const name, struct group **const grpp,
+ struct alloc *const alloc)
+{
+ struct getgrnam_wrapper_data data;
+
+ data.wrapped.func = wrapped_getgrnam_r;
+ data.name = name;
+ data.grpp = grpp;
+ return (alloc_wrap((struct alloc_wrap_data *)&data, alloc));
+}
+
+/*
+ * Retrieve the UID from a user string.
+ *
+ * Tries first to interpret the string as a user name, then as a numeric ID
+ * (this order is prescribed by POSIX for a number of utilities).
+ *
+ * 'pwdp' and 'allocp' must be NULL or non-NULL together. If non-NULL, then
+ * 'allocp' can be any allocation (possibly empty) and will be extended to
+ * contain the result if necessary. It will not be freed (even on failure).
+ */
+static uid_t
+parse_user_pwd(const char *s, struct passwd **pwdp, struct alloc *allocp)
+{
+ struct passwd *pwd;
+ struct alloc alloc = ALLOC_INITIALIZER;
+ const char *errp;
+ uid_t uid;
+ int error;
+
+ assert((pwdp == NULL && allocp == NULL) ||
+ (pwdp != NULL && allocp != NULL));
+
+ if (pwdp == NULL) {
+ pwdp = &pwd;
+ allocp = &alloc;
+ }
+
+ error = alloc_getpwnam(s, pwdp, allocp);
+ if (error == 0) {
+ uid = (*pwdp)->pw_uid;
+ goto finish;
+ } else if (error != ENOENT)
+ errc(EXIT_FAILURE, error,
+ "cannot access the password database");
+
+ uid = strtonum(s, 0, UID_MAX, &errp);
+ if (errp != NULL)
+ errx(EXIT_FAILURE, "invalid UID '%s': %s", s, errp);
+
+finish:
+ if (allocp == &alloc)
+ alloc_free(allocp);
+ return (uid);
+}
+
+/* See parse_user_pwd() for the doc. */
+static uid_t
+parse_user(const char *s)
+{
+ return (parse_user_pwd(s, NULL, NULL));
+}
+
+/*
+ * Retrieve the GID from a group string.
+ *
+ * Tries first to interpret the string as a group name, then as a numeric ID
+ * (this order is prescribed by POSIX for a number of utilities).
+ */
+static gid_t
+parse_group(const char *s)
+{
+ struct group *grp;
+ struct alloc alloc = ALLOC_INITIALIZER;
+ const char *errp;
+ gid_t gid;
+ int error;
+
+ error = alloc_getgrnam(s, &grp, &alloc);
+ if (error == 0) {
+ gid = grp->gr_gid;
+ goto finish;
+ } else if (error != ENOENT)
+ errc(EXIT_FAILURE, error, "cannot access the group database");
+
+ gid = strtonum(s, 0, GID_MAX, &errp);
+ if (errp != NULL)
+ errx(EXIT_FAILURE, "invalid GID '%s': %s", s, errp);
+
+finish:
+ alloc_free(&alloc);
+ return (gid);
+}
+
+struct group_array {
+ u_int nb;
+ gid_t *groups;
+};
+
+static const struct group_array GROUP_ARRAY_INITIALIZER = {
+ .nb = 0,
+ .groups = NULL,
+};
+
+static bool
+group_array_is_empty(const struct group_array *const ga)
+{
+ return (ga->nb == 0);
+}
+
+static void
+realloc_groups(struct group_array *const ga, const u_int diff)
+{
+ const u_int new_nb = ga->nb + diff;
+ const size_t new_size = new_nb * sizeof(*ga->groups);
+
+ assert(new_nb >= diff && new_size >= new_nb);
+ ga->groups = realloc(ga->groups, new_size);
+ if (ga->groups == NULL)
+ err(EXIT_FAILURE, "realloc of groups failed");
+ ga->nb = new_nb;
+}
+
+static int
+gidp_cmp(const void *p1, const void *p2)
+{
+ const gid_t g1 = *(const gid_t *)p1;
+ const gid_t g2 = *(const gid_t *)p2;
+
+ return ((g1 > g2) - (g1 < g2));
+}
+
+static void
+sort_uniq_groups(struct group_array *const ga)
+{
+ size_t j = 0;
+
+ if (ga->nb <= 1)
+ return;
+
+ qsort(ga->groups, ga->nb, sizeof(gid_t), gidp_cmp);
+
+ for (size_t i = 1; i < ga->nb; ++i)
+ if (ga->groups[i] != ga->groups[j])
+ ga->groups[++j] = ga->groups[i];
+}
+
+/*
+ * Remove elements in 'set' that are in 'remove'.
+ *
+ * Expects both arrays to have been treated with sort_uniq_groups(). Works in
+ * O(n + m), modifying 'set' in place.
+ */
+static void
+remove_groups(struct group_array *const set,
+ const struct group_array *const remove)
+{
+ u_int from = 0, to = 0, rem = 0;
+ gid_t cand, to_rem;
+
+ if (set->nb == 0 || remove->nb == 0)
+ /* Nothing to remove. */
+ return;
+
+ cand = set->groups[0];
+ to_rem = remove->groups[0];
+
+ for (;;) {
+ if (cand < to_rem) {
+ /* Keep. */
+ if (to != from)
+ set->groups[to] = cand;
+ ++to;
+ cand = set->groups[++from];
+ if (from == set->nb)
+ break;
+ } else if (cand == to_rem) {
+ cand = set->groups[++from];
+ if (from == set->nb)
+ break;
+ to_rem = remove->groups[++rem]; /* No duplicates. */
+ if (rem == remove->nb)
+ break;
+ } else {
+ to_rem = remove->groups[++rem];
+ if (rem == remove->nb)
+ break;
+ }
+ }
+
+ /* All remaining groups in 'set' must be kept. */
+ if (from == to)
+ /* Nothing was removed. 'set' will stay the same. */
+ return;
+ memmove(set->groups + to, set->groups + from,
+ (set->nb - from) * sizeof(gid_t));
+ set->nb = to + (set->nb - from);
}
int
main(int argc, char **argv)
{
- struct passwd *pw;
- const char *username = "root";
+ const char *const default_user = "root";
+
+ const char *user_name = NULL;
+ const char *primary_group = NULL;
+ char *supp_groups_str = NULL;
+ char *supp_mod_str = NULL;
+ bool start_from_current_groups = false;
+ bool start_from_current_users = false;
+ const char *euid_str = NULL;
+ const char *ruid_str = NULL;
+ const char *svuid_str = NULL;
+ const char *egid_str = NULL;
+ const char *rgid_str = NULL;
+ const char *svgid_str = NULL;
+ bool need_user = false; /* '-u' or '-k' needed. */
+
+ const int go_euid = 1000;
+ const int go_ruid = 1001;
+ const int go_svuid = 1002;
+ const int go_egid = 1003;
+ const int go_rgid = 1004;
+ const int go_svgid = 1005;
+ const struct option longopts[] = {
+ {"euid", required_argument, NULL, go_euid},
+ {"ruid", required_argument, NULL, go_ruid},
+ {"svuid", required_argument, NULL, go_svuid},
+ {"egid", required_argument, NULL, go_egid},
+ {"rgid", required_argument, NULL, go_rgid},
+ {"svgid", required_argument, NULL, go_svgid},
+ {NULL, 0, NULL, 0}
+ };
+ int ch;
+
struct setcred wcred = SETCRED_INITIALIZER;
u_int setcred_flags = 0;
- bool uidonly = false;
- int ch;
- while ((ch = getopt(argc, argv, "u:i")) != -1) {
+ struct passwd *pw = NULL;
+ struct alloc pw_alloc = ALLOC_INITIALIZER;
+ struct group_array supp_groups = GROUP_ARRAY_INITIALIZER;
+ struct group_array supp_rem = GROUP_ARRAY_INITIALIZER;
+
+
+ /*
+ * Process options.
+ */
+ while (ch = getopt_long(argc, argv, "+G:g:hiks:u:", longopts, NULL),
+ ch != -1) {
switch (ch) {
- case 'u':
- username = optarg;
+ case 'G':
+ supp_groups_str = optarg;
+ need_user = true;
+ break;
+ case 'g':
+ primary_group = optarg;
+ need_user = true;
break;
+ case 'h':
+ usage();
case 'i':
- uidonly = true;
+ start_from_current_groups = true;
+ break;
+ case 'k':
+ start_from_current_users = true;
+ break;
+ case 's':
+ supp_mod_str = optarg;
+ need_user = true;
+ break;
+ case 'u':
+ user_name = optarg;
+ break;
+ case go_euid:
+ euid_str = optarg;
+ need_user = true;
+ break;
+ case go_ruid:
+ ruid_str = optarg;
+ need_user = true;
+ break;
+ case go_svuid:
+ svuid_str = optarg;
+ need_user = true;
+ break;
+ case go_egid:
+ egid_str = optarg;
+ need_user = true;
+ break;
+ case go_rgid:
+ rgid_str = optarg;
+ need_user = true;
+ break;
+ case go_svgid:
+ svgid_str = optarg;
+ need_user = true;
break;
default:
usage();
}
}
+
argc -= optind;
argv += optind;
- if ((pw = getpwnam(username)) == NULL) {
- if (strspn(username, "0123456789") == strlen(username)) {
- const char *errp = NULL;
- uid_t uid = strtonum(username, 0, UID_MAX, &errp);
- if (errp != NULL)
- err(EXIT_FAILURE, "invalid user ID '%s'",
- username);
- pw = getpwuid(uid);
+ /*
+ * Determine users.
+ *
+ * We do that first as in some cases we need to retrieve the
+ * corresponding password database entry to be able to set the primary
+ * groups.
+ */
+
+ if (start_from_current_users) {
+ if (user_name != NULL)
+ errx(EXIT_FAILURE, "-k incompatible with -u");
+
+ /*
+ * If starting from the current user(s) as a base, finding one
+ * of them in the password database and using its groups would
+ * be quite surprising, so we instead let '-k' imply '-i'.
+ */
+ start_from_current_groups = true;
+ } else {
+ uid_t uid;
+
+ /*
+ * In the case of any overrides, we impose an explicit base user
+ * via '-u' or '-k' instead of implicitly taking 'root' as the
+ * base.
+ */
+ if (user_name == NULL) {
+ if (need_user)
+ errx(EXIT_FAILURE,
+ "Some overrides specified, "
+ "'-u' or '-k' needed.");
+ user_name = default_user;
}
+
+ /*
+ * Even if all user overrides are present as well as primary and
+ * supplementary groups ones, in which case the final result
+ * doesn't depend on '-u', we still call parse_user_pwd() to
+ * check that the passed username is correct.
+ */
+ uid = parse_user_pwd(user_name, &pw, &pw_alloc);
+ wcred.sc_uid = wcred.sc_ruid = wcred.sc_svuid = uid;
+ setcred_flags |= SETCREDF_UID | SETCREDF_RUID |
+ SETCREDF_SVUID;
+ }
+
+ if (euid_str != NULL) {
+ wcred.sc_uid = parse_user(euid_str);
+ setcred_flags |= SETCREDF_UID;
+ }
+
+ if (ruid_str != NULL) {
+ wcred.sc_ruid = parse_user(ruid_str);
+ setcred_flags |= SETCREDF_RUID;
+ }
+
+ if (svuid_str != NULL) {
+ wcred.sc_svuid = parse_user(svuid_str);
+ setcred_flags |= SETCREDF_SVUID;
+ }
+
+ /*
+ * Determine primary groups.
+ */
+
+ /*
+ * When not starting from the current groups, we need to set all
+ * primary groups. If '-g' was not passed, we use the primary
+ * group from the password database as the "base" to which
+ * overrides '--egid', '--rgid' and '--svgid' apply. But if all
+ * overrides were specified, we in fact just don't need the
+ * password database at all.
+ *
+ * '-g' is treated outside of this 'if' as it can also be used
+ * as an override.
+ */
+ if (!start_from_current_groups && primary_group == NULL &&
+ (egid_str == NULL || rgid_str == NULL || svgid_str == NULL)) {
if (pw == NULL)
- err(EXIT_FAILURE, "invalid username '%s'", username);
+ errx(EXIT_FAILURE,
+ "must specify primary groups or a user name "
+ "with an entry in the password database");
+
+ wcred.sc_gid = wcred.sc_rgid = wcred.sc_svgid =
+ pw->pw_gid;
+ setcred_flags |= SETCREDF_GID | SETCREDF_RGID |
+ SETCREDF_SVGID;
+ }
+
+ if (primary_group != NULL) {
+ /*
+ * We always call parse_group() even in case all overrides are
+ * present to check that the passed group is valid.
+ */
+ wcred.sc_gid = wcred.sc_rgid = wcred.sc_svgid =
+ parse_group(primary_group);
+ setcred_flags |= SETCREDF_GID | SETCREDF_RGID | SETCREDF_SVGID;
+ }
+
+ if (egid_str != NULL) {
+ wcred.sc_gid = parse_group(egid_str);
+ setcred_flags |= SETCREDF_GID;
+ }
+
+ if (rgid_str != NULL) {
+ wcred.sc_rgid = parse_group(rgid_str);
+ setcred_flags |= SETCREDF_RGID;
+ }
+
+ if (svgid_str != NULL) {
+ wcred.sc_svgid = parse_group(svgid_str);
+ setcred_flags |= SETCREDF_SVGID;
+ }
+
+ /*
+ * Determine supplementary groups.
+ */
+
+ /*
+ * This makes sense to catch user's mistakes. It is not a strong
+ * limitation of the code below (allowing this case is just a matter of,
+ * in the block treating '-s' with '@' below, replacing an assert() by
+ * a reset of 'supp_groups').
+ */
+ if (supp_groups_str != NULL && supp_mod_str != NULL &&
+ supp_mod_str[0] == '@')
+ errx(EXIT_FAILURE, "'-G' and '-s' with '@' are incompatible");
+
+ /*
+ * Determine the supplementary groups to start with, but only if we
+ * really need to operate on them later (and set them back).
+ */
+ if (!start_from_current_groups) {
+ assert(!start_from_current_users);
+
+ if (supp_groups_str == NULL && (supp_mod_str == NULL ||
+ supp_mod_str[0] != '@')) {
+ /*
+ * If we are to replace supplementary groups (i.e.,
+ * neither '-i' nor '-k' was specified) and they are not
+ * completely specified (with '-g' or '-s' with '@'), we
+ * start from those in the groups database if we were
+ * passed a user name that is in the password database
+ * (this is a protection against erroneous ID/name
+ * conflation in the groups database), else we simply
+ * error.
+ */
+
+ if (pw == NULL)
+ errx(EXIT_FAILURE,
+ "must specify the full supplementary "
+ "groups set or a user name with an entry "
+ "in the password database");
+
+ const long ngroups_alloc = sysconf(_SC_NGROUPS_MAX) + 1;
+ gid_t *groups;
+ int ngroups;
+
+ groups = malloc(sizeof(*groups) * ngroups_alloc);
+ if (groups == NULL)
+ errx(EXIT_FAILURE,
+ "cannot allocate memory to retrieve "
+ "user groups from the groups database");
+
+ ngroups = ngroups_alloc;
+ getgrouplist(user_name, pw->pw_gid, groups, &ngroups);
+
+ if (ngroups > ngroups_alloc)
+ err(EXIT_FAILURE,
+ "too many groups for user '%s'",
+ user_name);
+
+ realloc_groups(&supp_groups, ngroups);
+ memcpy(supp_groups.groups + supp_groups.nb - ngroups,
+ groups, ngroups * sizeof(*groups));
+ free(groups);
+
+ /*
+ * Have to set SETCREDF_SUPP_GROUPS here since we may be
+ * in the case where neither '-G' nor '-s' was passed,
+ * but we still have to set the supplementary groups to
+ * those of the groups database.
+ */
+ setcred_flags |= SETCREDF_SUPP_GROUPS;
+ }
+ } else if (supp_groups_str == NULL && (supp_mod_str == NULL ||
+ supp_mod_str[0] != '@')) {
+ const int ngroups = getgroups(0, NULL);
+
+ if (ngroups > 0) {
+ realloc_groups(&supp_groups, ngroups);
+
+ if (getgroups(ngroups, supp_groups.groups +
+ supp_groups.nb - ngroups) < 0)
+ err(EXIT_FAILURE, "getgroups() failed");
+ }
+
+ /*
+ * Setting SETCREDF_SUPP_GROUPS here is not necessary, we will
+ * do it below since 'supp_mod_str' != NULL.
+ */
}
- wcred.sc_uid = wcred.sc_ruid = wcred.sc_svuid = pw->pw_uid;
- setcred_flags |= SETCREDF_UID | SETCREDF_RUID | SETCREDF_SVUID;
+ if (supp_groups_str != NULL) {
+ char *p = supp_groups_str;
+ char *tok;
- if (!uidonly) {
/*
- * If there are too many groups specified for some UID, setting
- * the groups will fail. We preserve this condition by
- * allocating one more group slot than allowed, as
- * getgrouplist() itself is just some getter function and thus
- * doesn't (and shouldn't) check the limit, and to allow
- * setcred() to actually check for overflow.
+ * We will set the supplementary groups to exactly the set
+ * passed with '-G', and we took care above not to retrieve
+ * "base" groups (current ones or those from the groups
+ * database) in this case.
*/
- const long ngroups_alloc = sysconf(_SC_NGROUPS_MAX) + 2;
- gid_t *const groups = malloc(sizeof(*groups) * ngroups_alloc);
- int ngroups = ngroups_alloc;
+ assert(group_array_is_empty(&supp_groups));
+
+ /* WARNING: 'supp_groups_str' going to be modified. */
+ while ((tok = strsep(&p, ",")) != NULL) {
+ gid_t g;
+
+ if (*tok == '\0')
+ continue;
+
+ g = parse_group(tok);
+ realloc_groups(&supp_groups, 1);
+ supp_groups.groups[supp_groups.nb - 1] = g;
+ }
+
+ setcred_flags |= SETCREDF_SUPP_GROUPS;
+ }
+
+ if (supp_mod_str != NULL) {
+ char *p = supp_mod_str;
+ char *tok;
+ gid_t gid;
- if (groups == NULL)
- err(EXIT_FAILURE, "cannot allocate memory for groups");
+ /* WARNING: 'supp_mod_str' going to be modified. */
+ while ((tok = strsep(&p, ",")) != NULL) {
+ switch (tok[0]) {
+ case '\0':
+ break;
- getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
+ case '@':
+ if (tok != supp_mod_str)
+ errx(EXIT_FAILURE, "'@' must be "
+ "the first token in '-s' option");
+ /* See same assert() above. */
+ assert(group_array_is_empty(&supp_groups));
+ break;
+
+ case '+':
+ case '-':
+ gid = parse_group(tok + 1);
+ if (tok[0] == '+') {
+ realloc_groups(&supp_groups, 1);
+ supp_groups.groups[supp_groups.nb - 1] = gid;
+ } else {
+ realloc_groups(&supp_rem, 1);
+ supp_rem.groups[supp_rem.nb - 1] = gid;
+ }
+ break;
+
+ default:
+ errx(EXIT_FAILURE,
+ "invalid '-s' token '%s' at index %zu",
+ tok, tok - supp_mod_str);
+ }
+ }
- wcred.sc_gid = wcred.sc_rgid = wcred.sc_svgid = pw->pw_gid;
- wcred.sc_supp_groups = groups + 1;
- wcred.sc_supp_groups_nb = ngroups - 1;
- setcred_flags |= SETCREDF_GID | SETCREDF_RGID | SETCREDF_SVGID |
- SETCREDF_SUPP_GROUPS;
+ setcred_flags |= SETCREDF_SUPP_GROUPS;
+ }
+
+ /*
+ * We don't need to pass the kernel a normalized representation of the
+ * new supplementary groups set (array sorted and without duplicates),
+ * so we don't do it here unless we need to remove some groups, where it
+ * enables more efficient algorithms (if the number of groups for some
+ * reason grows out of control).
+ */
+ if (!group_array_is_empty(&supp_groups) &&
+ !group_array_is_empty(&supp_rem)) {
+ sort_uniq_groups(&supp_groups);
+ sort_uniq_groups(&supp_rem);
+ remove_groups(&supp_groups, &supp_rem);
+ }
+
+ if ((setcred_flags & SETCREDF_SUPP_GROUPS) != 0) {
+ wcred.sc_supp_groups = supp_groups.groups;
+ wcred.sc_supp_groups_nb = supp_groups.nb;
}
if (setcred(setcred_flags, &wcred, sizeof(wcred)) != 0)
- err(EXIT_FAILURE, "calling setcred() failed");
+ err(EXIT_FAILURE, "setcred()");
+
+ /*
+ * We don't bother freeing memory still allocated at this point as we
+ * are about to exec() or exit.
+ */
if (*argv == NULL) {
const char *sh = getenv("SHELL");
+
if (sh == NULL)
sh = _PATH_BSHELL;
execlp(sh, sh, "-i", NULL);
diff --git a/usr.bin/mididump/Makefile b/usr.bin/mididump/Makefile
index 758bbb3a1189..5b22376b7bb8 100644
--- a/usr.bin/mididump/Makefile
+++ b/usr.bin/mididump/Makefile
@@ -1,5 +1,7 @@
.include <src.opts.mk>
+PACKAGE= sound
+
PROG= mididump
SRCS= ${PROG}.c
MAN= ${PROG}.1
diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c
index 622141e4ff69..7ee03eb3689b 100644
--- a/usr.bin/netstat/if.c
+++ b/usr.bin/netstat/if.c
@@ -282,7 +282,8 @@ next_ifma(struct ifmaddrs *ifma, const char *name, const sa_family_t family)
sdl = (struct sockaddr_dl *)ifma->ifma_name;
if (ifma->ifma_addr->sa_family == family &&
- strcmp(sdl->sdl_data, name) == 0)
+ sdl->sdl_nlen == strlen(name) &&
+ strncmp(sdl->sdl_data, name, sdl->sdl_nlen) == 0)
break;
}
diff --git a/usr.bin/sockstat/main.c b/usr.bin/sockstat/main.c
index 2e75e4966d80..7fedfd5b8724 100644
--- a/usr.bin/sockstat/main.c
+++ b/usr.bin/sockstat/main.c
@@ -51,6 +51,7 @@
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp_var.h>
+#include <netinet/tcp_log_buf.h>
#include <arpa/inet.h>
#include <capsicum_helpers.h>
@@ -84,6 +85,7 @@
static bool opt_4; /* Show IPv4 sockets */
static bool opt_6; /* Show IPv6 sockets */
static bool opt_A; /* Show kernel address of pcb */
+static bool opt_b; /* Show BBLog state */
static bool opt_C; /* Show congestion control */
static bool opt_c; /* Show connected sockets */
static bool opt_f; /* Show FIB numbers */
@@ -101,6 +103,7 @@ static bool opt_u; /* Show Unix domain sockets */
static u_int opt_v; /* Verbose mode */
static bool opt_w; /* Automatically size the columns */
static bool is_xo_style_encoding;
+static bool show_path_state = false;
/*
* Default protocols to use if no -P was defined.
@@ -141,6 +144,7 @@ struct sock {
int proto;
int state;
int fibnum;
+ int bblog_state;
const char *protoname;
char stack[TCP_FUNCTION_NAME_LEN_MAX];
char cc[TCP_CA_NAME_MAX];
@@ -581,6 +585,7 @@ gather_sctp(void)
!(local_all_loopback ||
foreign_all_loopback))) {
RB_INSERT(socks_t, &socks, sock);
+ show_path_state = true;
} else {
free_socket(sock);
}
@@ -738,6 +743,7 @@ gather_inet(int proto)
sock->vflag = xip->inp_vflag;
if (proto == IPPROTO_TCP) {
sock->state = xtp->t_state;
+ sock->bblog_state = xtp->t_logstate;
memcpy(sock->stack, xtp->xt_stack,
TCP_FUNCTION_NAME_LEN_MAX);
memcpy(sock->cc, xtp->xt_cc, TCP_CA_NAME_MAX);
@@ -1056,6 +1062,37 @@ sctp_path_state(int state)
}
}
+static const char *
+bblog_state(int state)
+{
+ switch (state) {
+ case TCP_LOG_STATE_OFF:
+ return "OFF";
+ break;
+ case TCP_LOG_STATE_TAIL:
+ return "TAIL";
+ break;
+ case TCP_LOG_STATE_HEAD:
+ return "HEAD";
+ break;
+ case TCP_LOG_STATE_HEAD_AUTO:
+ return "HEAD_AUTO";
+ break;
+ case TCP_LOG_STATE_CONTINUAL:
+ return "CONTINUAL";
+ break;
+ case TCP_LOG_STATE_TAIL_AUTO:
+ return "TAIL_AUTO";
+ break;
+ case TCP_LOG_VIA_BBPOINTS:
+ return "BBPOINTS";
+ break;
+ default:
+ return "UNKNOWN";
+ break;
+ }
+}
+
static int
format_unix_faddr(struct addr *faddr, char *buf, size_t bufsize) {
#define SAFEBUF (buf == NULL ? NULL : buf + pos)
@@ -1143,6 +1180,7 @@ struct col_widths {
int encaps;
int path_state;
int conn_state;
+ int bblog_state;
int stack;
int cc;
};
@@ -1194,40 +1232,40 @@ calculate_sock_column_widths(struct col_widths *cw, struct sock *s)
{ .socket = s->splice_socket });
if (sp != NULL) {
len = formataddr(&sp->laddr->address,
- NULL, 0);
+ NULL, 0);
cw->splice_address = MAX(
- cw->splice_address, len);
+ cw->splice_address, len);
}
}
}
if (opt_i) {
- if (s->proto == IPPROTO_TCP || s->proto == IPPROTO_UDP)
- {
+ if (s->proto == IPPROTO_TCP ||
+ s->proto == IPPROTO_UDP) {
len = snprintf(NULL, 0,
- "%" PRIu64, s->inp_gencnt);
+ "%" PRIu64, s->inp_gencnt);
cw->inp_gencnt = MAX(cw->inp_gencnt, len);
}
}
if (opt_U) {
if (faddr != NULL &&
- ((s->proto == IPPROTO_SCTP &&
- s->state != SCTP_CLOSED &&
- s->state != SCTP_BOUND &&
- s->state != SCTP_LISTEN) ||
- (s->proto == IPPROTO_TCP &&
- s->state != TCPS_CLOSED &&
- s->state != TCPS_LISTEN))) {
+ ((s->proto == IPPROTO_SCTP &&
+ s->state != SCTP_CLOSED &&
+ s->state != SCTP_BOUND &&
+ s->state != SCTP_LISTEN) ||
+ (s->proto == IPPROTO_TCP &&
+ s->state != TCPS_CLOSED &&
+ s->state != TCPS_LISTEN))) {
len = snprintf(NULL, 0, "%u",
- ntohs(faddr->encaps_port));
+ ntohs(faddr->encaps_port));
cw->encaps = MAX(cw->encaps, len);
}
}
if (opt_s) {
if (faddr != NULL &&
- s->proto == IPPROTO_SCTP &&
- s->state != SCTP_CLOSED &&
- s->state != SCTP_BOUND &&
- s->state != SCTP_LISTEN) {
+ s->proto == IPPROTO_SCTP &&
+ s->state != SCTP_CLOSED &&
+ s->state != SCTP_BOUND &&
+ s->state != SCTP_LISTEN) {
len = strlen(sctp_path_state(faddr->state));
cw->path_state = MAX(cw->path_state, len);
}
@@ -1235,21 +1273,22 @@ calculate_sock_column_widths(struct col_widths *cw, struct sock *s)
if (first) {
if (opt_s) {
if (s->proto == IPPROTO_SCTP ||
- s->proto == IPPROTO_TCP) {
+ s->proto == IPPROTO_TCP) {
switch (s->proto) {
case IPPROTO_SCTP:
len = strlen(
sctp_conn_state(s->state));
cw->conn_state = MAX(
- cw->conn_state, len);
+ cw->conn_state, len);
break;
case IPPROTO_TCP:
if (s->state >= 0 &&
s->state < TCP_NSTATES) {
- len = strlen(
- tcpstates[s->state]);
- cw->conn_state = MAX(
- cw->conn_state, len);
+ len = strlen(
+ tcpstates[s->state]);
+ cw->conn_state = MAX(
+ cw->conn_state,
+ len);
}
break;
}
@@ -1426,8 +1465,8 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
cw->splice_address, buf);
}
if (opt_i) {
- if (s->proto == IPPROTO_TCP || s->proto == IPPROTO_UDP)
- {
+ if (s->proto == IPPROTO_TCP ||
+ s->proto == IPPROTO_UDP) {
snprintf(buf, bufsize, "%" PRIu64,
s->inp_gencnt);
xo_emit(" {:id/%*s}", cw->inp_gencnt, buf);
@@ -1436,29 +1475,29 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
}
if (opt_U) {
if (faddr != NULL &&
- ((s->proto == IPPROTO_SCTP &&
- s->state != SCTP_CLOSED &&
- s->state != SCTP_BOUND &&
- s->state != SCTP_LISTEN) ||
- (s->proto == IPPROTO_TCP &&
- s->state != TCPS_CLOSED &&
- s->state != TCPS_LISTEN))) {
+ ((s->proto == IPPROTO_SCTP &&
+ s->state != SCTP_CLOSED &&
+ s->state != SCTP_BOUND &&
+ s->state != SCTP_LISTEN) ||
+ (s->proto == IPPROTO_TCP &&
+ s->state != TCPS_CLOSED &&
+ s->state != TCPS_LISTEN))) {
xo_emit(" {:encaps/%*u}", cw->encaps,
- ntohs(faddr->encaps_port));
+ ntohs(faddr->encaps_port));
} else if (!is_xo_style_encoding)
xo_emit(" {:encaps/%*s}", cw->encaps, "??");
}
- if (opt_s) {
+ if (opt_s && show_path_state) {
if (faddr != NULL &&
- s->proto == IPPROTO_SCTP &&
- s->state != SCTP_CLOSED &&
- s->state != SCTP_BOUND &&
- s->state != SCTP_LISTEN) {
+ s->proto == IPPROTO_SCTP &&
+ s->state != SCTP_CLOSED &&
+ s->state != SCTP_BOUND &&
+ s->state != SCTP_LISTEN) {
xo_emit(" {:path-state/%-*s}", cw->path_state,
- sctp_path_state(faddr->state));
+ sctp_path_state(faddr->state));
} else if (!is_xo_style_encoding)
xo_emit(" {:path-state/%-*s}", cw->path_state,
- "??");
+ "??");
}
if (first) {
if (opt_s) {
@@ -1467,31 +1506,40 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
switch (s->proto) {
case IPPROTO_SCTP:
xo_emit(" {:conn-state/%-*s}",
- cw->conn_state,
- sctp_conn_state(s->state));
+ cw->conn_state,
+ sctp_conn_state(s->state));
break;
case IPPROTO_TCP:
if (s->state >= 0 &&
- s->state < TCP_NSTATES)
+ s->state < TCP_NSTATES)
xo_emit(" {:conn-state/%-*s}",
- cw->conn_state,
- tcpstates[s->state]);
+ cw->conn_state,
+ tcpstates[s->state]);
else if (!is_xo_style_encoding)
xo_emit(" {:conn-state/%-*s}",
- cw->conn_state, "??");
+ cw->conn_state, "??");
break;
}
} else if (!is_xo_style_encoding)
xo_emit(" {:conn-state/%-*s}",
- cw->conn_state, "??");
+ cw->conn_state, "??");
+ }
+ if (opt_b) {
+ if (s->proto == IPPROTO_TCP)
+ xo_emit(" {:bblog-state/%-*s}",
+ cw->bblog_state,
+ bblog_state(s->bblog_state));
+ else if (!is_xo_style_encoding)
+ xo_emit(" {:bblog-state/%-*s}",
+ cw->bblog_state, "??");
}
if (opt_S) {
if (s->proto == IPPROTO_TCP)
xo_emit(" {:stack/%-*s}",
- cw->stack, s->stack);
+ cw->stack, s->stack);
else if (!is_xo_style_encoding)
xo_emit(" {:stack/%-*s}",
- cw->stack, "??");
+ cw->stack, "??");
}
if (opt_C) {
if (s->proto == IPPROTO_TCP)
@@ -1499,18 +1547,30 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
else if (!is_xo_style_encoding)
xo_emit(" {:cc/%-*s}", cw->cc, "??");
}
+ } else if (!is_xo_style_encoding) {
+ if (opt_s)
+ xo_emit(" {:conn-state/%-*s}", cw->conn_state,
+ "??");
+ if (opt_b)
+ xo_emit(" {:bblog-state/%-*s}", cw->bblog_state,
+ "??");
+ if (opt_S)
+ xo_emit(" {:stack/%-*s}", cw->stack, "??");
+ if (opt_C)
+ xo_emit(" {:cc/%-*s}", cw->cc, "??");
}
if (laddr != NULL)
laddr = laddr->next;
if (faddr != NULL)
faddr = faddr->next;
+ xo_emit("\n");
if (!is_xo_style_encoding && (laddr != NULL || faddr != NULL))
xo_emit("{:user/%-*s} {:command/%-*s} {:pid/%*s}"
- " {:fd/%*s}", cw->user, "??", cw->command, "??",
- cw->pid, "??", cw->fd, "??");
+ " {:fd/%*s} {:proto/%-*s}", cw->user, "??",
+ cw->command, "??", cw->pid, "??", cw->fd, "??",
+ cw->proto, "??");
first = false;
}
- xo_emit("\n");
}
static void
@@ -1544,6 +1604,7 @@ display(void)
.encaps = strlen("ENCAPS"),
.path_state = strlen("PATH STATE"),
.conn_state = strlen("CONN STATE"),
+ .bblog_state = strlen("BBLOG STATE"),
.stack = strlen("STACK"),
.cc = strlen("CC"),
};
@@ -1567,15 +1628,19 @@ display(void)
xo_emit(" {T:/%*s}", cw.fib, "FIB");
if (opt_I)
xo_emit(" {T:/%-*s}", cw.splice_address,
- "SPLICE ADDRESS");
+ "SPLICE ADDRESS");
if (opt_i)
xo_emit(" {T:/%*s}", cw.inp_gencnt, "ID");
if (opt_U)
xo_emit(" {T:/%*s}", cw.encaps, "ENCAPS");
if (opt_s) {
- xo_emit(" {T:/%-*s}", cw.path_state, "PATH STATE");
+ if (show_path_state)
+ xo_emit(" {T:/%-*s}", cw.path_state,
+ "PATH STATE");
xo_emit(" {T:/%-*s}", cw.conn_state, "CONN STATE");
}
+ if (opt_b)
+ xo_emit(" {T:/%-*s}", cw.bblog_state, "BBLOG STATE");
if (opt_S)
xo_emit(" {T:/%-*s}", cw.stack, "STACK");
if (opt_C)
@@ -1596,15 +1661,15 @@ display(void)
if (opt_n ||
(pwd = cap_getpwuid(cappwd, xf->xf_uid)) == NULL)
xo_emit("{:user/%-*lu}", cw.user,
- (u_long)xf->xf_uid);
+ (u_long)xf->xf_uid);
else
xo_emit("{:user/%-*s}", cw.user, pwd->pw_name);
if (!is_xo_style_encoding)
xo_emit(" {:command/%-*.10s}", cw.command,
- getprocname(xf->xf_pid));
+ getprocname(xf->xf_pid));
else
xo_emit(" {:command/%-*s}", cw.command,
- getprocname(xf->xf_pid));
+ getprocname(xf->xf_pid));
xo_emit(" {:pid/%*lu}", cw.pid, (u_long)xf->xf_pid);
xo_emit(" {:fd/%*d}", cw.fd, xf->xf_fd);
display_sock(s, &cw, buf, bufsize);
@@ -1619,8 +1684,8 @@ display(void)
xo_open_instance("socket");
if (!is_xo_style_encoding)
xo_emit("{:user/%-*s} {:command/%-*s} {:pid/%*s}"
- " {:fd/%*s}", cw.user, "??", cw.command, "??",
- cw.pid, "??", cw.fd, "??");
+ " {:fd/%*s}", cw.user, "??", cw.command, "??",
+ cw.pid, "??", cw.fd, "??");
display_sock(s, &cw, buf, bufsize);
xo_close_instance("socket");
}
@@ -1632,8 +1697,8 @@ display(void)
xo_open_instance("socket");
if (!is_xo_style_encoding)
xo_emit("{:user/%-*s} {:command/%-*s} {:pid/%*s}"
- " {:fd/%*s}", cw.user, "??", cw.command, "??",
- cw.pid, "??", cw.fd, "??");
+ " {:fd/%*s}", cw.user, "??", cw.command, "??",
+ cw.pid, "??", cw.fd, "??");
display_sock(s, &cw, buf, bufsize);
xo_close_instance("socket");
}
@@ -1706,7 +1771,7 @@ static void
usage(void)
{
xo_error(
-"usage: sockstat [--libxo ...] [-46ACcfIiLlnqSsUuvw] [-j jid] [-p ports]\n"
+"usage: sockstat [--libxo ...] [-46AbCcfIiLlnqSsUuvw] [-j jid] [-p ports]\n"
" [-P protocols]\n");
exit(1);
}
@@ -1728,7 +1793,7 @@ main(int argc, char *argv[])
xo_get_style(NULL) != XO_STYLE_HTML)
is_xo_style_encoding = true;
opt_j = -1;
- while ((o = getopt(argc, argv, "46ACcfIij:Llnp:P:qSsUuvw")) != -1)
+ while ((o = getopt(argc, argv, "46AbCcfIij:Llnp:P:qSsUuvw")) != -1)
switch (o) {
case '4':
opt_4 = true;
@@ -1739,6 +1804,9 @@ main(int argc, char *argv[])
case 'A':
opt_A = true;
break;
+ case 'b':
+ opt_b = true;
+ break;
case 'C':
opt_C = true;
break;
diff --git a/usr.bin/sockstat/sockstat.1 b/usr.bin/sockstat/sockstat.1
index 091911cd0879..d14eb967ad0f 100644
--- a/usr.bin/sockstat/sockstat.1
+++ b/usr.bin/sockstat/sockstat.1
@@ -25,7 +25,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd July 17, 2025
+.Dd October 9, 2025
.Dt SOCKSTAT 1
.Os
.Sh NAME
@@ -34,7 +34,7 @@
.Sh SYNOPSIS
.Nm
.Op Fl -libxo
-.Op Fl 46ACcfIiLlnqSsUuvw
+.Op Fl 46AbCcfIiLlnqSsUuvw
.Op Fl j Ar jail
.Op Fl p Ar ports
.Op Fl P Ar protocols
@@ -65,6 +65,9 @@ Show
.It Fl A
Show the address of a protocol control block (PCB) associated with a socket;
used for debugging.
+.It Fl b
+Show the BBLog state of the socket.
+This is currently only implemented for TCP.
.It Fl C
Display the congestion control module, if applicable.
This is currently only implemented for TCP.
@@ -202,10 +205,15 @@ is specified (only for SCTP or TCP).
The path state if
.Fl s
is specified (only for SCTP).
+This column is only shown when there is at least one path state shown.
.It Li CONN STATE
The connection state if
.Fl s
is specified (only for SCTP or TCP).
+.It Li BBLOG STATE
+The BBLog state if
+.Fl b
+is specified (only for TCP).
.It Li STACK
The protocol stack if
.Fl S
diff --git a/usr.bin/tail/tests/tail_test.sh b/usr.bin/tail/tests/tail_test.sh
index 74d6908f7568..82c74a0d4da4 100755
--- a/usr.bin/tail/tests/tail_test.sh
+++ b/usr.bin/tail/tests/tail_test.sh
@@ -341,6 +341,7 @@ follow_create_body()
rm -f infile
tail -F infile > outfile &
pid=$!
+ sleep 0.1
seq 1 5 >infile
sleep 2
atf_check cmp infile outfile
@@ -360,6 +361,7 @@ follow_rename_body()
seq 1 3 > infile
tail -F infile > outfile &
pid=$!
+ sleep 0.1
seq 4 5 > infile_new
atf_check mv infile infile_old
atf_check mv infile_new infile
diff --git a/usr.bin/tcopy/tcopy.cc b/usr.bin/tcopy/tcopy.cc
index 37a146376c2e..a1dd35682aac 100644
--- a/usr.bin/tcopy/tcopy.cc
+++ b/usr.bin/tcopy/tcopy.cc
@@ -580,7 +580,9 @@ getspace(size_t blk)
static void
usage(void)
{
- fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] [src [dest]]\n");
+ fprintf(stderr,
+ "usage: tcopy [-crvx] [-l logfile] [-s maxblk] [src [dest]]\n"
+ );
exit(1);
}
diff --git a/usr.bin/xz/Makefile b/usr.bin/xz/Makefile
index 0d5bce4c16f0..0a9103d60a13 100644
--- a/usr.bin/xz/Makefile
+++ b/usr.bin/xz/Makefile
@@ -1,5 +1,7 @@
.include <src.opts.mk>
+PACKAGE=xz
+
PROG= xz
LINKS= ${BINDIR}/xz ${BINDIR}/unxz
diff --git a/usr.bin/xzdec/Makefile b/usr.bin/xzdec/Makefile
index 7c43b2e03d78..6bf3dc07a408 100644
--- a/usr.bin/xzdec/Makefile
+++ b/usr.bin/xzdec/Makefile
@@ -1,3 +1,5 @@
+PACKAGE=xz
+
PROG= xzdec
LINKS= ${BINDIR}/xzdec ${BINDIR}/lzdec