From 474b62b876718890adf24759cc7c15fa5cb7778e Mon Sep 17 00:00:00 2001 From: Allan Jude Date: Sat, 5 Sep 2015 17:02:01 +0000 Subject: [PATCH] Introduce libxo to procstat(1) Reviewed by: rodrigc, bapt Approved by: marcel (mentor) Relnotes: yes Sponsored by: ScaleEngine Inc. Differential Revision: https://reviews.freebsd.org/D2446 --- usr.bin/procstat/Makefile | 2 +- usr.bin/procstat/procstat.1 | 25 ++-- usr.bin/procstat/procstat.c | 61 ++++++++-- usr.bin/procstat/procstat.h | 5 + usr.bin/procstat/procstat_args.c | 51 ++++++--- usr.bin/procstat/procstat_auxv.c | 93 +++++++++------ usr.bin/procstat/procstat_basic.c | 27 +++-- usr.bin/procstat/procstat_bin.c | 12 +- usr.bin/procstat/procstat_cred.c | 32 +++--- usr.bin/procstat/procstat_cs.c | 39 ++++--- usr.bin/procstat/procstat_files.c | 170 +++++++++++++++++++--------- usr.bin/procstat/procstat_kstack.c | 60 ++++++++-- usr.bin/procstat/procstat_rlimit.c | 27 ++++- usr.bin/procstat/procstat_rusage.c | 60 ++++++++-- usr.bin/procstat/procstat_sigs.c | 100 ++++++++++++---- usr.bin/procstat/procstat_threads.c | 44 ++++--- usr.bin/procstat/procstat_vm.c | 89 +++++++++++---- 17 files changed, 654 insertions(+), 243 deletions(-) diff --git a/usr.bin/procstat/Makefile b/usr.bin/procstat/Makefile index 211ce1a1431b..21f325f05b2a 100644 --- a/usr.bin/procstat/Makefile +++ b/usr.bin/procstat/Makefile @@ -17,6 +17,6 @@ SRCS= procstat.c \ procstat_threads.c \ procstat_vm.c -LIBADD+= util procstat +LIBADD+= procstat xo util sbuf .include diff --git a/usr.bin/procstat/procstat.1 b/usr.bin/procstat/procstat.1 index 0fd314f5a701..68aaaee72f48 100644 --- a/usr.bin/procstat/procstat.1 +++ b/usr.bin/procstat/procstat.1 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 18, 2015 +.Dd September 5, 2015 .Dt PROCSTAT 1 .Os .Sh NAME @@ -33,6 +33,7 @@ .Nd get detailed process information .Sh SYNOPSIS .Nm +.Op Fl -libxo .Op Fl CHhn .Op Fl w Ar interval .Op Fl b | c | e | f | i | j | k | l | r | s | S | t | v | x @@ -52,6 +53,13 @@ By default, basic process statistics are printed; one of the following options may be specified in order to select more detailed process information for printing: .Bl -tag -width indent +.It Fl -libxo +Generate output via +.Xr libxo 3 +in a selection of different human and machine readable formats. +See +.Xr xo_parse_args 3 +for details on command line arguments. .It Fl b Display binary information for the process. .It Fl c @@ -531,16 +539,19 @@ auxiliary vector value .Xr cap_enter 2 , .Xr cap_rights_limit 2 , .Xr libprocstat 3 , +.Xr libxo 3 , +.Xr xo_parse_args 3 , .Xr ddb 4 , .Xr stack 9 .Sh AUTHORS -.An Robert N M Watson +.An Robert N M Watson Aq Mt rwatson@FreeBSD.org . +.br +.Xr libxo 3 +support was added by +.An -nosplit +Allan Jude +.Aq Mt allanjude@FreeBSD.org . .Sh BUGS -Some field values may include spaces, which limits the extent to which the -output of -.Nm -may be mechanically parsed. -.Pp The display of open file or memory mapping pathnames is implemented using the kernel's name cache. If a file system does not use the name cache, or the path to a file is not in diff --git a/usr.bin/procstat/procstat.c b/usr.bin/procstat/procstat.c index 48a2135180a2..cafb33525b27 100644 --- a/usr.bin/procstat/procstat.c +++ b/usr.bin/procstat/procstat.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2007, 2011 Robert N. M. Watson + * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,17 +48,24 @@ static void usage(void) { - fprintf(stderr, "usage: procstat [-CHhn] [-M core] [-N system] " - "[-w interval] \n"); - fprintf(stderr, " [-b | -c | -e | -f | -i | -j | -k | " - "-l | -r | -s | -S | -t | -v | -x]\n"); - fprintf(stderr, " [-a | pid | core ...]\n"); + xo_error("usage: procstat [-CHhn] [-M core] [-N system] " + "[-w interval]\n" + " [-b | -c | -e | -f | -i | -j | -k | " + "-l | -r | -s | -S | -t | -v | -x]\n" + " [-a | pid | core ...]\n"); + xo_finish(); exit(EX_USAGE); } static void procstat(struct procstat *prstat, struct kinfo_proc *kipp) { + char *pidstr = NULL; + + asprintf(&pidstr, "%d", kipp->ki_pid); + if (pidstr == NULL) + xo_errc(1, ENOMEM, "Failed to allocate memory in procstat()"); + xo_open_container(pidstr); if (bflag) procstat_bin(prstat, kipp); @@ -89,6 +97,9 @@ procstat(struct procstat *prstat, struct kinfo_proc *kipp) procstat_cs(prstat, kipp); else procstat_basic(kipp); + + xo_close_container(pidstr); + free(pidstr); } /* @@ -126,10 +137,14 @@ main(int argc, char *argv[]) pid_t pid; char *dummy; char *nlistf, *memf; + const char *xocontainer; int cnt; interval = 0; memf = nlistf = NULL; + argc = xo_parse_args(argc, argv); + xocontainer = "basic"; + while ((ch = getopt(argc, argv, "CHN:M:abcefijklhrsStvw:x")) != -1) { switch (ch) { case 'C': @@ -148,6 +163,7 @@ main(int argc, char *argv[]) break; case 'S': Sflag++; + xocontainer = "cs"; break; case 'a': aflag++; @@ -155,34 +171,42 @@ main(int argc, char *argv[]) case 'b': bflag++; + xocontainer = "binary"; break; case 'c': cflag++; + xocontainer = "arguments"; break; case 'e': eflag++; + xocontainer = "environment"; break; case 'f': fflag++; + xocontainer = "files"; break; case 'i': iflag++; + xocontainer = "signals"; break; case 'j': jflag++; + xocontainer = "thread_signals"; break; case 'k': kflag++; + xocontainer = "kstack"; break; case 'l': lflag++; + xocontainer = "rlimit"; break; case 'n': @@ -195,18 +219,22 @@ main(int argc, char *argv[]) case 'r': rflag++; + xocontainer = "rusage"; break; case 's': sflag++; + xocontainer = "credentials"; break; case 't': tflag++; + xocontainer = "threads"; break; case 'v': vflag++; + xocontainer = "vm"; break; case 'w': @@ -220,6 +248,7 @@ main(int argc, char *argv[]) case 'x': xflag++; + xocontainer = "auxv"; break; case '?': @@ -254,18 +283,23 @@ main(int argc, char *argv[]) else prstat = procstat_open_sysctl(); if (prstat == NULL) - errx(1, "procstat_open()"); + xo_errx(1, "procstat_open()"); do { + xo_set_version(PROCSTAT_XO_VERSION); + xo_open_container("procstat"); + xo_open_container(xocontainer); + if (aflag) { p = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &cnt); if (p == NULL) - errx(1, "procstat_getprocs()"); + xo_errx(1, "procstat_getprocs()"); kinfo_proc_sort(p, cnt); for (i = 0; i < cnt; i++) { procstat(prstat, &p[i]); /* Suppress header after first process. */ hflag = 1; + xo_flush(); } procstat_freeprocs(prstat, p); } @@ -276,9 +310,10 @@ main(int argc, char *argv[]) usage(); pid = l; - p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &cnt); + p = procstat_getprocs(prstat, KERN_PROC_PID, + pid, &cnt); if (p == NULL) - errx(1, "procstat_getprocs()"); + xo_errx(1, "procstat_getprocs()"); if (cnt != 0) procstat(prstat, p); procstat_freeprocs(prstat, p); @@ -291,7 +326,7 @@ main(int argc, char *argv[]) p = procstat_getprocs(cprstat, KERN_PROC_PID, -1, &cnt); if (p == NULL) - errx(1, "procstat_getprocs()"); + xo_errx(1, "procstat_getprocs()"); if (cnt != 0) procstat(cprstat, p); procstat_freeprocs(cprstat, p); @@ -300,9 +335,15 @@ main(int argc, char *argv[]) /* Suppress header after first process. */ hflag = 1; } + + xo_close_container(xocontainer); + xo_close_container("procstat"); + xo_finish(); if (interval) sleep(interval); } while (interval); + procstat_close(prstat); + exit(0); } diff --git a/usr.bin/procstat/procstat.h b/usr.bin/procstat/procstat.h index 50795219111f..dfdf3285ebb7 100644 --- a/usr.bin/procstat/procstat.h +++ b/usr.bin/procstat/procstat.h @@ -1,5 +1,6 @@ /*- * Copyright (c) 2007 Robert N. M. Watson + * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,9 +27,13 @@ * $FreeBSD$ */ +#include + #ifndef PROCSTAT_H #define PROCSTAT_H +#define PROCSTAT_XO_VERSION "1" + extern int hflag, nflag, Cflag, Hflag; struct kinfo_proc; diff --git a/usr.bin/procstat/procstat_args.c b/usr.bin/procstat/procstat_args.c index 342b60f57e5e..fd5f3d3b0738 100644 --- a/usr.bin/procstat/procstat_args.c +++ b/usr.bin/procstat/procstat_args.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2007 Robert N. M. Watson + * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,40 +41,56 @@ #include "procstat.h" -static void -do_args(struct procstat *procstat, struct kinfo_proc *kipp, int env) +void +procstat_args(struct procstat *procstat, struct kinfo_proc *kipp) { int i; char **args; if (!hflag) { - printf("%5s %-16s %-53s\n", "PID", "COMM", - env ? "ENVIRONMENT" : "ARGS"); + xo_emit("{T:/%5s %-16s %-53s}\n", "PID", "COMM", "ARGS"); } - args = env ? procstat_getenvv(procstat, kipp, 0) : - procstat_getargv(procstat, kipp, 0); + args = procstat_getargv(procstat, kipp, 0); - printf("%5d %-16s", kipp->ki_pid, kipp->ki_comm); + xo_emit("{k:process_id/%5d/%d} {:command/%-16s/%s}", kipp->ki_pid, + kipp->ki_comm); if (args == NULL) { - printf(" -\n"); + xo_emit(" {d:args/-}\n"); return; } + xo_open_list("arguments"); for (i = 0; args[i] != NULL; i++) - printf(" %s", args[i]); - printf("\n"); -} - -void -procstat_args(struct procstat *procstat, struct kinfo_proc *kipp) -{ - do_args(procstat, kipp, 0); + xo_emit(" {l:args/%s}", args[i]); + xo_close_list("arguments"); + xo_emit("\n"); } void procstat_env(struct procstat *procstat, struct kinfo_proc *kipp) { - do_args(procstat, kipp, 1); + int i; + char **envs; + + if (!hflag) { + xo_emit("{T:/%5s %-16s %-53s}\n", "PID", "COMM", "ENVIRONMENT"); + } + + envs = procstat_getenvv(procstat, kipp, 0); + + xo_emit("{k:process_id/%5d/%d} {:command/%-16s/%s}", kipp->ki_pid, + kipp->ki_comm); + + if (envs == NULL) { + xo_emit(" {d:env/-}\n"); + return; + } + + xo_open_list("environment"); + for (i = 0; envs[i] != NULL; i++) + xo_emit(" {l:env/%s}", envs[i]); + xo_close_list("environment"); + xo_emit("\n"); } diff --git a/usr.bin/procstat/procstat_auxv.c b/usr.bin/procstat/procstat_auxv.c index aa62594b7fba..3509e0d60e14 100644 --- a/usr.bin/procstat/procstat_auxv.c +++ b/usr.bin/procstat/procstat_auxv.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2011 Mikolaj Golub + * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,11 +44,6 @@ #include "procstat.h" -#define PRINT(name, spec, val) \ - printf("%s %-16s " #spec "\n", prefix, #name, (val)) -#define PRINT_UNKNOWN(type, val) \ - printf("%s %16ld %#lx\n", prefix, (long)type, (u_long)(val)) - void procstat_auxv(struct procstat *procstat, struct kinfo_proc *kipp) { @@ -56,12 +52,18 @@ procstat_auxv(struct procstat *procstat, struct kinfo_proc *kipp) static char prefix[256]; if (!hflag) - printf("%5s %-16s %-16s %-16s\n", "PID", "COMM", "AUXV", "VALUE"); + xo_emit("{T:/%5s %-16s %-16s %-16s}\n", "PID", "COMM", "AUXV", + "VALUE"); + auxv = procstat_getauxv(procstat, kipp, &count); if (auxv == NULL) return; - snprintf(prefix, sizeof(prefix), "%5d %-16s", kipp->ki_pid, + snprintf(prefix, sizeof(prefix), "%5d %-16s", kipp->ki_pid, + kipp->ki_comm); + + xo_emit("{e:process_id/%5d/%d}{e:command/%-16s/%s}", kipp->ki_pid, kipp->ki_comm); + for (i = 0; i < count; i++) { switch(auxv[i].a_type) { case AT_NULL: @@ -69,92 +71,119 @@ procstat_auxv(struct procstat *procstat, struct kinfo_proc *kipp) case AT_IGNORE: break; case AT_EXECFD: - PRINT(AT_EXECFD, %ld, (long)auxv[i].a_un.a_val); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_EXECFD/%ld}\n", + prefix, "AT_EXECFD", (long)auxv[i].a_un.a_val); break; case AT_PHDR: - PRINT(AT_PHDR, %p, auxv[i].a_un.a_ptr); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_PHDR/%p}\n", + prefix, "AT_PHDR", auxv[i].a_un.a_ptr); break; case AT_PHENT: - PRINT(AT_PHENT, %ld, (long)auxv[i].a_un.a_val); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_PHENT/%ld}\n", + prefix, "AT_PHENT", (long)auxv[i].a_un.a_val); break; case AT_PHNUM: - PRINT(AT_PHNUM, %ld, (long)auxv[i].a_un.a_val); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_PHNUM/%ld}\n", + prefix, "AT_PHNUM", (long)auxv[i].a_un.a_val); break; case AT_PAGESZ: - PRINT(AT_PAGESZ, %ld, (long)auxv[i].a_un.a_val); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_PAGESZ/%ld}\n", + prefix, "AT_PAGESZ", (long)auxv[i].a_un.a_val); break; case AT_BASE: - PRINT(AT_BASE, %p, auxv[i].a_un.a_ptr); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_BASE/%p}\n", + prefix, "AT_BASE", auxv[i].a_un.a_ptr); break; case AT_FLAGS: - PRINT(AT_FLAGS, %#lx, (u_long)auxv[i].a_un.a_val); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_FLAGS/%#lx}\n", + prefix, "AT_FLAGS", (u_long)auxv[i].a_un.a_val); break; case AT_ENTRY: - PRINT(AT_ENTRY, %p, auxv[i].a_un.a_ptr); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_ENTRY/%p}\n", + prefix, "AT_ENTRY", auxv[i].a_un.a_ptr); break; #ifdef AT_NOTELF case AT_NOTELF: - PRINT(AT_NOTELF, %ld, (long)auxv[i].a_un.a_val); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_NOTELF/%ld}\n", + prefix, "AT_NOTELF", (long)auxv[i].a_un.a_val); break; #endif #ifdef AT_UID case AT_UID: - PRINT(AT_UID, %ld, (long)auxv[i].a_un.a_val); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_UID/%ld}\n", + prefix, "AT_UID", (long)auxv[i].a_un.a_val); break; #endif #ifdef AT_EUID case AT_EUID: - PRINT(AT_EUID, %ld, (long)auxv[i].a_un.a_val); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_EUID/%ld}\n", + prefix, "AT_EUID", (long)auxv[i].a_un.a_val); break; #endif #ifdef AT_GID case AT_GID: - PRINT(AT_GID, %ld, (long)auxv[i].a_un.a_val); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_GID/%ld}\n", + prefix, "AT_GID", (long)auxv[i].a_un.a_val); break; #endif #ifdef AT_EGID case AT_EGID: - PRINT(AT_EGID, %ld, (long)auxv[i].a_un.a_val); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_EGID/%ld}\n", + prefix, "AT_EGID", (long)auxv[i].a_un.a_val); break; #endif case AT_EXECPATH: - PRINT(AT_EXECPATH, %p, auxv[i].a_un.a_ptr); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_EXECPATH/%p}\n", + prefix, "AT_EXECPATH", auxv[i].a_un.a_ptr); break; case AT_CANARY: - PRINT(AT_CANARY, %p, auxv[i].a_un.a_ptr); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_CANARY/%p}\n", + prefix, "AT_CANARY", auxv[i].a_un.a_ptr); break; case AT_CANARYLEN: - PRINT(AT_CANARYLEN, %ld, (long)auxv[i].a_un.a_val); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_CANARYLEN/%ld}\n", + prefix, "AT_CANARYLEN", (long)auxv[i].a_un.a_val); break; case AT_OSRELDATE: - PRINT(AT_OSRELDATE, %ld, (long)auxv[i].a_un.a_val); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_OSRELDATE/%ld}\n", + prefix, "AT_OSRELDATE", (long)auxv[i].a_un.a_val); break; case AT_NCPUS: - PRINT(AT_NCPUS, %ld, (long)auxv[i].a_un.a_val); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_NCPUS/%ld}\n", + prefix, "AT_NCPUS", (long)auxv[i].a_un.a_val); break; case AT_PAGESIZES: - PRINT(AT_PAGESIZES, %p, auxv[i].a_un.a_ptr); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_PAGESIZES/%p}\n", + prefix, "AT_PAGESIZES", auxv[i].a_un.a_ptr); break; case AT_PAGESIZESLEN: - PRINT(AT_PAGESIZESLEN, %ld, (long)auxv[i].a_un.a_val); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}" + "{:AT_PAGESIZESLEN/%ld}\n", prefix, + "AT_PAGESIZESLEN", (long)auxv[i].a_un.a_val); break; case AT_STACKPROT: if ((auxv[i].a_un.a_val & VM_PROT_EXECUTE) != 0) - PRINT(AT_STACKPROT, %s, "NONEXECUTABLE"); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}" + "{:AT_STACKPROT/%s}\n", prefix, + "AT_STACKPROT", "NONEXECUTABLE"); else - PRINT(AT_STACKPROT, %s, "EXECUTABLE"); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}" + "{:AT_STACKPROT/%s}\n", prefix, + "AT_STACKPROT", "EXECUTABLE"); break; #ifdef AT_TIMEKEEP case AT_TIMEKEEP: - PRINT(AT_TIMEKEEP, %p, auxv[i].a_un.a_ptr); + xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_TIMEKEEP/%p}\n", + prefix, "AT_TIMEKEEP", auxv[i].a_un.a_ptr); break; #endif default: - PRINT_UNKNOWN(auxv[i].a_type, auxv[i].a_un.a_val); + xo_emit("{dw:/%s}{Lw:/%16ld/%ld}{:UNKNOWN/%#lx}\n", + prefix, auxv[i].a_type, auxv[i].a_un.a_val); break; } } - printf("\n"); + xo_emit("\n"); procstat_freeauxv(procstat, auxv); } diff --git a/usr.bin/procstat/procstat_basic.c b/usr.bin/procstat/procstat_basic.c index af43fd1329e2..75bb7a8d9ef1 100644 --- a/usr.bin/procstat/procstat_basic.c +++ b/usr.bin/procstat/procstat_basic.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2007 Robert N. M. Watson + * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,24 +43,26 @@ procstat_basic(struct kinfo_proc *kipp) { if (!hflag) - printf("%5s %5s %5s %5s %5s %3s %-8s %-9s %-13s %-12s\n", + xo_emit("{T:/%5s %5s %5s %5s %5s %3s %-8s %-9s %-13s %-12s}\n", "PID", "PPID", "PGID", "SID", "TSID", "THR", "LOGIN", "WCHAN", "EMUL", "COMM"); - printf("%5d ", kipp->ki_pid); - printf("%5d ", kipp->ki_ppid); - printf("%5d ", kipp->ki_pgid); - printf("%5d ", kipp->ki_sid); - printf("%5d ", kipp->ki_tsid); - printf("%3d ", kipp->ki_numthreads); - printf("%-8s ", strlen(kipp->ki_login) ? kipp->ki_login : "-"); + xo_emit("{k:process_id/%5d/%d} ", kipp->ki_pid); + xo_emit("{:parent_process_id/%5d/%d} ", kipp->ki_ppid); + xo_emit("{:process_group_id/%5d/%d} ", kipp->ki_pgid); + xo_emit("{:session_id/%5d/%d} ", kipp->ki_sid); + xo_emit("{:terminal_session_id/%5d/%d} ", kipp->ki_tsid); + xo_emit("{:threads/%3d/%d} ", kipp->ki_numthreads); + xo_emit("{:login/%-8s/%s} ", strlen(kipp->ki_login) ? + kipp->ki_login : "-"); if (kipp->ki_kiflag & KI_LOCKBLOCK) { - printf("*%-8s ", strlen(kipp->ki_lockname) ? + xo_emit("{:lockname/*%-8s/%s} ", strlen(kipp->ki_lockname) ? kipp->ki_lockname : "-"); } else { - printf("%-9s ", strlen(kipp->ki_wmesg) ? + xo_emit("{:wait_channel/%-9s/%s} ", strlen(kipp->ki_wmesg) ? kipp->ki_wmesg : "-"); } - printf("%-13s ", strcmp(kipp->ki_emul, "null") ? kipp->ki_emul : "-"); - printf("%-12s\n", kipp->ki_comm); + xo_emit("{:emulation/%-13s/%s} ", strcmp(kipp->ki_emul, "null") ? + kipp->ki_emul : "-"); + xo_emit("{:command/%-12s/%s}\n", kipp->ki_comm); } diff --git a/usr.bin/procstat/procstat_bin.c b/usr.bin/procstat/procstat_bin.c index dc88c38c5124..8b2b8a14be8b 100644 --- a/usr.bin/procstat/procstat_bin.c +++ b/usr.bin/procstat/procstat_bin.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2007 Robert N. M. Watson + * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,7 +47,8 @@ procstat_bin(struct procstat *prstat, struct kinfo_proc *kipp) static char pathname[PATH_MAX]; if (!hflag) - printf("%5s %-16s %8s %s\n", "PID", "COMM", "OSREL", "PATH"); + xo_emit("{T:/%5s %-16s %8s %s}\n", "PID", "COMM", "OSREL", + "PATH"); if (procstat_getpathname(prstat, kipp, pathname, sizeof(pathname)) != 0) return; @@ -55,8 +57,8 @@ procstat_bin(struct procstat *prstat, struct kinfo_proc *kipp) if (procstat_getosrel(prstat, kipp, &osrel) != 0) return; - printf("%5d ", kipp->ki_pid); - printf("%-16s ", kipp->ki_comm); - printf("%8d ", osrel); - printf("%s\n", pathname); + xo_emit("{k:process_id/%5d/%d} ", kipp->ki_pid); + xo_emit("{:command/%-16s/%s} ", kipp->ki_comm); + xo_emit("{:osrel/%8d/%d} ", osrel); + xo_emit("{:pathname/%s}\n", pathname); } diff --git a/usr.bin/procstat/procstat_cred.c b/usr.bin/procstat/procstat_cred.c index f9a22412fcbf..940c952a8324 100644 --- a/usr.bin/procstat/procstat_cred.c +++ b/usr.bin/procstat/procstat_cred.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2007-2008 Robert N. M. Watson + * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,21 +49,22 @@ procstat_cred(struct procstat *procstat, struct kinfo_proc *kipp) gid_t *groups; if (!hflag) - printf("%5s %-16s %5s %5s %5s %5s %5s %5s %5s %5s %-15s\n", + xo_emit("{T:/%5s %-16s %5s %5s %5s %5s %5s %5s %5s %5s %-15s}\n", "PID", "COMM", "EUID", "RUID", "SVUID", "EGID", "RGID", "SVGID", "UMASK", "FLAGS", "GROUPS"); - printf("%5d ", kipp->ki_pid); - printf("%-16s ", kipp->ki_comm); - printf("%5d ", kipp->ki_uid); - printf("%5d ", kipp->ki_ruid); - printf("%5d ", kipp->ki_svuid); - printf("%5d ", kipp->ki_groups[0]); - printf("%5d ", kipp->ki_rgid); - printf("%5d ", kipp->ki_svgid); - printf("%5s ", get_umask(procstat, kipp)); - printf("%s", kipp->ki_cr_flags & CRED_FLAG_CAPMODE ? "C" : "-"); - printf(" "); + xo_emit("{k:process_id/%5d/%d} ", kipp->ki_pid); + xo_emit("{:command/%-16s/%s} ", kipp->ki_comm); + xo_emit("{:uid/%5d} ", kipp->ki_uid); + xo_emit("{:ruid/%5d} ", kipp->ki_ruid); + xo_emit("{:svuid/%5d} ", kipp->ki_svuid); + xo_emit("{:group/%5d} ", kipp->ki_groups[0]); + xo_emit("{:rgid/%5d} ", kipp->ki_rgid); + xo_emit("{:svgid/%5d} ", kipp->ki_svgid); + xo_emit("{:umask/%5s} ", get_umask(procstat, kipp)); + xo_emit("{:cr_flags/%s}", kipp->ki_cr_flags & CRED_FLAG_CAPMODE ? + "C" : "-"); + xo_emit("{P: }"); groups = NULL; /* @@ -76,12 +78,14 @@ procstat_cred(struct procstat *procstat, struct kinfo_proc *kipp) ngroups = kipp->ki_ngroups; groups = kipp->ki_groups; } + xo_open_list("groups"); for (i = 0; i < ngroups; i++) - printf("%s%d", (i > 0) ? "," : "", groups[i]); + xo_emit("{D:/%s}{l:groups/%d}", (i > 0) ? "," : "", groups[i]); if (groups != kipp->ki_groups) procstat_freegroups(procstat, groups); - printf("\n"); + xo_close_list("groups"); + xo_emit("\n"); } static const char * diff --git a/usr.bin/procstat/procstat_cs.c b/usr.bin/procstat/procstat_cs.c index 8ccf1ea82227..bbf9d05eec4e 100644 --- a/usr.bin/procstat/procstat_cs.c +++ b/usr.bin/procstat/procstat_cs.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2007 Robert N. M. Watson + * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,6 +29,7 @@ #include #include +#include #include #include @@ -46,11 +48,12 @@ procstat_cs(struct procstat *procstat, struct kinfo_proc *kipp) cpusetid_t cs; cpuset_t mask; struct kinfo_proc *kip; + struct sbuf *cpusetbuf; unsigned int count, i; int once, twice, lastcpu, cpu; if (!hflag) - printf("%5s %6s %-16s %-16s %2s %4s %-7s\n", "PID", + xo_emit("{T:/%5s %6s %-16s %-16s %2s %4s %-7s}\n", "PID", "TID", "COMM", "TDNAME", "CPU", "CSID", "CPU MASK"); kip = procstat_getprocs(procstat, KERN_PROC_PID | KERN_PROC_INC_THREAD, @@ -60,49 +63,57 @@ procstat_cs(struct procstat *procstat, struct kinfo_proc *kipp) kinfo_proc_sort(kip, count); for (i = 0; i < count; i++) { kipp = &kip[i]; - printf("%5d ", kipp->ki_pid); - printf("%6d ", kipp->ki_tid); - printf("%-16s ", strlen(kipp->ki_comm) ? + xo_emit("{k:process_id/%5d/%d} ", kipp->ki_pid); + xo_emit("{:thread_id/%6d/%d} ", kipp->ki_tid); + xo_emit("{:command/%-16s/%s} ", strlen(kipp->ki_comm) ? kipp->ki_comm : "-"); - printf("%-16s ", (strlen(kipp->ki_tdname) && + xo_emit("{:thread_name/%-16s/%s} ", (strlen(kipp->ki_tdname) && (strcmp(kipp->ki_comm, kipp->ki_tdname) != 0)) ? kipp->ki_tdname : "-"); if (kipp->ki_oncpu != 255) - printf("%3d ", kipp->ki_oncpu); + xo_emit("{:cpu/%3d/%d} ", kipp->ki_oncpu); else if (kipp->ki_lastcpu != 255) - printf("%3d ", kipp->ki_lastcpu); + xo_emit("{:cpu/%3d/%d} ", kipp->ki_lastcpu); else - printf("%3s ", "-"); + xo_emit("{:cpu/%3s/%s} ", "-"); if (cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_TID, kipp->ki_tid, &cs) != 0) { cs = CPUSET_INVALID; } - printf("%4d ", cs); + xo_emit("{:cpu_set_id/%4d/%d} ", cs); if ((cs != CPUSET_INVALID) && (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, kipp->ki_tid, sizeof(mask), &mask) == 0)) { lastcpu = -1; once = 0; twice = 0; + cpusetbuf = sbuf_new_auto(); for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { if (CPU_ISSET(cpu, &mask)) { if (once == 0) { - printf("%d", cpu); + sbuf_printf(cpusetbuf, "%d", + cpu); once = 1; } else if (cpu == lastcpu + 1) { twice = 1; } else if (twice == 1) { - printf("-%d,%d", lastcpu, cpu); + sbuf_printf(cpusetbuf, "-%d,%d", + lastcpu, cpu); twice = 0; } else - printf(",%d", cpu); + sbuf_printf(cpusetbuf, ",%d", + cpu); lastcpu = cpu; } } if (once && twice) - printf("-%d", lastcpu); + sbuf_printf(cpusetbuf, "-%d", lastcpu); + if (sbuf_finish(cpusetbuf) != 0) + xo_err(1, "Could not generate output"); + xo_emit("{:cpu_set/%s}", sbuf_data(cpusetbuf)); + sbuf_delete(cpusetbuf); } - printf("\n"); + xo_emit("\n"); } procstat_freeprocs(procstat, kip); } diff --git a/usr.bin/procstat/procstat_files.c b/usr.bin/procstat/procstat_files.c index 8c560b65dc0f..ae7928dece7d 100644 --- a/usr.bin/procstat/procstat_files.c +++ b/usr.bin/procstat/procstat_files.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2007-2011 Robert N. M. Watson + * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -123,15 +124,6 @@ addr_to_string(struct sockaddr_storage *ss, char *buffer, int buflen) } } -static void -print_address(struct sockaddr_storage *ss) -{ - char addr[PATH_MAX]; - - addr_to_string(ss, addr, sizeof(addr)); - printf("%s", addr); -} - static struct cap_desc { uint64_t cd_right; const char *cd_desc; @@ -273,19 +265,22 @@ print_capability(cap_rights_t *rightsp, u_int capwidth) width = 0; for (i = width_capability(rightsp); i < capwidth; i++) { if (i != 0) - printf(" "); + xo_emit(" "); else - printf("-"); + xo_emit("-"); } + xo_open_list("capabilities"); for (i = 0; i < cap_desc_count; i++) { if (cap_rights_is_set(rightsp, cap_desc[i].cd_right)) { - printf("%s%s", count ? "," : "", cap_desc[i].cd_desc); + xo_emit("{D:/%s}{l:capabilities/%s}", count ? "," : "", + cap_desc[i].cd_desc); width += strlen(cap_desc[i].cd_desc); if (count) width++; count++; } } + xo_close_list("capabilities"); } void @@ -298,6 +293,8 @@ procstat_files(struct procstat *procstat, struct kinfo_proc *kipp) struct vnstat vn; u_int capwidth, width; int error; + char src_addr[PATH_MAX]; + char dst_addr[PATH_MAX]; /* * To print the header in capability mode, we need to know the width @@ -319,84 +316,103 @@ procstat_files(struct procstat *procstat, struct kinfo_proc *kipp) if (!hflag) { if (Cflag) - printf("%5s %-16s %5s %1s %-8s %-*s " - "%-3s %-12s\n", "PID", "COMM", "FD", "T", + xo_emit("{T:/%5s %-16s %5s %1s %-8s %-*s " + "%-3s %-12s}\n", "PID", "COMM", "FD", "T", "FLAGS", capwidth, "CAPABILITIES", "PRO", "NAME"); else - printf("%5s %-16s %5s %1s %1s %-8s " - "%3s %7s %-3s %-12s\n", "PID", "COMM", "FD", "T", + xo_emit("{T:/%5s %-16s %5s %1s %1s %-8s " + "%3s %7s %-3s %-12s}\n", "PID", "COMM", "FD", "T", "V", "FLAGS", "REF", "OFFSET", "PRO", "NAME"); } if (head == NULL) return; + xo_emit("{ek:process_id/%5d/%d}", kipp->ki_pid); + xo_emit("{e:command/%-16s/%s}", kipp->ki_comm); + xo_open_list("files"); STAILQ_FOREACH(fst, head, next) { - printf("%5d ", kipp->ki_pid); - printf("%-16s ", kipp->ki_comm); + xo_open_instance("files"); + xo_emit("{dk:process_id/%5d/%d} ", kipp->ki_pid); + xo_emit("{d:command/%-16s/%s} ", kipp->ki_comm); if (fst->fs_uflags & PS_FST_UFLAG_CTTY) - printf(" ctty "); + xo_emit("{P: }{:fd/%s} ", "ctty"); else if (fst->fs_uflags & PS_FST_UFLAG_CDIR) - printf(" cwd "); + xo_emit("{P: }{:fd/%s} ", "cwd"); else if (fst->fs_uflags & PS_FST_UFLAG_JAIL) - printf(" jail "); + xo_emit("{P: }{:fd/%s} ", "jail"); else if (fst->fs_uflags & PS_FST_UFLAG_RDIR) - printf(" root "); + xo_emit("{P: }{:fd/%s} ", "root"); else if (fst->fs_uflags & PS_FST_UFLAG_TEXT) - printf(" text "); + xo_emit("{P: }{:fd/%s} ", "text"); else if (fst->fs_uflags & PS_FST_UFLAG_TRACE) - printf("trace "); + xo_emit("{:fd/%s} ", "trace"); else - printf("%5d ", fst->fs_fd); + xo_emit("{:fd/%5d} ", fst->fs_fd); switch (fst->fs_type) { case PS_FST_TYPE_VNODE: str = "v"; + xo_emit("{eq:fd_type/vnode}"); break; case PS_FST_TYPE_SOCKET: str = "s"; + xo_emit("{eq:fd_type/socket}"); break; case PS_FST_TYPE_PIPE: str = "p"; + xo_emit("{eq:fd_type/pipe}"); break; case PS_FST_TYPE_FIFO: str = "f"; + xo_emit("{eq:fd_type/fifo}"); break; case PS_FST_TYPE_KQUEUE: str = "k"; + xo_emit("{eq:fd_type/kqueue}"); break; case PS_FST_TYPE_CRYPTO: str = "c"; + xo_emit("{eq:fd_type/crypto}"); break; case PS_FST_TYPE_MQUEUE: str = "m"; + xo_emit("{eq:fd_type/mqueue}"); break; case PS_FST_TYPE_SHM: str = "h"; + xo_emit("{eq:fd_type/shm}"); break; case PS_FST_TYPE_PTS: str = "t"; + xo_emit("{eq:fd_type/pts}"); break; case PS_FST_TYPE_SEM: str = "e"; + xo_emit("{eq:fd_type/sem}"); break; case PS_FST_TYPE_NONE: + str = "?"; + xo_emit("{eq:fd_type/none}"); + break; + case PS_FST_TYPE_UNKNOWN: default: str = "?"; + xo_emit("{eq:fd_type/unknown}"); break; } - printf("%1s ", str); + xo_emit("{d:fd_type/%1s/%s} ", str); if (!Cflag) { str = "-"; if (fst->fs_type == PS_FST_TYPE_VNODE) { @@ -405,74 +421,118 @@ procstat_files(struct procstat *procstat, struct kinfo_proc *kipp) switch (vn.vn_type) { case PS_FST_VTYPE_VREG: str = "r"; + xo_emit("{eq:vode_type/regular}"); break; case PS_FST_VTYPE_VDIR: str = "d"; + xo_emit("{eq:vode_type/directory}"); break; case PS_FST_VTYPE_VBLK: str = "b"; + xo_emit("{eq:vode_type/block}"); break; case PS_FST_VTYPE_VCHR: str = "c"; + xo_emit("{eq:vode_type/character}"); break; case PS_FST_VTYPE_VLNK: str = "l"; + xo_emit("{eq:vode_type/link}"); break; case PS_FST_VTYPE_VSOCK: str = "s"; + xo_emit("{eq:vode_type/socket}"); break; case PS_FST_VTYPE_VFIFO: str = "f"; + xo_emit("{eq:vode_type/fifo}"); break; case PS_FST_VTYPE_VBAD: str = "x"; + xo_emit("{eq:vode_type/revoked_device}"); break; case PS_FST_VTYPE_VNON: + str = "?"; + xo_emit("{eq:vode_type/non}"); + break; + case PS_FST_VTYPE_UNKNOWN: default: str = "?"; + xo_emit("{eq:vode_type/unknown}"); break; } } - printf("%1s ", str); + xo_emit("{d:vnode_type/%1s/%s} ", str); } - printf("%s", fst->fs_fflags & PS_FST_FFLAG_READ ? "r" : "-"); - printf("%s", fst->fs_fflags & PS_FST_FFLAG_WRITE ? "w" : "-"); - printf("%s", fst->fs_fflags & PS_FST_FFLAG_APPEND ? "a" : "-"); - printf("%s", fst->fs_fflags & PS_FST_FFLAG_ASYNC ? "s" : "-"); - printf("%s", fst->fs_fflags & PS_FST_FFLAG_SYNC ? "f" : "-"); - printf("%s", fst->fs_fflags & PS_FST_FFLAG_NONBLOCK ? "n" : "-"); - printf("%s", fst->fs_fflags & PS_FST_FFLAG_DIRECT ? "d" : "-"); - printf("%s", fst->fs_fflags & PS_FST_FFLAG_HASLOCK ? "l" : "-"); - printf(" "); + + xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_READ ? + "r" : "-"); + xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_WRITE ? + "w" : "-"); + xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_APPEND ? + "a" : "-"); + xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_ASYNC ? + "s" : "-"); + xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_SYNC ? + "f" : "-"); + xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_NONBLOCK ? + "n" : "-"); + xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_DIRECT ? + "d" : "-"); + xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_HASLOCK ? + "l" : "-"); + xo_emit(" "); + xo_open_list("fd_flags"); + if (fst->fs_fflags & PS_FST_FFLAG_READ) + xo_emit("{elq:fd_flags/read}"); + if (fst->fs_fflags & PS_FST_FFLAG_WRITE) + xo_emit("{elq:fd_flags/write}"); + if (fst->fs_fflags & PS_FST_FFLAG_APPEND) + xo_emit("{elq:fd_flags/append}"); + if (fst->fs_fflags & PS_FST_FFLAG_ASYNC) + xo_emit("{elq:fd_flags/async}"); + if (fst->fs_fflags & PS_FST_FFLAG_SYNC) + xo_emit("{elq:fd_flags/fsync}"); + if (fst->fs_fflags & PS_FST_FFLAG_NONBLOCK) + xo_emit("{elq:fd_flags/nonblocking}"); + if (fst->fs_fflags & PS_FST_FFLAG_DIRECT) + xo_emit("{elq:fd_flags/direct_io}"); + if (fst->fs_fflags & PS_FST_FFLAG_HASLOCK) + xo_emit("{elq:fd_flags/lock_held}"); + xo_close_list("fd_flags"); + if (!Cflag) { if (fst->fs_ref_count > -1) - printf("%3d ", fst->fs_ref_count); + xo_emit("{:ref_count/%3d/%d} ", + fst->fs_ref_count); else - printf("%3c ", '-'); + xo_emit("{q:ref_count/%3c/%c} ", '-'); if (fst->fs_offset > -1) - printf("%7jd ", (intmax_t)fst->fs_offset); + xo_emit("{:offset/%7jd/%jd} ", + (intmax_t)fst->fs_offset); else - printf("%7c ", '-'); + xo_emit("{q:offset/%7c/%c} ", '-'); } if (Cflag) { print_capability(&fst->fs_cap_rights, capwidth); - printf(" "); + xo_emit(" "); } switch (fst->fs_type) { case PS_FST_TYPE_SOCKET: - error = procstat_get_socket_info(procstat, fst, &sock, NULL); + error = procstat_get_socket_info(procstat, fst, &sock, + NULL); if (error != 0) break; - printf("%-3s ", + xo_emit("{:protocol/%-3s/%s} ", protocol_to_string(sock.dom_family, sock.type, sock.proto)); /* @@ -487,22 +547,30 @@ procstat_files(struct procstat *procstat, struct kinfo_proc *kipp) (struct sockaddr_un *)&sock.sa_local; if (sun->sun_path[0] != 0) - print_address(&sock.sa_local); + addr_to_string(&sock.sa_local, + src_addr, sizeof(src_addr)); else - print_address(&sock.sa_peer); + addr_to_string(&sock.sa_peer, + src_addr, sizeof(src_addr)); + xo_emit("{:path/%s}", src_addr); } else { - print_address(&sock.sa_local); - printf(" "); - print_address(&sock.sa_peer); + addr_to_string(&sock.sa_local, src_addr, + sizeof(src_addr)); + addr_to_string(&sock.sa_peer, dst_addr, + sizeof(dst_addr)); + xo_emit("{:path/%s %s}", src_addr, dst_addr); } break; default: - printf("%-3s ", "-"); - printf("%-18s", fst->fs_path != NULL ? fst->fs_path : "-"); + xo_emit("{:protocol/%-3s/%s} ", "-"); + xo_emit("{:path/%-18s/%s}", fst->fs_path != NULL ? + fst->fs_path : "-"); } - printf("\n"); + xo_emit("\n"); + xo_close_instance("files"); } + xo_close_list("files"); procstat_freefiles(procstat, head); } diff --git a/usr.bin/procstat/procstat_kstack.c b/usr.bin/procstat/procstat_kstack.c index 8ffa4f98a4e9..cf324475711c 100644 --- a/usr.bin/procstat/procstat_kstack.c +++ b/usr.bin/procstat/procstat_kstack.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2007 Robert N. M. Watson + * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -105,6 +106,42 @@ kstack_cleanup(const char *old, char *new, int kflag) *cp_new = '\0'; } +static void +kstack_cleanup_encoded(const char *old, char *new, int kflag) +{ + enum trace_state old_ts, ts; + const char *cp_old; + char *cp_new, *cp_loop, *cp_tofree, *cp_line; + + ts = TS_FRAMENUM; + if (kflag == 1) { + for (cp_old = old, cp_new = new; *cp_old != '\0'; cp_old++) { + switch (*cp_old) { + case '\n': + *cp_new = *cp_old; + cp_new++; + case ' ': + case '+': + old_ts = ts; + ts = kstack_nextstate(old_ts); + continue; + } + if (ts == TS_FUNC) { + *cp_new = *cp_old; + cp_new++; + } + } + cp_tofree = cp_loop = strdup(new); + } else + cp_tofree = cp_loop = strdup(old); + while ((cp_line = strsep(&cp_loop, "\n")) != NULL) { + if (strlen(cp_line) != 0 && *cp_line != 127) + xo_emit("{le:token/%s}", cp_line); + } + *cp_new = '\0'; + free(cp_tofree); +} + /* * Sort threads by tid. */ @@ -129,12 +166,12 @@ procstat_kstack(struct procstat *procstat, struct kinfo_proc *kipp, int kflag) { struct kinfo_kstack *kkstp, *kkstp_free; struct kinfo_proc *kip, *kip_free; - char trace[KKST_MAXLEN]; + char trace[KKST_MAXLEN], encoded_trace[KKST_MAXLEN]; unsigned int i, j; unsigned int kip_count, kstk_count; if (!hflag) - printf("%5s %6s %-16s %-16s %-29s\n", "PID", "TID", "COMM", + xo_emit("{T:/%5s %6s %-16s %-16s %-29s}\n", "PID", "TID", "COMM", "TDNAME", "KSTACK"); kkstp = kkstp_free = procstat_getkstack(procstat, kipp, &kstk_count); @@ -169,27 +206,27 @@ procstat_kstack(struct procstat *procstat, struct kinfo_proc *kipp, int kflag) if (kipp == NULL) continue; - printf("%5d ", kipp->ki_pid); - printf("%6d ", kkstp->kkst_tid); - printf("%-16s ", kipp->ki_comm); - printf("%-16s ", (strlen(kipp->ki_tdname) && + xo_emit("{k:process_id/%5d/%d} ", kipp->ki_pid); + xo_emit("{:thread_id/%6d/%d} ", kkstp->kkst_tid); + xo_emit("{:command/%-16s/%s} ", kipp->ki_comm); + xo_emit("{:thread_name/%-16s/%s} ", (strlen(kipp->ki_tdname) && (strcmp(kipp->ki_comm, kipp->ki_tdname) != 0)) ? kipp->ki_tdname : "-"); switch (kkstp->kkst_state) { case KKST_STATE_RUNNING: - printf("%-29s\n", ""); + xo_emit("{:state/%-29s/%s}\n", ""); continue; case KKST_STATE_SWAPPED: - printf("%-29s\n", ""); + xo_emit("{:state/%-29s/%s}\n", ""); continue; case KKST_STATE_STACKOK: break; default: - printf("%-29s\n", ""); + xo_emit("{:state/%-29s/%s}\n", ""); continue; } @@ -199,7 +236,10 @@ procstat_kstack(struct procstat *procstat, struct kinfo_proc *kipp, int kflag) * returns to spaces. */ kstack_cleanup(kkstp->kkst_trace, trace, kflag); - printf("%-29s\n", trace); + xo_open_list("trace"); + kstack_cleanup_encoded(kkstp->kkst_trace, encoded_trace, kflag); + xo_close_list("trace"); + xo_emit("{d:trace/%-29s}\n", trace); } procstat_freekstack(procstat, kkstp_free); procstat_freeprocs(procstat, kip_free); diff --git a/usr.bin/procstat/procstat_rlimit.c b/usr.bin/procstat/procstat_rlimit.c index f7f67af1e0ff..5e7d12efc55f 100644 --- a/usr.bin/procstat/procstat_rlimit.c +++ b/usr.bin/procstat/procstat_rlimit.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2011 Mikolaj Golub + * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -93,15 +94,33 @@ procstat_rlimit(struct procstat *prstat, struct kinfo_proc *kipp) int i; if (!hflag) { - printf("%5s %-16s %-16s %16s %16s\n", + xo_emit("{T:/%5s %-16s %-16s %16s %16s}\n", "PID", "COMM", "RLIMIT", "SOFT ", "HARD "); } + xo_emit("{ek:process_id/%5d}{e:command/%-16s/%s}", kipp->ki_pid, + kipp->ki_comm); for (i = 0; i < RLIM_NLIMITS; i++) { if (procstat_getrlimit(prstat, kipp, i, &rlimit) == -1) return; - printf("%5d %-16s %-16s ", kipp->ki_pid, kipp->ki_comm, + xo_emit("{dk:process_id/%5d} {d:command/%-16s} " + "{d:rlimit_param/%-16s} ", kipp->ki_pid, kipp->ki_comm, rlimit_param[i].name); - printf("%16s ", humanize_rlimit(i, rlimit.rlim_cur)); - printf("%16s\n", humanize_rlimit(i, rlimit.rlim_max)); + + xo_open_container(rlimit_param[i].name); + if (rlimit.rlim_cur == RLIM_INFINITY) + xo_emit("{e:soft_limit/infinity}"); + else + xo_emit("{e:soft_limit/%U}", rlimit.rlim_cur); + + if (rlimit.rlim_max == RLIM_INFINITY) + xo_emit("{e:hard_limit/infinity}"); + else + xo_emit("{e:hard_limit/%U}", rlimit.rlim_max); + xo_close_container(rlimit_param[i].name); + + xo_emit("{d:rlim_cur/%16s} ", + humanize_rlimit(i, rlimit.rlim_cur)); + xo_emit("{d:rlim_max/%16s}\n", + humanize_rlimit(i, rlimit.rlim_max)); } } diff --git a/usr.bin/procstat/procstat_rusage.c b/usr.bin/procstat/procstat_rusage.c index 63e5ab830a74..e14ae2470fef 100644 --- a/usr.bin/procstat/procstat_rusage.c +++ b/usr.bin/procstat/procstat_rusage.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2012 Hudson River Trading LLC * Written by: John H. Baldwin + * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include "procstat.h" @@ -79,7 +81,7 @@ format_time(struct timeval *tv) else if (days > 0) used += snprintf(buffer, sizeof(buffer), "%u days ", days); - snprintf(buffer + used, sizeof(buffer) - used, "%02u:%02u:%02u.%06u ", + snprintf(buffer + used, sizeof(buffer) - used, "%02u:%02u:%02u.%06u", hours, minutes, seconds, (unsigned int)tv->tv_usec); return (buffer); } @@ -103,10 +105,10 @@ static void print_prefix(struct kinfo_proc *kipp) { - printf("%5d ", kipp->ki_pid); + xo_emit("{d:process_id/%5d/%d} ", kipp->ki_pid); if (Hflag) - printf("%6d ", kipp->ki_tid); - printf("%-16s ", kipp->ki_comm); + xo_emit("{d:thread_id/%6d/%d} ", kipp->ki_tid); + xo_emit("{d:command/%-16s/%s} ", kipp->ki_comm); } static void @@ -114,21 +116,48 @@ print_rusage(struct kinfo_proc *kipp) { long *lp; unsigned int i; + char *field, *threadid; print_prefix(kipp); - printf("%-14s %32s\n", "user time", + xo_emit("{d:resource/%-14s} {d:usage/%29s}{P: }\n", "user time", format_time(&kipp->ki_rusage.ru_utime)); print_prefix(kipp); - printf("%-14s %32s\n", "system time", + xo_emit("{d:resource/%-14s} {d:usage/%29s}{P: }\n", "system time", format_time(&kipp->ki_rusage.ru_stime)); + + if (Hflag) { + asprintf(&threadid, "%d", kipp->ki_tid); + if (threadid == NULL) + xo_errc(1, ENOMEM, + "Failed to allocate memory in print_rusage()"); + xo_open_container(threadid); + xo_emit("{e:thread_id/%d}", kipp->ki_tid); + } else { + xo_emit("{e:process_id/%d}", kipp->ki_pid); + xo_emit("{e:command/%s}", kipp->ki_comm); + } + xo_emit("{e:user time/%s}", format_time(&kipp->ki_rusage.ru_utime)); + xo_emit("{e:system time/%s}", format_time(&kipp->ki_rusage.ru_stime)); + lp = &kipp->ki_rusage.ru_maxrss; for (i = 0; i < nitems(rusage_info); i++) { print_prefix(kipp); - printf("%-32s %14s\n", rusage_info[i].ri_name, + asprintf(&field, "{e:%s/%%D}", rusage_info[i].ri_name); + if (field == NULL) + xo_errc(1, ENOMEM, + "Failed to allocate memory in print_rusage()"); + xo_emit(field, *lp); + free(field); + xo_emit("{d:resource/%-32s} {d:usage/%14s}\n", + rusage_info[i].ri_name, format_value(*lp, rusage_info[i].ri_humanize, - rusage_info[i].ri_scale)); + rusage_info[i].ri_scale)); lp++; } + if (Hflag) { + xo_close_container(threadid); + free(threadid); + } } void @@ -138,10 +167,10 @@ procstat_rusage(struct procstat *procstat, struct kinfo_proc *kipp) unsigned int count, i; if (!hflag) { - printf("%5s ", "PID"); + xo_emit("{d:ta/%5s} ", "PID"); if (Hflag) - printf("%6s ", "TID"); - printf("%-16s %-32s %14s\n", "COMM", "RESOURCE", + xo_emit("{d:tb/%6s} ", "TID"); + xo_emit("{d:tc/%-16s %-32s %14s}\n", "COMM", "RESOURCE", "VALUE "); } @@ -150,12 +179,19 @@ procstat_rusage(struct procstat *procstat, struct kinfo_proc *kipp) return; } + xo_emit("{e:process_id/%d}", kipp->ki_pid); + xo_emit("{e:command/%s}", kipp->ki_comm); + xo_open_container("threads"); + kip = procstat_getprocs(procstat, KERN_PROC_PID | KERN_PROC_INC_THREAD, kipp->ki_pid, &count); if (kip == NULL) return; kinfo_proc_sort(kip, count); - for (i = 0; i < count; i++) + for (i = 0; i < count; i++) { print_rusage(&kip[i]); + } + + xo_close_container("threads"); procstat_freeprocs(procstat, kip); } diff --git a/usr.bin/procstat/procstat_sigs.c b/usr.bin/procstat/procstat_sigs.c index 49e2b196e5c9..7bc73ec43471 100644 --- a/usr.bin/procstat/procstat_sigs.c +++ b/usr.bin/procstat/procstat_sigs.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2010 Konstantin Belousov + * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -51,70 +52,129 @@ procstat_print_signame(int sig) strlcpy(name, sys_signame[sig], sizeof(name)); for (i = 0; name[i] != 0; i++) name[i] = toupper(name[i]); - printf("%-7s ", name); + xo_emit("{d:signal/%-7s/%s} ", name); + xo_open_container(name); + } else { + xo_emit("{d:signal/%-7d/%d} ", sig); + snprintf(name, 12, "%d", sig); + xo_open_container(name); + } +} + +static void +procstat_close_signame(int sig) +{ + char name[12]; + int i; + + if (!nflag && sig < sys_nsig) { + strlcpy(name, sys_signame[sig], sizeof(name)); + for (i = 0; name[i] != 0; i++) + name[i] = toupper(name[i]); + xo_close_container(name); } else - printf("%-7d ", sig); + snprintf(name, 12, "%d", sig); + xo_close_container(name); } static void procstat_print_sig(const sigset_t *set, int sig, char flag) { - - printf("%c", sigismember(set, sig) ? flag : '-'); + xo_emit("{d:sigmember/%c}", sigismember(set, sig) ? flag : '-'); + switch (flag) { + case 'B': + xo_emit("{en:mask/%s}", sigismember(set, sig) ? + "true" : "false"); + break; + case 'C': + xo_emit("{en:catch/%s}", sigismember(set, sig) ? + "true" : "false"); + break; + case 'P': + xo_emit("{en:list/%s}", sigismember(set, sig) ? + "true" : "false"); + break; + case 'I': + xo_emit("{en:ignore/%s}", sigismember(set, sig) ? + "true" : "false"); + break; + default: + xo_emit("{en:unknown/%s}", sigismember(set, sig) ? + "true" : "false"); + break; + } } void procstat_sigs(struct procstat *prstat __unused, struct kinfo_proc *kipp) { int j; - pid_t pid; - pid = kipp->ki_pid; if (!hflag) - printf("%5s %-16s %-7s %4s\n", "PID", "COMM", "SIG", "FLAGS"); + xo_emit("{T:/%5s %-16s %-7s %4s}\n", "PID", "COMM", "SIG", + "FLAGS"); + xo_emit("{ek:process_id/%5d/%d}", kipp->ki_pid); + xo_emit("{e:command/%-16s/%s}", kipp->ki_comm); + xo_open_container("signals"); for (j = 1; j <= _SIG_MAXSIG; j++) { - printf("%5d ", pid); - printf("%-16s ", kipp->ki_comm); + xo_emit("{dk:process_id/%5d/%d} ", kipp->ki_pid); + xo_emit("{d:command/%-16s/%s} ", kipp->ki_comm); procstat_print_signame(j); - printf(" "); + xo_emit(" "); procstat_print_sig(&kipp->ki_siglist, j, 'P'); procstat_print_sig(&kipp->ki_sigignore, j, 'I'); procstat_print_sig(&kipp->ki_sigcatch, j, 'C'); - printf("\n"); + procstat_close_signame(j); + xo_emit("\n"); } + xo_close_container("signals"); } void procstat_threads_sigs(struct procstat *procstat, struct kinfo_proc *kipp) { struct kinfo_proc *kip; - pid_t pid; int j; unsigned int count, i; + char *threadid; - pid = kipp->ki_pid; if (!hflag) - printf("%5s %6s %-16s %-7s %4s\n", "PID", "TID", "COMM", + xo_emit("{T:/%5s %6s %-16s %-7s %4s}\n", "PID", "TID", "COMM", "SIG", "FLAGS"); kip = procstat_getprocs(procstat, KERN_PROC_PID | KERN_PROC_INC_THREAD, - pid, &count); + kipp->ki_pid, &count); if (kip == NULL) return; + xo_emit("{ek:process_id/%5d/%d}", kipp->ki_pid); + xo_emit("{e:command/%-16s/%s}", kipp->ki_comm); + xo_open_container("threads"); kinfo_proc_sort(kip, count); for (i = 0; i < count; i++) { kipp = &kip[i]; + asprintf(&threadid, "%d", kipp->ki_tid); + if (threadid == NULL) + xo_errc(1, ENOMEM, "Failed to allocate memory in " + "procstat_threads_sigs()"); + xo_open_container(threadid); + xo_emit("{e:thread_id/%6d/%d}", kipp->ki_tid); + xo_open_container("signals"); for (j = 1; j <= _SIG_MAXSIG; j++) { - printf("%5d ", pid); - printf("%6d ", kipp->ki_tid); - printf("%-16s ", kipp->ki_comm); + xo_emit("{dk:process_id/%5d/%d} ", kipp->ki_pid); + xo_emit("{d:thread_id/%6d/%d} ", kipp->ki_tid); + xo_emit("{d:command/%-16s/%s} ", kipp->ki_comm); procstat_print_signame(j); - printf(" "); + xo_emit(" "); procstat_print_sig(&kipp->ki_siglist, j, 'P'); procstat_print_sig(&kipp->ki_sigmask, j, 'B'); - printf("\n"); + procstat_close_signame(j); + xo_emit("\n"); } + xo_close_container("signals"); + xo_close_container(threadid); + free(threadid); } + xo_close_container("threads"); procstat_freeprocs(procstat, kip); } diff --git a/usr.bin/procstat/procstat_threads.c b/usr.bin/procstat/procstat_threads.c index 6bd88da508e3..aa9f9b5c0015 100644 --- a/usr.bin/procstat/procstat_threads.c +++ b/usr.bin/procstat/procstat_threads.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2007 Robert N. M. Watson + * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,11 +46,17 @@ procstat_threads(struct procstat *procstat, struct kinfo_proc *kipp) struct kinfo_proc *kip; unsigned int count, i; const char *str; + char *threadid; if (!hflag) - printf("%5s %6s %-16s %-16s %2s %4s %-7s %-9s\n", "PID", + xo_emit("{T:/%5s %6s %-16s %-16s %2s %4s %-7s %-9s}\n", "PID", "TID", "COMM", "TDNAME", "CPU", "PRI", "STATE", "WCHAN"); + xo_emit("{ek:process_id/%d}", kipp->ki_pid); + xo_emit("{e:command/%s}", strlen(kipp->ki_comm) ? + kipp->ki_comm : "-"); + xo_open_container("threads"); + kip = procstat_getprocs(procstat, KERN_PROC_PID | KERN_PROC_INC_THREAD, kipp->ki_pid, &count); if (kip == NULL) @@ -57,20 +64,25 @@ procstat_threads(struct procstat *procstat, struct kinfo_proc *kipp) kinfo_proc_sort(kip, count); for (i = 0; i < count; i++) { kipp = &kip[i]; - printf("%5d ", kipp->ki_pid); - printf("%6d ", kipp->ki_tid); - printf("%-16s ", strlen(kipp->ki_comm) ? + asprintf(&threadid, "%d", kipp->ki_tid); + if (threadid == NULL) + xo_errc(1, ENOMEM, "Failed to allocate memory in " + "procstat_threads()"); + xo_open_container(threadid); + xo_emit("{dk:process_id/%5d/%d} ", kipp->ki_pid); + xo_emit("{:thread_id/%6d/%d} ", kipp->ki_tid); + xo_emit("{d:command/%-16s/%s} ", strlen(kipp->ki_comm) ? kipp->ki_comm : "-"); - printf("%-16s ", (strlen(kipp->ki_tdname) && + xo_emit("{:thread_name/%-16s/%s} ", (strlen(kipp->ki_tdname) && (strcmp(kipp->ki_comm, kipp->ki_tdname) != 0)) ? kipp->ki_tdname : "-"); if (kipp->ki_oncpu != 255) - printf("%3d ", kipp->ki_oncpu); + xo_emit("{:cpu/%3d/%d} ", kipp->ki_oncpu); else if (kipp->ki_lastcpu != 255) - printf("%3d ", kipp->ki_lastcpu); + xo_emit("{:cpu/%3d/%d} ", kipp->ki_lastcpu); else - printf("%3s ", "-"); - printf("%4d ", kipp->ki_pri.pri_level); + xo_emit("{:cpu/%3s/%s} ", "-"); + xo_emit("{:priority/%4d/%d} ", kipp->ki_pri.pri_level); switch (kipp->ki_stat) { case SRUN: str = "run"; @@ -104,15 +116,19 @@ procstat_threads(struct procstat *procstat, struct kinfo_proc *kipp) str = "??"; break; } - printf("%-7s ", str); + xo_emit("{:run_state/%-7s/%s} ", str); if (kipp->ki_kiflag & KI_LOCKBLOCK) { - printf("*%-8s ", strlen(kipp->ki_lockname) ? + xo_emit("{:lock_name/*%-8s/%s} ", + strlen(kipp->ki_lockname) ? kipp->ki_lockname : "-"); } else { - printf("%-9s ", strlen(kipp->ki_wmesg) ? - kipp->ki_wmesg : "-"); + xo_emit("{:wait_channel/%-9s/%s} ", + strlen(kipp->ki_wmesg) ? kipp->ki_wmesg : "-"); } - printf("\n"); + xo_close_container(threadid); + free(threadid); + xo_emit("\n"); } + xo_close_container("threads"); procstat_freeprocs(procstat, kip); } diff --git a/usr.bin/procstat/procstat_vm.c b/usr.bin/procstat/procstat_vm.c index e4de4921621e..8c641e55aad5 100644 --- a/usr.bin/procstat/procstat_vm.c +++ b/usr.bin/procstat/procstat_vm.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2007 Robert N. M. Watson + * Copyright (c) 2015 Allan Jude * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,70 +47,118 @@ procstat_vm(struct procstat *procstat, struct kinfo_proc *kipp) struct kinfo_vmentry *freep, *kve; int ptrwidth; int i, cnt; - const char *str; + const char *str, *lstr; ptrwidth = 2*sizeof(void *) + 2; if (!hflag) - printf("%5s %*s %*s %3s %4s %4s %3s %3s %-4s %-2s %-s\n", + xo_emit("{T:/%5s %*s %*s %3s %4s %4s %3s %3s %-4s %-2s %-s}\n", "PID", ptrwidth, "START", ptrwidth, "END", "PRT", "RES", "PRES", "REF", "SHD", "FLAG", "TP", "PATH"); + xo_emit("{ek:process_id/%d}", kipp->ki_pid); + freep = procstat_getvmmap(procstat, kipp, &cnt); if (freep == NULL) return; + xo_open_list("vm"); for (i = 0; i < cnt; i++) { + xo_open_instance("vm"); kve = &freep[i]; - printf("%5d ", kipp->ki_pid); - printf("%#*jx ", ptrwidth, (uintmax_t)kve->kve_start); - printf("%#*jx ", ptrwidth, (uintmax_t)kve->kve_end); - printf("%s", kve->kve_protection & KVME_PROT_READ ? "r" : "-"); - printf("%s", kve->kve_protection & KVME_PROT_WRITE ? "w" : "-"); - printf("%s ", kve->kve_protection & KVME_PROT_EXEC ? "x" : "-"); - printf("%4d ", kve->kve_resident); - printf("%4d ", kve->kve_private_resident); - printf("%3d ", kve->kve_ref_count); - printf("%3d ", kve->kve_shadow_count); - printf("%-1s", kve->kve_flags & KVME_FLAG_COW ? "C" : "-"); - printf("%-1s", kve->kve_flags & KVME_FLAG_NEEDS_COPY ? "N" : - "-"); - printf("%-1s", kve->kve_flags & KVME_FLAG_SUPER ? "S" : "-"); - printf("%-1s ", kve->kve_flags & KVME_FLAG_GROWS_UP ? "U" : - kve->kve_flags & KVME_FLAG_GROWS_DOWN ? "D" : "-"); + xo_emit("{dk:process_id/%5d} ", kipp->ki_pid); + xo_emit("{d:kve_start/%#*jx} ", ptrwidth, + (uintmax_t)kve->kve_start); + xo_emit("{d:kve_end/%#*jx} ", ptrwidth, + (uintmax_t)kve->kve_end); + xo_emit("{e:kve_start/%#jx}", (uintmax_t)kve->kve_start); + xo_emit("{e:kve_end/%#jx}", (uintmax_t)kve->kve_end); + xo_emit("{d:read/%s}", kve->kve_protection & KVME_PROT_READ ? + "r" : "-"); + xo_emit("{d:write/%s}", kve->kve_protection & KVME_PROT_WRITE ? + "w" : "-"); + xo_emit("{d:exec/%s} ", kve->kve_protection & KVME_PROT_EXEC ? + "x" : "-"); + xo_open_container("kve_protection"); + xo_emit("{en:read/%s}", kve->kve_protection & KVME_PROT_READ ? + "true" : "false"); + xo_emit("{en:write/%s}", kve->kve_protection & KVME_PROT_WRITE ? + "true" : "false"); + xo_emit("{en:exec/%s}", kve->kve_protection & KVME_PROT_EXEC ? + "true" : "false"); + xo_close_container("kve_protection"); + xo_emit("{:kve_resident/%4d/%d} ", kve->kve_resident); + xo_emit("{:kve_private_resident/%4d/%d} ", + kve->kve_private_resident); + xo_emit("{:kve_ref_count/%3d/%d} ", kve->kve_ref_count); + xo_emit("{:kve_shadow_count/%3d/%d} ", kve->kve_shadow_count); + xo_emit("{d:copy_on_write/%-1s}", kve->kve_flags & + KVME_FLAG_COW ? "C" : "-"); + xo_emit("{d:need_copy/%-1s}", kve->kve_flags & + KVME_FLAG_NEEDS_COPY ? "N" : "-"); + xo_emit("{d:super_pages/%-1s}", kve->kve_flags & + KVME_FLAG_SUPER ? "S" : "-"); + xo_emit("{d:grows_down/%-1s} ", kve->kve_flags & + KVME_FLAG_GROWS_UP ? "U" : kve->kve_flags & + KVME_FLAG_GROWS_DOWN ? "D" : "-"); + xo_open_container("kve_flags"); + xo_emit("{en:copy_on_write/%s}", kve->kve_flags & + KVME_FLAG_COW ? "true" : "false"); + xo_emit("{en:needs_copy/%s}", kve->kve_flags & + KVME_FLAG_NEEDS_COPY ? "true" : "false"); + xo_emit("{en:super_pages/%s}", kve->kve_flags & + KVME_FLAG_SUPER ? "true" : "false"); + xo_emit("{en:grows_up/%s}", kve->kve_flags & + KVME_FLAG_GROWS_UP ? "true" : "false"); + xo_emit("{en:grows_down/%s}", kve->kve_flags & + KVME_FLAG_GROWS_DOWN ? "true" : "false"); + xo_close_container("kve_flags"); switch (kve->kve_type) { case KVME_TYPE_NONE: str = "--"; + lstr = "none"; break; case KVME_TYPE_DEFAULT: str = "df"; + lstr = "default"; break; case KVME_TYPE_VNODE: str = "vn"; + lstr = "vnode"; break; case KVME_TYPE_SWAP: str = "sw"; + lstr = "swap"; break; case KVME_TYPE_DEVICE: str = "dv"; + lstr = "device"; break; case KVME_TYPE_PHYS: str = "ph"; + lstr = "physical"; break; case KVME_TYPE_DEAD: str = "dd"; + lstr = "dead"; break; case KVME_TYPE_SG: str = "sg"; + lstr = "scatter/gather"; break; case KVME_TYPE_MGTDEVICE: str = "md"; + lstr = "managed_device"; break; case KVME_TYPE_UNKNOWN: default: str = "??"; + lstr = "unknown"; break; } - printf("%-2s ", str); - printf("%-s\n", kve->kve_path); + xo_emit("{d:kve_type/%-2s} ", str); + xo_emit("{e:kve_type/%s}", lstr); + xo_emit("{:kve_path/%-s/%s}\n", kve->kve_path); + xo_close_instance("vm"); } + xo_close_list("vm"); free(freep); }