The branch main has been updated by asomers:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=7b35b4d196309baf579571e1c1a433a4000d74c9

commit 7b35b4d196309baf579571e1c1a433a4000d74c9
Author:     Damin Rido <r...@freebsd.org>
AuthorDate: 2025-07-16 17:20:15 +0000
Commit:     Alan Somers <asom...@freebsd.org>
CommitDate: 2025-07-30 20:27:14 +0000

    sockstat: add libxo support
    
    Sponsored by:   Google, LLC (GSoC 2025)
    MFC after:      2 weeks
    Reviewed by:    asomers
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/1770
    Relnotes:       yes
---
 usr.bin/sockstat/Makefile   |   2 +-
 usr.bin/sockstat/sockstat.1 |  17 +-
 usr.bin/sockstat/sockstat.c | 467 +++++++++++++++++++++++++++-----------------
 3 files changed, 306 insertions(+), 180 deletions(-)

diff --git a/usr.bin/sockstat/Makefile b/usr.bin/sockstat/Makefile
index 188432dfc27e..7254511f21c6 100644
--- a/usr.bin/sockstat/Makefile
+++ b/usr.bin/sockstat/Makefile
@@ -2,7 +2,7 @@
 
 PROG=          sockstat
 
-LIBADD=                jail
+LIBADD=                jail xo
 
 .if ${MK_CASPER} != "no"
 LIBADD+=       casper
diff --git a/usr.bin/sockstat/sockstat.1 b/usr.bin/sockstat/sockstat.1
index 4832a09764fd..091911cd0879 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 June 30, 2025
+.Dd July 17, 2025
 .Dt SOCKSTAT 1
 .Os
 .Sh NAME
@@ -33,6 +33,7 @@
 .Nd list open sockets
 .Sh SYNOPSIS
 .Nm
+.Op Fl -libxo
 .Op Fl 46ACcfIiLlnqSsUuvw
 .Op Fl j Ar jail
 .Op Fl p Ar ports
@@ -46,6 +47,13 @@ domain sockets.
 .Pp
 The following options are available:
 .Bl -tag -width Fl
+.It Fl -libxo
+Generate output via
+.Xr libxo 3
+in a selection of different human and machine readable formats.
+See
+.Xr xo_options 7
+for details on command line arguments.
 .It Fl 4
 Show
 .Dv AF_INET
@@ -229,6 +237,11 @@ Show TCP IPv6 sockets which are listening and connected 
(default):
 .Bd -literal -offset indent
 $ sockstat -6 -P tcp
 .Ed
+.Pp
+Show all sockets in JSON format with neat alignment:
+.Bd -literal -offset indent
+$ sockstat --libxo json,pretty
+.Ed
 .Sh SEE ALSO
 .Xr fstat 1 ,
 .Xr netstat 1 ,
@@ -237,6 +250,8 @@ $ sockstat -6 -P tcp
 .Xr inet 4 ,
 .Xr inet6 4 ,
 .Xr protocols 5
+.Xr libxo 3 ,
+.Xr xo_options 7
 .Sh HISTORY
 The
 .Nm
diff --git a/usr.bin/sockstat/sockstat.c b/usr.bin/sockstat/sockstat.c
index d0540c54a1aa..7355eaa272a0 100644
--- a/usr.bin/sockstat/sockstat.c
+++ b/usr.bin/sockstat/sockstat.c
@@ -55,7 +55,6 @@
 
 #include <capsicum_helpers.h>
 #include <ctype.h>
-#include <err.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <jail.h>
@@ -67,6 +66,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <libxo/xo.h>
 
 #include <libcasper.h>
 #include <casper/cap_net.h>
@@ -74,6 +74,7 @@
 #include <casper/cap_pwd.h>
 #include <casper/cap_sysctl.h>
 
+#define SOCKSTAT_XO_VERSION "1"
 #define        sstosin(ss)     ((struct sockaddr_in *)(ss))
 #define        sstosin6(ss)    ((struct sockaddr_in6 *)(ss))
 #define        sstosun(ss)     ((struct sockaddr_un *)(ss))
@@ -197,7 +198,7 @@ static bool
 _check_ksize(size_t received_size, size_t expected_size, const char 
*struct_name)
 {
        if (received_size != expected_size) {
-               warnx("%s size mismatch: expected %zd, received %zd",
+               xo_warnx("%s size mismatch: expected %zd, received %zd",
                    struct_name, expected_size, received_size);
                return false;
        }
@@ -209,7 +210,7 @@ static void
 _enforce_ksize(size_t received_size, size_t expected_size, const char 
*struct_name)
 {
        if (received_size != expected_size) {
-               errx(1, "fatal: struct %s size mismatch: expected %zd, received 
%zd",
+               xo_errx(1, "fatal: struct %s size mismatch: expected %zd, 
received %zd",
                    struct_name, expected_size, received_size);
        }
 }
@@ -227,7 +228,7 @@ get_proto_type(const char *proto)
        else
                pent = getprotobyname(proto);
        if (pent == NULL) {
-               warn("cap_getprotobyname");
+               xo_warn("cap_getprotobyname");
                return (-1);
        }
        return (pent->p_proto);
@@ -248,7 +249,7 @@ init_protos(int num)
        }
 
        if ((protos = malloc(sizeof(int) * proto_count)) == NULL)
-               err(1, "malloc");
+               xo_err(1, "malloc");
        numprotos = proto_count;
 }
 
@@ -282,17 +283,17 @@ parse_ports(const char *portspec)
 
        if (ports == NULL)
                if ((ports = calloc(65536 / INT_BIT, sizeof(int))) == NULL)
-                       err(1, "calloc()");
+                       xo_err(1, "calloc()");
        p = portspec;
        while (*p != '\0') {
                if (!isdigit(*p))
-                       errx(1, "syntax error in port range");
+                       xo_errx(1, "syntax error in port range");
                for (q = p; *q != '\0' && isdigit(*q); ++q)
                        /* nothing */ ;
                for (port = 0; p < q; ++p)
                        port = port * 10 + digittoint(*p);
                if (port < 0 || port > 65535)
-                       errx(1, "invalid port number");
+                       xo_errx(1, "invalid port number");
                SET_PORT(port);
                switch (*p) {
                case '-':
@@ -310,7 +311,7 @@ parse_ports(const char *portspec)
                for (end = 0; p < q; ++p)
                        end = end * 10 + digittoint(*p);
                if (end < port || end > 65535)
-                       errx(1, "invalid port number");
+                       xo_errx(1, "invalid port number");
                while (port++ < end)
                        SET_PORT(port);
                if (*p == ',')
@@ -395,15 +396,15 @@ gather_sctp(void)
        varname = "net.inet.sctp.assoclist";
        if (cap_sysctlbyname(capsysctl, varname, 0, &len, 0, 0) < 0) {
                if (errno != ENOENT)
-                       err(1, "cap_sysctlbyname()");
+                       xo_err(1, "cap_sysctlbyname()");
                return;
        }
        if ((buf = (char *)malloc(len)) == NULL) {
-               err(1, "malloc()");
+               xo_err(1, "malloc()");
                return;
        }
        if (cap_sysctlbyname(capsysctl, varname, buf, &len, 0, 0) < 0) {
-               err(1, "cap_sysctlbyname()");
+               xo_err(1, "cap_sysctlbyname()");
                free(buf);
                return;
        }
@@ -411,7 +412,7 @@ gather_sctp(void)
        offset = sizeof(struct xsctp_inpcb);
        while ((offset < len) && (xinpcb->last == 0)) {
                if ((sock = calloc(1, sizeof *sock)) == NULL)
-                       err(1, "malloc()");
+                       xo_err(1, "malloc()");
                sock->socket = xinpcb->socket;
                sock->proto = IPPROTO_SCTP;
                sock->protoname = "sctp";
@@ -439,7 +440,7 @@ gather_sctp(void)
                        if (xladdr->last == 1)
                                break;
                        if ((laddr = calloc(1, sizeof(struct addr))) == NULL)
-                               err(1, "malloc()");
+                               xo_err(1, "malloc()");
                        switch (xladdr->address.sa.sa_family) {
                        case AF_INET:
 #define        __IN_IS_ADDR_LOOPBACK(pina) \
@@ -461,7 +462,7 @@ gather_sctp(void)
                                    htons(xinpcb->local_port));
                                break;
                        default:
-                               errx(1, "address family %d not supported",
+                               xo_errx(1, "address family %d not supported",
                                    xladdr->address.sa.sa_family);
                        }
                        laddr->next = NULL;
@@ -474,7 +475,7 @@ gather_sctp(void)
                if (sock->laddr == NULL) {
                        if ((sock->laddr =
                            calloc(1, sizeof(struct addr))) == NULL)
-                               err(1, "malloc()");
+                               xo_err(1, "malloc()");
                        sock->laddr->address.ss_family = sock->family;
                        if (sock->family == AF_INET)
                                sock->laddr->address.ss_len =
@@ -485,7 +486,7 @@ gather_sctp(void)
                        local_all_loopback = 0;
                }
                if ((sock->faddr = calloc(1, sizeof(struct addr))) == NULL)
-                       err(1, "malloc()");
+                       xo_err(1, "malloc()");
                sock->faddr->address.ss_family = sock->family;
                if (sock->family == AF_INET)
                        sock->faddr->address.ss_len =
@@ -512,7 +513,7 @@ gather_sctp(void)
                        no_stcb = 0;
                        if (opt_c) {
                                if ((sock = calloc(1, sizeof *sock)) == NULL)
-                                       err(1, "malloc()");
+                                       xo_err(1, "malloc()");
                                sock->socket = xinpcb->socket;
                                sock->proto = IPPROTO_SCTP;
                                sock->protoname = "sctp";
@@ -542,7 +543,7 @@ gather_sctp(void)
                                        continue;
                                laddr = calloc(1, sizeof(struct addr));
                                if (laddr == NULL)
-                                       err(1, "malloc()");
+                                       xo_err(1, "malloc()");
                                switch (xladdr->address.sa.sa_family) {
                                case AF_INET:
 #define        __IN_IS_ADDR_LOOPBACK(pina) \
@@ -564,7 +565,7 @@ gather_sctp(void)
                                            htons(xstcb->local_port));
                                        break;
                                default:
-                                       errx(1,
+                                       xo_errx(1,
                                            "address family %d not supported",
                                            xladdr->address.sa.sa_family);
                                }
@@ -587,7 +588,7 @@ gather_sctp(void)
                                        continue;
                                faddr = calloc(1, sizeof(struct addr));
                                if (faddr == NULL)
-                                       err(1, "malloc()");
+                                       xo_err(1, "malloc()");
                                switch (xraddr->address.sa.sa_family) {
                                case AF_INET:
 #define        __IN_IS_ADDR_LOOPBACK(pina) \
@@ -609,7 +610,7 @@ gather_sctp(void)
                                            htons(xstcb->remote_port));
                                        break;
                                default:
-                                       errx(1,
+                                       xo_errx(1,
                                            "address family %d not supported",
                                            xraddr->address.sa.sa_family);
                                }
@@ -673,7 +674,7 @@ gather_inet(int proto)
                protoname = "div";
                break;
        default:
-               errx(1, "protocol %d not supported", proto);
+               xo_errx(1, "protocol %d not supported", proto);
        }
 
        buf = NULL;
@@ -682,7 +683,7 @@ gather_inet(int proto)
        do {
                for (;;) {
                        if ((buf = realloc(buf, bufsize)) == NULL)
-                               err(1, "realloc()");
+                               xo_err(1, "realloc()");
                        len = bufsize;
                        if (cap_sysctlbyname(capsysctl, varname, buf, &len,
                            NULL, 0) == 0)
@@ -690,7 +691,7 @@ gather_inet(int proto)
                        if (errno == ENOENT)
                                goto out;
                        if (errno != ENOMEM || len != bufsize)
-                               err(1, "cap_sysctlbyname()");
+                               xo_err(1, "cap_sysctlbyname()");
                        bufsize *= 2;
                }
                xig = (struct xinpgen *)buf;
@@ -701,7 +702,7 @@ gather_inet(int proto)
        } while (xig->xig_gen != exig->xig_gen && retry--);
 
        if (xig->xig_gen != exig->xig_gen && opt_v)
-               warnx("warning: data may be inconsistent");
+               xo_warnx("warning: data may be inconsistent");
 
        for (;;) {
                xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len);
@@ -722,7 +723,7 @@ gather_inet(int proto)
                                goto out;
                        break;
                default:
-                       errx(1, "protocol %d not supported", proto);
+                       xo_errx(1, "protocol %d not supported", proto);
                }
                so = &xip->xi_socket;
                if ((xip->inp_vflag & vflag) == 0)
@@ -748,15 +749,15 @@ gather_inet(int proto)
                                continue;
                } else {
                        if (opt_v)
-                               warnx("invalid vflag 0x%x", xip->inp_vflag);
+                               xo_warnx("invalid vflag 0x%x", xip->inp_vflag);
                        continue;
                }
                if ((sock = calloc(1, sizeof(*sock))) == NULL)
-                       err(1, "malloc()");
+                       xo_err(1, "malloc()");
                if ((laddr = calloc(1, sizeof *laddr)) == NULL)
-                       err(1, "malloc()");
+                       xo_err(1, "malloc()");
                if ((faddr = calloc(1, sizeof *faddr)) == NULL)
-                       err(1, "malloc()");
+                       xo_err(1, "malloc()");
                sock->socket = so->xso_so;
                sock->pcb = so->so_pcb;
                sock->splice_socket = so->so_splice_so;
@@ -822,7 +823,9 @@ gather_unix(int proto)
                break;
        case SOCK_SEQPACKET:
                varname = "net.local.seqpacket.pcblist";
-               protoname = "seqpac";
+               protoname = (xo_get_style(NULL) == XO_STYLE_TEXT)
+                               ? "seqpac"
+                               : "seqpacket";
                break;
        default:
                abort();
@@ -833,13 +836,13 @@ gather_unix(int proto)
        do {
                for (;;) {
                        if ((buf = realloc(buf, bufsize)) == NULL)
-                               err(1, "realloc()");
+                               xo_err(1, "realloc()");
                        len = bufsize;
                        if (cap_sysctlbyname(capsysctl, varname, buf, &len,
                            NULL, 0) == 0)
                                break;
                        if (errno != ENOMEM || len != bufsize)
-                               err(1, "cap_sysctlbyname()");
+                               xo_err(1, "cap_sysctlbyname()");
                        bufsize *= 2;
                }
                xug = (struct xunpgen *)buf;
@@ -851,7 +854,7 @@ gather_unix(int proto)
        } while (xug->xug_gen != exug->xug_gen && retry--);
 
        if (xug->xug_gen != exug->xug_gen && opt_v)
-               warnx("warning: data may be inconsistent");
+               xo_warnx("warning: data may be inconsistent");
 
        for (;;) {
                xug = (struct xunpgen *)(void *)((char *)xug + xug->xug_len);
@@ -864,11 +867,11 @@ gather_unix(int proto)
                    (xup->unp_conn != 0 && !opt_c))
                        continue;
                if ((sock = calloc(1, sizeof(*sock))) == NULL)
-                       err(1, "malloc()");
+                       xo_err(1, "malloc()");
                if ((laddr = calloc(1, sizeof *laddr)) == NULL)
-                       err(1, "malloc()");
+                       xo_err(1, "malloc()");
                if ((faddr = calloc(1, sizeof *faddr)) == NULL)
-                       err(1, "malloc()");
+                       xo_err(1, "malloc()");
                sock->socket = xup->xu_socket.xso_so;
                sock->pcb = xup->xu_unpp;
                sock->proto = proto;
@@ -899,21 +902,21 @@ getfiles(void)
 
        olen = len = sizeof(*xfiles);
        if ((xfiles = malloc(len)) == NULL)
-               err(1, "malloc()");
+               xo_err(1, "malloc()");
        while (cap_sysctlbyname(capsysctl, "kern.file", xfiles, &len, 0, 0)
            == -1) {
                if (errno != ENOMEM || len != olen)
-                       err(1, "cap_sysctlbyname()");
+                       xo_err(1, "cap_sysctlbyname()");
                olen = len *= 2;
                if ((xfiles = realloc(xfiles, len)) == NULL)
-                       err(1, "realloc()");
+                       xo_err(1, "realloc()");
        }
        if (len > 0)
                enforce_ksize(xfiles->xf_size, struct xfile);
        nfiles = len / sizeof(*xfiles);
 
        if ((files = malloc(nfiles * sizeof(struct file))) == NULL)
-               err(1, "malloc()");
+               xo_err(1, "malloc()");
 
        for (int i = 0; i < nfiles; i++) {
                files[i].xf_data = xfiles[i].xf_data;
@@ -932,6 +935,7 @@ formataddr(struct sockaddr_storage *ss, char *buf, size_t 
bufsize)
        struct sockaddr_un *sun;
        char addrstr[NI_MAXHOST] = { '\0', '\0' };
        int error, off, port = 0;
+       const bool is_text_style = (xo_get_style(NULL) == XO_STYLE_TEXT);
 
        switch (ss->ss_family) {
        case AF_INET:
@@ -947,6 +951,11 @@ formataddr(struct sockaddr_storage *ss, char *buf, size_t 
bufsize)
        case AF_UNIX:
                sun = sstosun(ss);
                off = (int)((char *)&sun->sun_path - (char *)sun);
+               if (!is_text_style) {
+                       xo_emit("{:path/%.*s}", sun->sun_len - off,
+                               sun->sun_path);
+                       return 0;
+               }
                return snprintf(buf, bufsize, "%.*s",
                                sun->sun_len - off, sun->sun_path);
        }
@@ -954,7 +963,12 @@ formataddr(struct sockaddr_storage *ss, char *buf, size_t 
bufsize)
                error = cap_getnameinfo(capnet, sstosa(ss), ss->ss_len,
                    addrstr, sizeof(addrstr), NULL, 0, NI_NUMERICHOST);
                if (error)
-                       errx(1, "cap_getnameinfo()");
+                       xo_errx(1, "cap_getnameinfo()");
+       }
+       if (!is_text_style) {
+               xo_emit("{:address/%s}", addrstr);
+               xo_emit("{:port/%d}", port);
+               return 0;
        }
        if (port == 0)
                return snprintf(buf, bufsize, "%s:*", addrstr);
@@ -977,7 +991,7 @@ getprocname(pid_t pid)
            == -1) {
                /* Do not warn if the process exits before we get its name. */
                if (errno != ESRCH)
-                       warn("cap_sysctl()");
+                       xo_warn("cap_sysctl()");
                return ("??");
        }
        return (proc.ki_comm);
@@ -999,7 +1013,7 @@ getprocjid(pid_t pid)
            == -1) {
                /* Do not warn if the process exits before we get its jid. */
                if (errno != ESRCH)
-                       warn("cap_sysctl()");
+                       xo_warn("cap_sysctl()");
                return (-1);
        }
        return (proc.ki_jid);
@@ -1099,13 +1113,15 @@ format_unix_faddr(struct addr *faddr, char *buf, size_t 
bufsize) {
        #define SAFESIZE (buf == NULL ? 0 : bufsize - pos)
 
        size_t pos = 0;
-       /* Remote peer we connect(2) to, if any. */
+       const bool is_text_style = (xo_get_style(NULL) == XO_STYLE_TEXT);
        if (faddr->conn != 0) {
+               /* Remote peer we connect(2) to, if any. */
                struct sock *p;
-               pos += strlcpy(SAFEBUF, "-> ", SAFESIZE);
+               if (is_text_style)
+                       pos += strlcpy(SAFEBUF, "-> ", SAFESIZE);
                p = RB_FIND(pcbs_t, &pcbs,
                        &(struct sock){ .pcb = faddr->conn });
-               if (__predict_false(p == NULL)) {
+               if (__predict_false(p == NULL) && is_text_style) {
                        /* XXGL: can this happen at all? */
                        pos += snprintf(SAFEBUF, SAFESIZE, "??");
                } else if (p->laddr->address.ss_len == 0) {
@@ -1114,34 +1130,52 @@ format_unix_faddr(struct addr *faddr, char *buf, size_t 
bufsize) {
                                &(struct file){ .xf_data =
                                p->socket });
                        if (f != NULL) {
-                               pos += snprintf(SAFEBUF, SAFESIZE, "[%lu %d]",
-                                       (u_long)f->xf_pid, f->xf_fd);
+                               if (is_text_style) {
+                                       pos += snprintf(SAFEBUF, SAFESIZE,
+                                               "[%lu %d]", (u_long)f->xf_pid,
+                                               f->xf_fd);
+                               } else {
+                                       xo_open_list("connections");
+                                       xo_open_instance("connections");
+                                       xo_emit("{:pid/%lu}", 
(u_long)f->xf_pid);
+                                       xo_emit("{:fd/%d}", f->xf_fd);
+                                       xo_close_instance("connections");
+                                       xo_close_list("connections");
+                               }
                        }
                } else
                        pos += formataddr(&p->laddr->address,
                                SAFEBUF, SAFESIZE);
-       }
-       /* Remote peer(s) connect(2)ed to us, if any. */
-       if (faddr->firstref != 0) {
+       } else if (faddr->firstref != 0) {
+               /* Remote peer(s) connect(2)ed to us, if any. */
                struct sock *p;
                struct file *f;
                kvaddr_t ref = faddr->firstref;
                bool fref = true;
 
-               pos += snprintf(SAFEBUF, SAFESIZE, " <- ");
-
+               if (is_text_style)
+                       pos += snprintf(SAFEBUF, SAFESIZE, " <- ");
+               xo_open_list("connections");
                while ((p = RB_FIND(pcbs_t, &pcbs,
                        &(struct sock){ .pcb = ref })) != 0) {
                        f = RB_FIND(files_t, &ftree,
                                &(struct file){ .xf_data = p->socket });
                        if (f != NULL) {
-                               pos += snprintf(SAFEBUF, SAFESIZE,
-                                       "%s[%lu %d]", fref ? "" : ",",
-                                       (u_long)f->xf_pid, f->xf_fd);
+                               if (is_text_style) {
+                                       pos += snprintf(SAFEBUF, SAFESIZE,
+                                               "%s[%lu %d]", fref ? "" : ",",
+                                               (u_long)f->xf_pid, f->xf_fd);
+                               } else {
+                                       xo_open_instance("connections");
+                                       xo_emit("{:pid/%lu}", 
(u_long)f->xf_pid);
+                                       xo_emit("{:fd/%d}", f->xf_fd);
+                                       xo_close_instance("connections");
+                               }
                        }
                        ref = p->faddr->nextref;
                        fref = false;
                }
+               xo_close_list("connections");
        }
        return pos;
 }
@@ -1183,7 +1217,7 @@ calculate_sock_column_widths(struct col_widths *cw, 
struct sock *s)
        while (laddr != NULL || faddr != NULL) {
                if (opt_w && s->family == AF_UNIX) {
                        if ((laddr == NULL) || (faddr == NULL))
-                               errx(1, "laddr = %p or faddr = %p is NULL",
+                               xo_errx(1, "laddr = %p or faddr = %p is NULL",
                                        (void *)laddr, (void *)faddr);
                        if (laddr->address.ss_len > 0)
                                len = formataddr(&laddr->address, NULL, 0);
@@ -1298,6 +1332,7 @@ calculate_column_widths(struct col_widths *cw)
        struct sock *s;
        struct passwd *pwd;
 
+       cap_setpassent(cappwd, 1);
        for (xf = files, n = 0; n < nfiles; ++n, ++xf) {
                if (xf->xf_data == 0)
                        continue;
@@ -1345,65 +1380,104 @@ display_sock(struct sock *s, struct col_widths *cw, 
char *buf, size_t bufsize)
        laddr = s->laddr;
        faddr = s->faddr;
        first = true;
+       const bool is_text_style = (xo_get_style(NULL) == XO_STYLE_TEXT);
 
        snprintf(buf, bufsize, "%s%s%s",
                s->protoname,
                s->vflag & INP_IPV4 ? "4" : "",
                s->vflag & INP_IPV6 ? "6" : "");
-       printf(" %-*s", cw->proto, buf);
+       xo_emit(" {:proto/%-*s}", cw->proto, buf);
        while (laddr != NULL || faddr != NULL) {
                if (s->family == AF_UNIX) {
                        if ((laddr == NULL) || (faddr == NULL))
-                               errx(1, "laddr = %p or faddr = %p is NULL",
+                               xo_errx(1, "laddr = %p or faddr = %p is NULL",
                                        (void *)laddr, (void *)faddr);
-                       if (laddr->address.ss_len > 0)
+                       if (laddr->address.ss_len > 0) {
+                               xo_open_container("local");
                                formataddr(&laddr->address, buf, bufsize);
-                       else if (laddr->address.ss_len == 0 && faddr->conn == 0)
-                               strlcpy(buf, "(not connected)", bufsize);
-                       else
-                               strlcpy(buf, "??", bufsize);
-                       printf(" %-*.*s", cw->local_addr, cw->local_addr, buf);
-                       if (format_unix_faddr(faddr, buf, bufsize) == 0)
-                               strlcpy(buf, "??", bufsize);
-                       printf(" %-*.*s", cw->foreign_addr,
-                               cw->foreign_addr, buf);
+                               if (is_text_style) {
+                                       xo_emit(" {:/%-*.*s}", cw->local_addr,
+                                               cw->local_addr, buf);
+                               }
+                               xo_close_container("local");
+                       } else if (laddr->address.ss_len == 0 &&
+                               faddr->conn == 0 && is_text_style) {
+                               xo_emit(" {:/%-*.*s}", cw->local_addr,
+                                       cw->local_addr, "(not connected)");
+                       } else if (is_text_style) {
+                               xo_emit(" {:/%-*.*s}", cw->local_addr,
+                                       cw->local_addr, "??");
+                       }
+                       if (faddr->conn != 0 || faddr->firstref != 0) {
+                               xo_open_container("foreign");
+                               int len = format_unix_faddr(faddr, buf,
+                                               bufsize);
+                               if (len == 0 && is_text_style)
+                                       xo_emit(" {:/%-*s}",
+                                               cw->foreign_addr, "??");
+                               else if (is_text_style)
+                                       xo_emit(" {:/%-*.*s}", cw->foreign_addr,
+                                               cw->foreign_addr, buf);
+                               xo_close_container("foreign");
+                       } else if (is_text_style)
+                               xo_emit(" {:/%-*s}", cw->foreign_addr, "??");
                } else {
-                       if (laddr != NULL)
+                       if (laddr != NULL) {
+                               xo_open_container("local");
                                formataddr(&laddr->address, buf, bufsize);
-                       else
-                               strlcpy(buf, "??", bufsize);
-                       printf(" %-*.*s", cw->local_addr, cw->local_addr, buf);
-                       if (faddr != NULL)
+                               if (is_text_style) {
+                                       xo_emit(" {:/%-*.*s}", cw->local_addr,
+                                               cw->local_addr, buf);
+                               }
+                               xo_close_container("local");
+                       } else if (is_text_style)
+                               xo_emit(" {:/%-*.*s}", cw->local_addr,
+                                       cw->local_addr, "??");
+                       if (faddr != NULL) {
+                               xo_open_container("foreign");
                                formataddr(&faddr->address, buf, bufsize);
-                       else
-                               strlcpy(buf, "??", bufsize);
-                       printf(" %-*.*s", cw->foreign_addr,
-                               cw->foreign_addr, buf);
+                               if (is_text_style) {
+                                       xo_emit(" {:/%-*.*s}", cw->foreign_addr,
+                                               cw->foreign_addr, buf);
+                               }
+                               xo_close_container("foreign");
+                       } else if (is_text_style) {
+                               xo_emit(" {:/%-*.*s}", cw->foreign_addr,
+                                       cw->foreign_addr, "??");
+                       }
+               }
+               if (opt_A) {
+                       snprintf(buf, bufsize, "%#*" PRIx64,
+                               cw->pcb_kva, s->pcb);
+                       xo_emit(" {:pcb-kva/%s}", buf);
                }
-               if (opt_A)
-                       printf(" %#*" PRIx64, cw->pcb_kva, s->pcb);
                if (opt_f)
-                       printf(" %*d", cw->fib, s->fibnum);
+                       xo_emit(" {:fib/%*d}", cw->fib, s->fibnum);
                if (opt_I) {
                        if (s->splice_socket != 0) {
                                struct sock *sp;
                                sp = RB_FIND(socks_t, &socks, &(struct sock)
                                        { .socket = s->splice_socket });
-                               if (sp != NULL)
+                               if (sp != NULL) {
+                                       xo_open_container("splice");
                                        formataddr(&sp->laddr->address,
                                                                buf, bufsize);
-                               else
+                                       xo_close_container("splice");
+                               } else if (is_text_style)
                                        strlcpy(buf, "??", bufsize);
-                       } else
+                       } else if (is_text_style)
                                strlcpy(buf, "??", bufsize);
-                       printf(" %-*s", cw->splice_address, buf);
+                       if (is_text_style)
+                               xo_emit(" {:/%-*s}", cw->splice_address, buf);
                }
                if (opt_i) {
                        if (s->proto == IPPROTO_TCP || s->proto == IPPROTO_UDP)
-                               printf(" %*" PRIu64, cw->inp_gencnt,
+                       {
+                               snprintf(buf, bufsize, "%" PRIu64,
                                        s->inp_gencnt);
-                       else
-                               printf(" %*s", cw->inp_gencnt, "??");
+                               xo_emit(" {:id/%*s}", cw->inp_gencnt, buf);
+                       } else if (is_text_style)
+                               xo_emit(" {:/%*s}", cw->inp_gencnt, "??");
                }
                if (opt_U) {
                        if (faddr != NULL &&
@@ -1414,10 +1488,10 @@ display_sock(struct sock *s, struct col_widths *cw, 
char *buf, size_t bufsize)
                                        (s->proto == IPPROTO_TCP &&
                                        s->state != TCPS_CLOSED &&
                                        s->state != TCPS_LISTEN))) {
-                               printf(" %*u", cw->encaps,
+                               xo_emit(" {:encaps/%*u}", cw->encaps,
                                        ntohs(faddr->encaps_port));
-                       } else
-                               printf(" %*s", cw->encaps, "??");
+                       } else if (is_text_style)
+                               xo_emit(" {:/%*s}", cw->encaps, "??");
                }
                if (opt_s) {
                        if (faddr != NULL &&
@@ -1425,10 +1499,10 @@ display_sock(struct sock *s, struct col_widths *cw, 
char *buf, size_t bufsize)
                                s->state != SCTP_CLOSED &&
                                s->state != SCTP_BOUND &&
                                s->state != SCTP_LISTEN) {
-                               printf(" %-*s", cw->path_state,
+                               xo_emit(" {:path-state/%-*s}", cw->path_state,
                                        sctp_path_state(faddr->state));
-                       } else
-                               printf(" %-*s", cw->path_state, "??");
+                       } else if (is_text_style)
+                               xo_emit(" {:/%-*s}", cw->path_state, "??");
                }
                if (first) {
                        if (opt_s) {
@@ -1436,47 +1510,52 @@ display_sock(struct sock *s, struct col_widths *cw, 
char *buf, size_t bufsize)
                                    s->proto == IPPROTO_TCP) {
                                        switch (s->proto) {
                                        case IPPROTO_SCTP:
-                                               printf(" %-*s", cw->conn_state,
-                                                   sctp_conn_state(s->state));
+                                               xo_emit(" {:path-state/%-*s}",
+                                                       cw->path_state,
+                                                       sctp_path_state(
+                                                               faddr->state));
                                                break;
                                        case IPPROTO_TCP:
                                                if (s->state >= 0 &&
                                                        s->state < TCP_NSTATES)
-                                                       printf(" %-*s",
-                                                       cw->conn_state,
-                                                       tcpstates[s->state]);
-                                               else
-                                                       printf(" %-*s",
-                                                       cw->conn_state, "??");
+                                                       xo_emit(" 
{:conn-state/%-*s}",
+                                                               cw->conn_state,
+                                                               
tcpstates[s->state]);
+                                               else if (is_text_style)
+                                                       xo_emit(" {:/%-*s}",
+                                                               cw->conn_state, 
"??");
                                                break;
                                        }
-                               } else
-                                       printf(" %-*s", cw->conn_state, "??");
+                               } else if (is_text_style)
+                                       xo_emit(" {:/%-*s}",
+                                               cw->conn_state, "??");
                        }
                        if (opt_S) {
                                if (s->proto == IPPROTO_TCP)
-                                       printf(" %-*s", cw->stack, s->stack);
-                               else
-                                       printf(" %-*s", cw->stack, "??");
+                                       xo_emit(" {:stack/%-*s}",
+                                               cw->stack, s->stack);
+                               else if (is_text_style)
+                                       xo_emit(" {:/%-*s}",
+                                               cw->stack, "??");
                        }
                        if (opt_C) {
                                if (s->proto == IPPROTO_TCP)
-                                       printf(" %-*s", cw->cc, s->cc);
-                               else
-                                       printf(" %-*s", cw->cc, "??");
+                                       xo_emit(" {:cc/%-*s}", cw->cc, s->cc);
+                               else if (is_text_style)
+                                       xo_emit(" {:/%-*s}", cw->cc, "??");
                        }
                }
                if (laddr != NULL)
                        laddr = laddr->next;
                if (faddr != NULL)
                        faddr = faddr->next;
-               if (laddr != NULL || faddr != NULL)
-                       printf("%-*s %-*s %-*s %-*s %-*s", cw->user, "",
-                               cw->command, "", cw->pid, "", cw->fd, "",
-                               cw->proto, "");
+               if (is_text_style && (laddr != NULL || faddr != NULL))
+                       xo_emit("{:/%-*s} {:/%-*s} {:/%*s} {:/%*s}",
+                               cw->user, "??", cw->command, "??",
+                               cw->pid, "??", cw->fd, "??");
                first = false;
        }
-       printf("\n");
+       xo_emit("\n");
 }
 
 static void
@@ -1490,56 +1569,63 @@ display(void)
        const size_t bufsize = 512;
        void *buf;
        if ((buf = (char *)malloc(bufsize)) == NULL) {
-               err(1, "malloc()");
+               xo_err(1, "malloc()");
                return;
        }
 
-       cw = (struct col_widths) {
-               .user = strlen("USER"),
-               .command = 10,
-               .pid = strlen("PID"),
-               .fd = strlen("FD"),
-               .proto = strlen("PROTO"),
-               .local_addr = opt_w ? strlen("LOCAL ADDRESS") : 21,
-               .foreign_addr = opt_w ? strlen("FOREIGN ADDRESS") : 21,
-               .pcb_kva = 18,
-               .fib = strlen("FIB"),
-               .splice_address = strlen("SPLICE ADDRESS"),
-               .inp_gencnt = strlen("ID"),
-               .encaps = strlen("ENCAPS"),
-               .path_state = strlen("PATH STATE"),
-               .conn_state = strlen("CONN STATE"),
-               .stack = strlen("STACK"),
-               .cc = strlen("CC"),
-       };
-       calculate_column_widths(&cw);
+       if (xo_get_style(NULL) == XO_STYLE_TEXT) {
+               cw = (struct col_widths) {
+                       .user = strlen("USER"),
+                       .command = 10,
+                       .pid = strlen("PID"),
+                       .fd = strlen("FD"),
+                       .proto = strlen("PROTO"),
+                       .local_addr = opt_w ? strlen("LOCAL ADDRESS") : 21,
+                       .foreign_addr = opt_w ? strlen("FOREIGN ADDRESS") : 21,
+                       .pcb_kva = 18,
+                       .fib = strlen("FIB"),
+                       .splice_address = strlen("SPLICE ADDRESS"),
+                       .inp_gencnt = strlen("ID"),
+                       .encaps = strlen("ENCAPS"),
+                       .path_state = strlen("PATH STATE"),
+                       .conn_state = strlen("CONN STATE"),
+                       .stack = strlen("STACK"),
+                       .cc = strlen("CC"),
+               };
+               calculate_column_widths(&cw);
+       } else
+               memset(&cw, 0, sizeof(cw));
 
+       xo_set_version(SOCKSTAT_XO_VERSION);
+       xo_open_container("sockstat");
+       xo_open_list("socket");
        if (!opt_q) {
-               printf("%-*s %-*s %*s %*s %-*s %-*s %-*s",
-                               cw.user, "USER", cw.command, "COMMAND",
-                               cw.pid, "PID", cw.fd, "FD", cw.proto, "PROTO",
-                               cw.local_addr, "LOCAL ADDRESS",
-                               cw.foreign_addr,"FOREIGN ADDRESS");
+               xo_emit("{T:/%-*s} {T:/%-*s} {T:/%*s} {T:/%*s} {T:/%-*s} "
+                       "{T:/%-*s} {T:/%-*s}", cw.user, "USER", cw.command,
+                       "COMMAND", cw.pid, "PID", cw.fd, "FD", cw.proto,
+                       "PROTO", cw.local_addr, "LOCAL ADDRESS",
+                       cw.foreign_addr, "FOREIGN ADDRESS");
                if (opt_A)
-                       printf(" %-*s", cw.pcb_kva, "PCB KVA");
+                       xo_emit(" {T:/%-*s}", cw.pcb_kva, "PCB KVA");
                if (opt_f)
                        /* RT_MAXFIBS is 65535. */
-                       printf(" %*s", cw.fib, "FIB");
+                       xo_emit(" {T:/%*s}", cw.fib, "FIB");
                if (opt_I)
-                       printf(" %-*s", cw.splice_address, "SPLICE ADDRESS");
+                       xo_emit(" {T:/%-*s}", cw.splice_address,
+                               "SPLICE ADDRESS");
                if (opt_i)
-                       printf(" %*s", cw.inp_gencnt, "ID");
+                       xo_emit(" {T:/%*s}", cw.inp_gencnt, "ID");
                if (opt_U)
-                       printf(" %*s", cw.encaps, "ENCAPS");
+                       xo_emit(" {T:/%*s}", cw.encaps, "ENCAPS");
                if (opt_s) {
-                       printf(" %-*s", cw.path_state, "PATH STATE");
-                       printf(" %-*s", cw.conn_state, "CONN STATE");
+                       xo_emit(" {T:/%-*s}", cw.path_state, "PATH STATE");
+                       xo_emit(" {T:/%-*s}", cw.conn_state, "CONN STATE");
                }
                if (opt_S)
-                       printf(" %-*s", cw.stack, "STACK");
+                       xo_emit(" {T:/%-*s}", cw.stack, "STACK");
                if (opt_C)
-                       printf(" %-*s", cw.cc, "CC");
-               printf("\n");
+                       xo_emit(" {T:/%-*s}", cw.cc, "CC");
+               xo_emit("\n");
        }
        cap_setpassent(cappwd, 1);
        for (xf = files, n = 0; n < nfiles; ++n, ++xf) {
@@ -1550,17 +1636,24 @@ display(void)
                s = RB_FIND(socks_t, &socks,
                        &(struct sock){ .socket = xf->xf_data});
                if (s != NULL && check_ports(s)) {
+                       xo_open_instance("socket");
                        s->shown = 1;
                        if (opt_n ||
                            (pwd = cap_getpwuid(cappwd, xf->xf_uid)) == NULL)
-                               printf("%-*lu", cw.user, (u_long)xf->xf_uid);
+                               xo_emit("{:user/%-*lu}", cw.user,
+                                       (u_long)xf->xf_uid);
+                       else
+                               xo_emit("{:user/%-*s}", cw.user, pwd->pw_name);
+                       if (xo_get_style(NULL) == XO_STYLE_TEXT)
+                               xo_emit(" {:/%-*.10s}", cw.command,
+                                       getprocname(xf->xf_pid));
                        else
-                               printf("%-*s", cw.user, pwd->pw_name);
-                       printf(" %-*.*s", cw.command, cw.command,
-                               getprocname(xf->xf_pid));
-                       printf(" %*lu", cw.pid, (u_long)xf->xf_pid);
-                       printf(" %*d", cw.fd, xf->xf_fd);
+                               xo_emit(" {:command/%-*s}", cw.command,
+                                       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);
+                       xo_close_instance("socket");
                }
        }
        if (opt_j >= 0)
@@ -1568,20 +1661,33 @@ display(void)
        SLIST_FOREACH(s, &nosocks, socket_list) {
                if (!check_ports(s))
                        continue;
-               printf("%-*s %-*s %*s %*s", cw.user, "??", cw.command, "??",
-                       cw.pid, "??", cw.fd, "??");
+               xo_open_instance("socket");
+               if (xo_get_style(NULL) == XO_STYLE_TEXT)
+                       xo_emit("{:/%-*s} {:/%-*s} {:/%*s} {:/%*s}",
+                               cw.user, "??", cw.command, "??",
+                               cw.pid, "??", cw.fd, "??");
                display_sock(s, &cw, buf, bufsize);
+               xo_close_instance("socket");
        }
        RB_FOREACH(s, socks_t, &socks) {
                if (s->shown)
                        continue;
                if (!check_ports(s))
                        continue;
-               printf("%-*s %-*s %*s %*s", cw.user, "??", cw.command, "??",
-                       cw.pid, "??", cw.fd, "??");
+               xo_open_instance("socket");
+               if (xo_get_style(NULL) == XO_STYLE_TEXT)
+                       xo_emit("{:/%-*s} {:/%-*s} {:/%*s} {:/%*s}",
+                               cw.user, "??", cw.command, "??",
+                               cw.pid, "??", cw.fd, "??");
                display_sock(s, &cw, buf, bufsize);
+               xo_close_instance("socket");
        }
+       xo_close_list("socket");
+       xo_close_container("sockstat");
*** 103 LINES SKIPPED ***

Reply via email to