diff options
-rw-r--r-- | usr.bin/systat/Makefile | 8 | ||||
-rw-r--r-- | usr.bin/systat/cache.c | 297 | ||||
-rw-r--r-- | usr.bin/systat/cache.h | 56 | ||||
-rw-r--r-- | usr.bin/systat/config.h | 85 | ||||
-rw-r--r-- | usr.bin/systat/disks.c | 98 | ||||
-rw-r--r-- | usr.bin/systat/engine.c | 1204 | ||||
-rw-r--r-- | usr.bin/systat/engine.h | 167 | ||||
-rw-r--r-- | usr.bin/systat/extern.h | 141 | ||||
-rw-r--r-- | usr.bin/systat/fetch.c | 54 | ||||
-rw-r--r-- | usr.bin/systat/if.c | 261 | ||||
-rw-r--r-- | usr.bin/systat/iostat.c | 307 | ||||
-rw-r--r-- | usr.bin/systat/keyboard.c | 165 | ||||
-rw-r--r-- | usr.bin/systat/main.c | 672 | ||||
-rw-r--r-- | usr.bin/systat/mbufs.c | 181 | ||||
-rw-r--r-- | usr.bin/systat/netcmds.c | 360 | ||||
-rw-r--r-- | usr.bin/systat/netstat.c | 669 | ||||
-rw-r--r-- | usr.bin/systat/pf.c | 326 | ||||
-rw-r--r-- | usr.bin/systat/pftop.c | 2160 | ||||
-rw-r--r-- | usr.bin/systat/pigs.c | 319 | ||||
-rw-r--r-- | usr.bin/systat/sensors.c | 237 | ||||
-rw-r--r-- | usr.bin/systat/swap.c | 212 | ||||
-rw-r--r-- | usr.bin/systat/systat.h | 57 | ||||
-rw-r--r-- | usr.bin/systat/vmstat.c | 119 |
23 files changed, 6067 insertions, 2088 deletions
diff --git a/usr.bin/systat/Makefile b/usr.bin/systat/Makefile index 68ab8380e0b..3cc4ff83bcf 100644 --- a/usr.bin/systat/Makefile +++ b/usr.bin/systat/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.19 2007/12/15 17:46:23 deraadt Exp $ +# $OpenBSD: Makefile,v 1.20 2008/06/12 22:26:01 canacar Exp $ PROG= systat @@ -6,8 +6,10 @@ PROG= systat CFLAGS+=-DNOKVM CPPFLAGS+=-I${.CURDIR}/../../usr.bin/vmstat -SRCS= cmds.c cmdtab.c disks.c dkstats.c fetch.c if.c iostat.c keyboard.c \ - main.c mbufs.c netcmds.c netstat.c pigs.c sensors.c swap.c vmstat.c +CPPFLAGS+=-I${.CURDIR}/../../sbin/pfctl +SRCS= dkstats.c engine.c if.c iostat.c main.c mbufs.c netstat.c \ + pigs.c sensors.c swap.c vmstat.c pftop.c cache.c pf.c + DPADD= ${LIBCURSES} ${LIBM} ${LIBKVM} LDADD= -lcurses -lm -lkvm BINGRP= kmem diff --git a/usr.bin/systat/cache.c b/usr.bin/systat/cache.c new file mode 100644 index 00000000000..136f8871435 --- /dev/null +++ b/usr.bin/systat/cache.c @@ -0,0 +1,297 @@ +/* $Id: cache.c,v 1.1 2008/06/12 22:26:01 canacar Exp $ */ +/* + * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <netinet/in.h> + +#include <netinet/tcp_fsm.h> +#ifdef TEST_COMPAT +#include "pfvarmux.h" +#else +#include <net/pfvar.h> +#endif +#include <arpa/inet.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <assert.h> + +#include "cache.h" + +/* prototypes */ +void update_state(struct sc_ent *, pf_state_t *, double); +struct sc_ent *cache_state(pf_state_t *); +static __inline int sc_cmp(struct sc_ent *s1, struct sc_ent *s2); + +/* initialize the tree and queue */ +RB_HEAD(sc_tree, sc_ent) sctree; +TAILQ_HEAD(sc_queue, sc_ent) scq1, scq2, scq_free; +RB_GENERATE(sc_tree, sc_ent, tlink, sc_cmp); + +struct sc_queue *scq_act = NULL; +struct sc_queue *scq_exp = NULL; + +int cache_max = 0; +int cache_size = 0; + +struct sc_ent *sc_store = NULL; + +/* preallocate the cache and insert into the 'free' queue */ +int +cache_init(int max) +{ + int n; + static int initialized = 0; + + if (max < 0 || initialized) + return (1); + + if (max == 0) { + sc_store = NULL; + } else { + sc_store = malloc(max * sizeof(struct sc_ent)); + if (sc_store == NULL) + return (1); + } + + RB_INIT(&sctree); + TAILQ_INIT(&scq1); + TAILQ_INIT(&scq2); + TAILQ_INIT(&scq_free); + + scq_act = &scq1; + scq_exp = &scq2; + + for (n = 0; n < max; n++) + TAILQ_INSERT_HEAD(&scq_free, sc_store + n, qlink); + + cache_size = cache_max = max; + initialized++; + + return (0); +} + +void +update_state(struct sc_ent *prev, pf_state_t *new, double rate) +{ + assert (prev != NULL && new != NULL); + prev->t = time(NULL); + prev->rate = rate; +#ifdef HAVE_INOUT_COUNT + prev->bytes = COUNTER(new->bytes[0]) + COUNTER(new->bytes[1]); +#else + prev->bytes = COUNTER(new->bytes); +#endif + if (prev->peak < rate) + prev->peak = rate; +} + +void +add_state(pf_state_t *st) +{ + struct sc_ent *ent; + assert(st != NULL); + + if (cache_max == 0) + return; + + if (TAILQ_EMPTY(&scq_free)) + return; + + ent = TAILQ_FIRST(&scq_free); + TAILQ_REMOVE(&scq_free, ent, qlink); + + cache_size--; + +#ifdef HAVE_PFSYNC_STATE + ent->id[0] = st->id[0]; + ent->id[1] = st->id[1]; +#else + ent->addr[0] = st->lan.addr; + ent->port[0] = st->lan.port; + ent->addr[1] = st->ext.addr; + ent->port[1] = st->ext.port; + ent->af = st->af; + ent->proto = st->proto; +#endif +#ifdef HAVE_INOUT_COUNT + ent->bytes = COUNTER(st->bytes[0]) + COUNTER(st->bytes[1]); +#else + ent->bytes = st->bytes; +#endif + ent->peak = 0; + ent->rate = 0; + ent->t = time(NULL); + + RB_INSERT(sc_tree, &sctree, ent); + TAILQ_INSERT_HEAD(scq_act, ent, qlink); +} + +/* must be called only once for each state before cache_endupdate */ +struct sc_ent * +cache_state(pf_state_t *st) +{ + struct sc_ent ent, *old; + double sd, td, r; + + if (cache_max == 0) + return (NULL); + +#ifdef HAVE_PFSYNC_STATE + ent.id[0] = st->id[0]; + ent.id[1] = st->id[1]; +#else + ent.addr[0] = st->lan.addr; + ent.port[0] = st->lan.port; + ent.addr[1] = st->ext.addr; + ent.port[1] = st->ext.port; + ent.af = st->af; + ent.proto = st->proto; +#endif + old = RB_FIND(sc_tree, &sctree, &ent); + + if (old == NULL) { + add_state(st); + return (NULL); + } + +#ifdef HAVE_INOUT_COUNT + if (COUNTER(st->bytes[0]) + COUNTER(st->bytes[1]) < old->bytes) + return (NULL); + + sd = COUNTER(st->bytes[0]) + COUNTER(st->bytes[1]) - old->bytes; +#else + if (st->bytes < old->bytes) + return (NULL); + + sd = st->bytes - old->bytes; +#endif + + td = time(NULL) - old->t; + + if (td > 0) { + r = sd/td; + update_state(old, st, r); + } + + /* move to active queue */ + TAILQ_REMOVE(scq_exp, old, qlink); + TAILQ_INSERT_HEAD(scq_act, old, qlink); + + return (old); +} + +/* remove the states that are not updated in this cycle */ +void +cache_endupdate(void) +{ + struct sc_queue *tmp; + struct sc_ent *ent; + + while (! TAILQ_EMPTY(scq_exp)) { + ent = TAILQ_FIRST(scq_exp); + TAILQ_REMOVE(scq_exp, ent, qlink); + RB_REMOVE(sc_tree, &sctree, ent); + TAILQ_INSERT_HEAD(&scq_free, ent, qlink); + cache_size++; + } + + tmp = scq_act; + scq_act = scq_exp; + scq_exp = tmp; +} + +static __inline int +sc_cmp(struct sc_ent *a, struct sc_ent *b) +{ +#ifdef HAVE_PFSYNC_STATE + if (a->id[0] > b->id[0]) + return (1); + if (a->id[0] < b->id[0]) + return (-1); + if (a->id[1] > b->id[1]) + return (1); + if (a->id[1] < b->id[1]) + return (-1); +#else + int diff; + + if ((diff = a->proto - b->proto) != 0) + return (diff); + if ((diff = a->af - b->af) != 0) + return (diff); + switch (a->af) { + case AF_INET: + if (a->addr[0].addr32[0] > b->addr[0].addr32[0]) + return (1); + if (a->addr[0].addr32[0] < b->addr[0].addr32[0]) + return (-1); + if (a->addr[1].addr32[0] > b->addr[1].addr32[0]) + return (1); + if (a->addr[1].addr32[0] < b->addr[1].addr32[0]) + return (-1); + break; + case AF_INET6: + if (a->addr[0].addr32[0] > b->addr[0].addr32[0]) + return (1); + if (a->addr[0].addr32[0] < b->addr[0].addr32[0]) + return (-1); + if (a->addr[0].addr32[1] > b->addr[0].addr32[1]) + return (1); + if (a->addr[0].addr32[1] < b->addr[0].addr32[1]) + return (-1); + if (a->addr[0].addr32[2] > b->addr[0].addr32[2]) + return (1); + if (a->addr[0].addr32[2] < b->addr[0].addr32[2]) + return (-1); + if (a->addr[0].addr32[3] > b->addr[0].addr32[3]) + return (1); + if (a->addr[0].addr32[3] < b->addr[0].addr32[3]) + return (-1); + if (a->addr[1].addr32[0] > b->addr[1].addr32[0]) + return (1); + if (a->addr[1].addr32[0] < b->addr[1].addr32[0]) + return (-1); + if (a->addr[1].addr32[1] > b->addr[1].addr32[1]) + return (1); + if (a->addr[1].addr32[1] < b->addr[1].addr32[1]) + return (-1); + if (a->addr[1].addr32[2] > b->addr[1].addr32[2]) + return (1); + if (a->addr[1].addr32[2] < b->addr[1].addr32[2]) + return (-1); + if (a->addr[1].addr32[3] > b->addr[1].addr32[3]) + return (1); + if (a->addr[1].addr32[3] < b->addr[1].addr32[3]) + return (-1); + break; + default: + return 1; + } + + if ((diff = a->port[0] - b->port[0]) != 0) + return (diff); + if ((diff = a->port[1] - b->port[1]) != 0) + return (diff); +#endif + return (0); +} diff --git a/usr.bin/systat/cache.h b/usr.bin/systat/cache.h new file mode 100644 index 00000000000..5e499b15e01 --- /dev/null +++ b/usr.bin/systat/cache.h @@ -0,0 +1,56 @@ +/* $Id: cache.h,v 1.1 2008/06/12 22:26:01 canacar Exp $ */ +/* + * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _CACHE_H_ +#define _CACHE_H_ + +#include "config.h" + +#include <sys/queue.h> +#ifdef HAVE_TREE_H +#include <sys/tree.h> +#else +#include "tree.h" +#endif + + +struct sc_ent { + RB_ENTRY(sc_ent) tlink; + TAILQ_ENTRY(sc_ent) qlink; +#ifdef HAVE_PFSYNC_STATE + u_int32_t id[2]; +#else + struct pf_addr addr[2]; +#endif + double peak; + double rate; + time_t t; + u_int32_t bytes; +#ifndef HAVE_PFSYNC_STATE + u_int16_t port[2]; + u_int8_t af; + u_int8_t proto; +#endif +}; + +int cache_init(int); +void cache_endupdate(void); +struct sc_ent *cache_state(pf_state_t *); +extern int cache_max, cache_size; + + +#endif diff --git a/usr.bin/systat/config.h b/usr.bin/systat/config.h new file mode 100644 index 00000000000..53e112ded2a --- /dev/null +++ b/usr.bin/systat/config.h @@ -0,0 +1,85 @@ +/* $Id: config.h,v 1.1 2008/06/12 22:26:01 canacar Exp $ */ +/* + * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + + +/* OS_LEVEL > 30 */ +#define HAVE_STATE_NOROUTE +#define HAVE_DEVICE_RO +#define HAVE_TREE_H +#define HAVE_QUEUE_H +#define HAVE_PF_ROUTE +#define HAVE_RULE_LABELS + +/* OS_LEVEL > 31 */ +#define HAVE_RULE_NUMBER +#define HAVE_ADDR_WRAP +#define HAVE_RULE_STATES +#define HAVE_RULE_IFNOT +#define HAVE_PROTO_NAMES +#define HAVE_MAX_STATES +#define HAVE_MAX_MSS +#define HAVE_RULE_UGID + +/* OS_LEVEL > 32 */ +#define HAVE_ADDR_MASK +#define HAVE_ADDR_TYPE +#define HAVE_ALTQ +#define HAVE_RULE_TOS +#define HAVE_OP_RRG + +/* OS_LEVEL > 33 */ +#define HAVE_INOUT_COUNT +#define HAVE_TAGS +#define HAVE_RULE_NATPASS + +/* OS_LEVEL > 34 */ +#define HAVE_STATE_IFNAME + +/* OS_LEVEL > 35 */ +#define HAVE_NEG +#define HAVE_RULESETS + +/* OS_LEVEL > 37 */ +#define HAVE_INOUT_COUNT_RULES + +/* OS_LEVEL > 38 */ +#define HAVE_STATE_COUNT_64 + +/* OS_LEVEL > 41 */ +#define HAVE_PFSYNC_STATE + +/* OS_LEVEL > 43 */ +#define HAVE_PFSYNC_KEY + +#ifdef HAVE_PFSYNC_STATE +typedef struct pfsync_state pf_state_t; +typedef struct pfsync_state_host pf_state_host_t; +typedef struct pfsync_state_peer pf_state_peer_t; +#define COUNTER(c) ((((u_int64_t) c[0])<<32) + c[1]) +#define pfs_ifname ifname +#else +typedef struct pf_state pf_state_t; +typedef struct pf_state_host pf_state_host_t; +typedef struct pf_state_peer pf_state_peer_t; +#define COUNTER(c) (c) +#define pfs_ifname u.ifname +#endif + +#endif diff --git a/usr.bin/systat/disks.c b/usr.bin/systat/disks.c index c08bbbef200..e69de29bb2d 100644 --- a/usr.bin/systat/disks.c +++ b/usr.bin/systat/disks.c @@ -1,98 +0,0 @@ -/* $OpenBSD: disks.c,v 1.17 2007/09/11 15:47:17 gilles Exp $ */ -/* $NetBSD: disks.c,v 1.4 1996/05/10 23:16:33 thorpej Exp $ */ - -/*- - * Copyright (c) 1980, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)disks.c 8.1 (Berkeley) 6/6/93"; -#endif -static char rcsid[] = "$OpenBSD: disks.c,v 1.17 2007/09/11 15:47:17 gilles Exp $"; -#endif /* not lint */ - -#include <string.h> -#include <ctype.h> -#include <signal.h> -#include "systat.h" -#include "extern.h" -static void dkselect(char *args, int truefalse, int selections[]); - - -int -dkcmd(char *cmd, char *args) -{ - if (prefix(cmd, "display") || prefix(cmd, "add")) { - dkselect(args, 1, dk_select); - return (1); - } - if (prefix(cmd, "ignore") || prefix(cmd, "delete")) { - dkselect(args, 0, dk_select); - return (1); - } - if (prefix(cmd, "drives")) { - int i; - - move(CMDLINE, 0); - clrtoeol(); - for (i = 0; i < dk_ndrive; i++) - printw("%s ", dr_name[i]); - return (1); - } - return (0); -} - -static void -dkselect(char *args, int truefalse, int selections[]) -{ - char *cp; - int i; - - args[strcspn(args, "\n")] = '\0'; - - for (;;) { - for (cp = args; isspace(*cp); cp++) - ; - args = cp; - for (; *cp && !isspace(*cp); cp++) - ; - if (*cp) - *cp++ = '\0'; - if (cp - args == 0) - break; - for (i = 0; i < dk_ndrive; i++) - if (strcmp(args, dr_name[i]) == 0) { - selections[i] = truefalse; - break; - } - if (i >= dk_ndrive) - error("%s: unknown drive", args); - args = cp; - } -} diff --git a/usr.bin/systat/engine.c b/usr.bin/systat/engine.c new file mode 100644 index 00000000000..f8a6d73094a --- /dev/null +++ b/usr.bin/systat/engine.c @@ -0,0 +1,1204 @@ +/* $Id: engine.c,v 1.1 2008/06/12 22:26:01 canacar Exp $ */ +/* + * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + + +#include <sys/types.h> +#include <sys/queue.h> + +#include <ctype.h> +#include <curses.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "engine.h" + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +/* circular linked list of views */ +CIRCLEQ_HEAD(view_list, view_ent) view_head = + CIRCLEQ_HEAD_INITIALIZER(view_head); +struct view_ent { + field_view *view; + CIRCLEQ_ENTRY(view_ent) entries; +}; + +useconds_t udelay = 5000000; +int dispstart = 0; +int interactive = 1; +int maxprint = 0; +int paused = 0; +int rawmode = 0; +int rawwidth = DEFAULT_WIDTH; +int sortdir = 1; +int columns, lines; +u_int32_t num_disp = 0; +int max_disp = -1; + +volatile sig_atomic_t gotsig_close = 0; +volatile sig_atomic_t gotsig_resize = 0; +volatile sig_atomic_t gotsig_alarm = 0; +int need_update = 0; +int need_sort = 0; + +SCREEN *screen; + +field_view *curr_view = NULL; +struct view_ent *curr_view_ent = NULL; +struct view_manager *curr_mgr = NULL; + +int curr_line = 0; +int home_line = 0; + +/* line buffer for raw mode */ +char linebuf[MAX_LINE_BUF]; +int linepos = 0; + +/* temp storage for state printing */ +char tmp_buf[MAX_LINE_BUF]; + +char cmdbuf[MAX_LINE_BUF]; +int cmd_len = -1; +struct command *curr_cmd = NULL; +char *curr_message = NULL; + +void print_cmdline(void); + + +/* screen output functions */ + +char * tb_ptr = NULL; +int tb_len = 0; + +void +tb_start(void) +{ + tb_ptr = tmp_buf; + tb_len = sizeof(tmp_buf); + tb_ptr[0] = '\0'; +} + +void +tb_end(void) +{ + tb_ptr = NULL; + tb_len = 0; +} + +int +tbprintf(char *format, ...) + GCC_PRINTFLIKE(1,2) /* defined in curses.h */ +{ + int len; + va_list arg; + + if (tb_ptr == NULL || tb_len <= 0) + return 0; + + va_start(arg, format); + len=vsnprintf(tb_ptr, tb_len, format, arg); + va_end(arg); + + if (len > tb_len) + tb_end(); + else if (len > 0) { + tb_ptr += len; + tb_len -= len; + } + + return len; +} + +void +move_horiz(int offset) +{ + if (rawmode) { + if (offset <= 0) + linepos = 0; + else if (offset >= MAX_LINE_BUF) + linepos = MAX_LINE_BUF - 1; + else + linepos = offset; + } else { + move(curr_line, offset); + } +} + +void +print_str(int len, const char *str) +{ + if (len <= 0) + return; + + if (rawmode) { + int length = MIN(len, MAX_LINE_BUF - linepos); + if (length <= 0) + return; + bcopy(str, &linebuf[linepos], length); + linepos += length; + } else + addnstr(str, len); +} + +void +clear_linebuf(void) +{ + memset(linebuf, ' ', MAX_LINE_BUF); +} + +void +end_line(void) +{ + if (rawmode) { + linebuf[rawwidth] = '\0'; + printf("%s\n", linebuf); + clear_linebuf(); + } + curr_line++; +} + +void +end_page(void) +{ + if (rawmode) { + linepos = 0; + clear_linebuf(); + } else { + move(home_line, 0); + print_cmdline(); + refresh(); + } + curr_line = 0; +} + +void +rawaddstr(char *s) +{ + if (rawmode) + printf("%s", s); + else + addstr(s); +} + +/* field output functions */ + +void +print_fld_str(field_def *fld, const char *str) +{ + int len, move; + char *cpos; + + if (str == NULL || fld == NULL) + return; + + if (fld->start < 0) + return; + + len = strlen(str); + + if (len >= fld->width) { + move_horiz(fld->start); + print_str(fld->width, str); + } else { + switch (fld->align) { + case FLD_ALIGN_RIGHT: + move_horiz(fld->start + (fld->width - len)); + break; + case FLD_ALIGN_CENTER: + move_horiz(fld->start + (fld->width - len) / 2); + break; + case FLD_ALIGN_COLUMN: + if ((cpos = strchr(str, ':')) == NULL) { + move = (fld->width - len) / 2; + } else { + move = (fld->width / 2) - (cpos - str); + if (move < 0) + move = 0; + else if (move > (fld->width - len)) + move = fld->width - len; + } + move_horiz(fld->start + move); + break; + default: + move_horiz(fld->start); + break; + } + print_str(len, str); + } +} + +void +print_bar_title(field_def *fld) +{ + char buf[16]; + int len, div, i, tr, tw, val, pos, cur; + + int divs[] = {20, 10, 5, 4, 3, 2, 1, 0}; + + if (fld->width < 1) + return; + + len = snprintf(buf, sizeof(buf), " %d\\", fld->arg); + if (len >= sizeof(buf)) + return; + + for (i = 0; divs[i]; i++) + if (divs[i] * len <= fld->width) + break; + + if (divs[i] == 0) { + print_fld_str(fld, "*****"); + return; + } + + div = divs[i]; + + val = 0; + pos = 0; + tr = fld->arg % div; + tw = fld->width % div; + + tb_start(); + cur = 0; + for(i = 0; i < div; i++) { + tw += fld->width; + tr += fld->arg; + + while (tr >= div) { + val++; + tr -= div; + } + while (tw >= div) { + pos++; + tw -= div; + } + + len = snprintf(buf, sizeof(buf), "%d\\", val); + while (cur < pos - len) { + tbprintf(" "); + cur++; + } + tbprintf("%s", buf); + cur += len; + } + + print_fld_tb(fld); +} + +void +print_fld_bar(field_def *fld, int value) +{ + int i, tw, val, cur; + + if (fld->width < 1) + return; + + val = 0; + tw = fld->arg / 2; + + tb_start(); + cur = 0; + for(i = 0; i < fld->width; i++) { + tw += fld->arg; + + while (tw >= fld->width) { + val++; + tw -= fld->width; + } + if (val > value) + break; + tbprintf("#"); + } + + print_fld_tb(fld); +} + +void +print_fld_tb(field_def *fld) +{ + print_fld_str(fld, tmp_buf); + tb_end(); +} + +void +print_title(void) +{ + field_def **fp; + + if (curr_view != NULL && curr_view->view != NULL) { + for (fp = curr_view->view; *fp != NULL; fp++) { + switch((*fp)->align) { + case FLD_ALIGN_LEFT: + case FLD_ALIGN_RIGHT: + case FLD_ALIGN_CENTER: + case FLD_ALIGN_COLUMN: + print_fld_str(*fp, (*fp)->title); + break; + case FLD_ALIGN_BAR: + print_bar_title(*fp); + break; + } + } + } + end_line(); +} + +/* view related functions */ +void +hide_field(field_def *fld) +{ + if (fld == NULL) + return; + + fld->flags |= FLD_FLAG_HIDDEN; +} + +void +show_field(field_def *fld) +{ + if (fld == NULL) + return; + + fld->flags &= ~((unsigned int) FLD_FLAG_HIDDEN); +} + +void +reset_fields(void) +{ + field_def **fp; + field_def *fld; + + if (curr_view == NULL) + return; + + if (curr_view->view == NULL) + return; + + for (fp = curr_view->view; *fp != NULL; fp++) { + fld = *fp; + fld->start = -1; + fld->width = fld->norm_width; + } +} + +void +field_setup(void) +{ + field_def **fp; + field_def *fld; + int st, fwid, change; + int width = columns; + + reset_fields(); + + dispstart = 0; + st = 0; + + for (fp = curr_view->view; *fp != NULL; fp++) { + fld = *fp; + if (fld->flags & FLD_FLAG_HIDDEN) + continue; + + if (width <= 1) + break; + + if (st != 1) + width--; + + fld->start = 1; + fwid = fld->width; + st++; + if (fwid >= width) { + fld->width = width; + width = 0; + } else + width -= fwid; + } + + change = 0; + while (width > 0) { + change = 0; + for (fp = curr_view->view; *fp != NULL; fp++) { + fld = *fp; + if (fld->flags & FLD_FLAG_HIDDEN) + continue; + if ((fld->width < fld->max_width) && + (fld->increment <= width)) { + int w = fld->width + fld->increment; + if (w > fld->max_width) + w = fld->max_width; + width += fld->width - w; + fld->width = w; + change = 1; + } + if (width <= 0) break; + } + if (change == 0) break; + } + + st = 0; + for (fp = curr_view->view; *fp != NULL; fp++) { + fld = *fp; + if (fld->flags & FLD_FLAG_HIDDEN) + continue; + if (fld->start < 0) break; + fld->start = st; + st += fld->width + 1; + } +} + +void +set_curr_view(struct view_ent *ve) +{ + field_view *v; + + reset_fields(); + + if (ve == NULL) { + curr_view_ent = NULL; + curr_view = NULL; + curr_mgr = NULL; + return; + } + + v = ve->view; + + if ((curr_view != NULL) && (curr_mgr != v->mgr)) { + gotsig_alarm = 1; + if (v->mgr != NULL && v->mgr->select_fn != NULL) + v->mgr->select_fn(); + } + + curr_view_ent = ve; + curr_view = v; + curr_mgr = v->mgr; + field_setup(); + need_update = 1; +} + +void +add_view(field_view *fv) +{ + struct view_ent *ent; + + if (fv == NULL) + return; + + if (fv->view == NULL || fv->name == NULL || fv->mgr == NULL) + return; + + ent = malloc(sizeof(struct view_ent)); + if (ent == NULL) + return; + + ent->view = fv; + CIRCLEQ_INSERT_TAIL(&view_head, ent, entries); + + if (curr_view == NULL) + set_curr_view(ent); +} + +int +set_view(char *opt) +{ + struct view_ent *ve, *vm = NULL; + field_view *v; + int len; + + if (opt == NULL || (len = strlen(opt)) == 0) + return 1; + + CIRCLEQ_FOREACH(ve, &view_head, entries) { + v = ve->view; + if (strncasecmp(opt, v->name, len) == 0) { + if (vm) + return 1; + vm = ve; + } + } + + if (vm) { + set_curr_view(vm); + return 0; + } + + return 1; +} + +void +foreach_view(void (*callback)(field_view *)) +{ + struct view_ent *ve; + + CIRCLEQ_FOREACH(ve, &view_head, entries) { + callback(ve->view); + } +} + +int +set_view_hotkey(int ch) +{ + struct view_ent *ve; + field_view *v; + int key = tolower(ch); + + CIRCLEQ_FOREACH(ve, &view_head, entries) { + v = ve->view; + if (key == v->hotkey) { + set_curr_view(ve); + return 1; + } + } + + return 0; +} + +void +next_view(void) +{ + struct view_ent *ve; + + if (CIRCLEQ_EMPTY(&view_head) || curr_view_ent == NULL) + return; + + ve = CIRCLEQ_NEXT(curr_view_ent, entries); + if (ve == CIRCLEQ_END(&view_head)) + ve = CIRCLEQ_FIRST(&view_head); + + set_curr_view(ve); +} + +void +prev_view(void) +{ + struct view_ent *ve; + + if (CIRCLEQ_EMPTY(&view_head) || curr_view_ent == NULL) + return; + + ve = CIRCLEQ_PREV(curr_view_ent, entries); + if (ve == CIRCLEQ_END(&view_head)) + ve = CIRCLEQ_LAST(&view_head); + + set_curr_view(ve); +} + +/* generic field printing */ + +void +print_fld_age(field_def *fld, unsigned int age) +{ + int len; + unsigned int h, m, s; + + if (fld == NULL) + return; + len = fld->width; + + if (len < 1) + return; + + s = age % 60; + m = age / 60; + h = m / 60; + m %= 60; + + tb_start(); + if (tbprintf("%02u:%02u:%02u", h, m, s) <= len) + goto ok; + + if (tbprintf("%u", age) <= len) + goto ok; + + age /= 60; + if (tbprintf("%um", age) <= len) + goto ok; + if (age == 0) + goto err; + + age /= 60; + if (tbprintf("%uh", age) <= len) + goto ok; + if (age == 0) + goto err; + + age /= 24; + if (tbprintf("%ud", age) <= len) + goto ok; + + err: + print_fld_str(fld, "*"); + tb_end(); + return; + + ok: + print_fld_tb(fld); +} + +void +print_fld_sdiv(field_def *fld, u_int64_t size, int div) +{ + int len; + + if (fld == NULL) + return; + + len = fld->width; + if (len < 1) + return; + + tb_start(); + if (tbprintf("%llu", size) <= len) + goto ok; + + size /= div; + if (tbprintf("%lluK", size) <= len) + goto ok; + if (size == 0) + goto err; + + size /= div; + if (tbprintf("%lluM", size) <= len) + goto ok; + if (size == 0) + goto err; + + size /= div; + if (tbprintf("%lluG", size) <= len) + goto ok; + +err: + print_fld_str(fld, "*"); + tb_end(); + return; + +ok: + print_fld_tb(fld); +} + +void +print_fld_size(field_def *fld, u_int64_t size) +{ + print_fld_sdiv(fld, size, 1024); +} + +void +print_fld_rate(field_def *fld, double rate) +{ + if (rate < 0) { + print_fld_str(fld, "*"); + } else { + print_fld_size(fld, rate); + } +} + +void +print_fld_bw(field_def *fld, double bw) +{ + if (bw < 0) { + print_fld_str(fld, "*"); + } else { + print_fld_sdiv(fld, bw, 1000); + } +} + +void +print_fld_uint(field_def *fld, unsigned int size) +{ + int len; + + if (fld == NULL) + return; + + len = fld->width; + if (len < 1) + return; + + tb_start(); + if (tbprintf("%u", size) > len) + print_fld_str(fld, "*"); + else + print_fld_tb(fld); + tb_end(); +} + + +/* ordering */ + +void +set_order(char *opt) +{ + order_type *o; + + if (curr_view == NULL || curr_view->mgr == NULL) + return; + + curr_view->mgr->order_curr = curr_view->mgr->order_list; + + if (opt == NULL) + return; + + o = curr_view->mgr->order_list; + + if (o == NULL) + return; + + for (;o->name != NULL; o++) { + if (strcasecmp(opt, o->match) == 0) { + curr_view->mgr->order_curr = o; + return; + } + } +} + +int +set_order_hotkey(int ch) +{ + order_type *o; + int key = ch; + + if (curr_view == NULL || curr_view->mgr == NULL) + return 0; + + o = curr_view->mgr->order_list; + + if (o == NULL) + return 0; + + for (;o->name != NULL; o++) { + if (key == o->hotkey) { + if (curr_view->mgr->order_curr == o) { + sortdir *= -1; + } else { + curr_view->mgr->order_curr = o; + } + return 1; + } + } + + return 0; +} + +void +next_order(void) +{ + order_type *o, *oc; + + oc = curr_view->mgr->order_curr; + + for (o = curr_view->mgr->order_list; o->name != NULL; o++) { + if (oc == o) { + o++; + if (o->name == NULL) + break; + curr_view->mgr->order_curr = o; + return; + } + } + + curr_view->mgr->order_curr = curr_view->mgr->order_list; +} + + +/* main program functions */ + +int +read_view(void) +{ + if (curr_mgr == NULL) + return (0); + + if (paused) + return (0); + + if (curr_mgr->read_fn != NULL) + return (curr_mgr->read_fn()); + + return (0); +} + + +int +disp_update(void) +{ + int lines; + + if (maxprint < 0) + dispstart = 0; + else if (dispstart + maxprint > num_disp) + dispstart = num_disp - maxprint; + + if (dispstart < 0) + dispstart = 0; + + if (curr_view == NULL) + return 0; + + if (curr_mgr != NULL) { + curr_line = 0; + + if (curr_mgr->header_fn != NULL) { + lines = curr_mgr->header_fn(); + if (lines < 0) + return (1); +// home_line = lines++; + curr_line = ++lines; + home_line = lines + maxprint + 1; + } + + print_title(); + + if (curr_mgr->print_fn != NULL) + curr_mgr->print_fn(); + } + + return (0); +} + +void +sort_view(void) +{ + if (curr_mgr != NULL) + if (curr_mgr->sort_fn != NULL) + curr_mgr->sort_fn(); +} + +void +sig_close(int signal) +{ + gotsig_close = 1; +} + +void +sig_resize(int signal) +{ + gotsig_resize = 1; +} + +void +sig_alarm(int signal) +{ + gotsig_alarm = 1; +} + +void +setup_term(int dmax) +{ + max_disp = dmax; + maxprint = dmax; + + if (rawmode) { + columns = rawwidth; + lines = DEFAULT_HEIGHT; + clear_linebuf(); + } else { + if (dmax < 0) + dmax = 0; + + screen = newterm(NULL, stdout, stdin); + if (screen == NULL) { + rawmode = 1; + interactive = 0; + setup_term(dmax); + return; + } + columns = COLS; + lines = LINES; + + if (maxprint > lines - HEADER_LINES) + maxprint = lines - HEADER_LINES; + + nonl(); + keypad(stdscr, TRUE); + intrflush(stdscr, FALSE); + + halfdelay(10); + noecho(); + } + + if (dmax == 0) + maxprint = lines - HEADER_LINES; + + field_setup(); +} + +struct command * +command_set(struct command *cmd, const char *init) +{ + struct command *prev = curr_cmd; + + if (cmd) { + if (init) { + cmd_len = strlcpy(cmdbuf, init, sizeof(cmdbuf)); + if (cmd_len >= sizeof(cmdbuf)) { + cmdbuf[0] = '\0'; + cmd_len = 0; + } + } else { + cmd_len = 0; + cmdbuf[0] = 0; + } + } + curr_message = NULL; + curr_cmd = cmd; + need_update = 1; + return prev; +} + +const char * +message_set(const char *msg) { + char *prev = curr_message; + if (msg) + curr_message = strdup(msg); + else + curr_message = NULL; + free(prev); + return NULL; +} + +void +print_cmdline(void) +{ + if (curr_cmd) { + attron(A_STANDOUT); + mvprintw(home_line, 0, "%s: ", curr_cmd->prompt); + attroff(A_STANDOUT); + printw("%s", cmdbuf); + } else if (curr_message) { + mvprintw(home_line, 0, "> %s", curr_message); + } + clrtoeol(); +} + + +void +cmd_keyboard(int ch) +{ + if (curr_cmd == NULL) + return; + + if (ch > 0 && isprint(ch)) { + if (cmd_len < sizeof(cmdbuf) - 1) { + cmdbuf[cmd_len++] = ch; + cmdbuf[cmd_len] = 0; + } else + beep(); + } + + switch (ch) { + case KEY_ENTER: + case 0x0a: + case 0x0d: + { + struct command * c = command_set(NULL, NULL); + c->exec(); + break; + } + case KEY_BACKSPACE: + case KEY_DC: + case CTRL_H: + if (cmd_len > 0) { + cmdbuf[--cmd_len] = 0; + } else + beep(); + break; + case 0x1b: + case CTRL_G: + if (cmd_len > 0) { + cmdbuf[0] = '\0'; + cmd_len = 0; + } else + command_set(NULL, NULL); + break; + default: + break; + } +} + +void +keyboard(void) +{ + int ch; + + ch = getch(); + + if (curr_cmd) { + cmd_keyboard(ch); + print_cmdline(); + return; + } + + if (curr_mgr != NULL) + if (curr_mgr->key_fn != NULL) + if (curr_mgr->key_fn(ch)) + return; + + if (curr_message != NULL) { + if (ch > 0) { + curr_message = NULL; + need_update = 1; + } + } + + switch (ch) { + case ' ': + gotsig_alarm = 1; + break; + case 'o': + next_order(); + need_sort = 1; + break; + case 'p': + paused = !paused; + gotsig_alarm = 1; + break; + case 'q': + gotsig_close = 1; + break; + case 'r': + sortdir *= -1; + need_sort = 1; + break; + case 'v': + /* FALLTHROUGH */ + case KEY_RIGHT: + /* FALLTHROUGH */ + case CTRL_F: + next_view(); + break; + case KEY_LEFT: + /* FALLTHROUGH */ + case CTRL_B: + prev_view(); + break; + case KEY_DOWN: + /* FALLTHROUGH */ + case CTRL_N: + dispstart++; + need_update = 1; + break; + case KEY_UP: + /* FALLTHROUGH */ + case CTRL_P: + dispstart--; + need_update = 1; + break; + case KEY_NPAGE: + /* FALLTHROUGH */ + case CTRL_V: + dispstart += maxprint; + need_update = 1; + break; + case KEY_PPAGE: + /* FALLTHROUGH */ + case META_V: + dispstart -= maxprint; + need_update = 1; + break; + case KEY_HOME: + /* FALLTHROUGH */ + case CTRL_A: + dispstart = 0; + need_update = 1; + break; + case KEY_END: + /* FALLTHROUGH */ + case CTRL_E: + dispstart = num_disp; + need_update = 1; + break; + case CTRL_L: + clear(); + need_update = 1; + break; + default: + break; + } + + if (set_order_hotkey(ch)) + need_sort = 1; + else + set_view_hotkey(ch); +} + +void +engine_initialize(void) +{ + signal(SIGTERM, sig_close); + signal(SIGINT, sig_close); + signal(SIGQUIT, sig_close); + signal(SIGWINCH, sig_resize); + signal(SIGALRM, sig_alarm); +} + +void +engine_loop(int countmax) +{ + int count = 0; + + for (;;) { + if (gotsig_alarm) { + read_view(); + need_sort = 1; + gotsig_alarm = 0; + ualarm(udelay, 0); + } + + if (need_sort) { + sort_view(); + need_sort = 0; + need_update = 1; + + /* XXX if sort took too long */ + if (gotsig_alarm) { + gotsig_alarm = 0; + ualarm(udelay, 0); + } + } + + if (need_update) { + erase(); + disp_update(); + end_page(); + need_update = 0; + if (countmax && ++count >= countmax) + break; + } + + if (gotsig_close) + break; + if (gotsig_resize) { + if (rawmode == 0) + endwin(); + setup_term(max_disp); + gotsig_resize = 0; + need_update = 1; + } + + if (interactive && need_update == 0) + keyboard(); + else if (interactive == 0) + usleep(udelay); + } + + if (rawmode == 0) + endwin(); +} diff --git a/usr.bin/systat/engine.h b/usr.bin/systat/engine.h new file mode 100644 index 00000000000..fd3d7e91a01 --- /dev/null +++ b/usr.bin/systat/engine.h @@ -0,0 +1,167 @@ +/* $Id: engine.h,v 1.1 2008/06/12 22:26:01 canacar Exp $ */ +/* + * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _ENGINE_H_ +#define _ENGINE_H_ + +#include <curses.h> + +#define DEFAULT_WIDTH 80 +#define DEFAULT_HEIGHT 25 + +/* XXX do not hardcode! */ +#define HEADER_LINES 4 + + +#define CTRL_A 1 +#define CTRL_B 2 +#define CTRL_E 5 +#define CTRL_F 6 +#define CTRL_G 7 +#define CTRL_H 8 +#define CTRL_L 12 +#define CTRL_N 14 +#define CTRL_P 16 +#define CTRL_V 22 + +#define META_V 246 + +#define MAX_LINE_BUF 1024 + + +#define FLD_ALIGN_LEFT 0 +#define FLD_ALIGN_RIGHT 1 +#define FLD_ALIGN_CENTER 2 +#define FLD_ALIGN_COLUMN 3 +#define FLD_ALIGN_BAR 4 + +#define FLD_FLAG_HIDDEN 1 + + +typedef struct { + char *title; + int norm_width; + int max_width; + int increment; + int align; + int start; + int width; + unsigned flags; + int arg; +} field_def; + +typedef struct { + char *name; + char *match; + int hotkey; + int (*func) (const void *, const void *); +} order_type; + +struct view_manager { + char *name; + int (*select_fn) (void); + int (*read_fn) (void); + void (*sort_fn) (void); + int (*header_fn) (void); + void (*print_fn) (void); + int (*key_fn) (int); + order_type *order_list; + order_type *order_curr; +}; + +typedef struct { + field_def **view; + char *name; + int hotkey; + struct view_manager *mgr; +} field_view; + +struct command { + char *prompt; + void ( *exec)(void); +}; + + +void tb_start(void); + +void tb_end(void); + +int tbprintf(char *format, ...) GCC_PRINTFLIKE(1,2); + +void end_line(void); +void end_page(void); + +void print_fld_str(field_def *fld, const char *str); +void print_fld_age(field_def *fld, unsigned int age); +void print_fld_sdiv(field_def *fld, u_int64_t size, int div); +void print_fld_size(field_def *fld, u_int64_t size); +void print_fld_bw(field_def *fld, double bw); +void print_fld_rate(field_def *fld, double rate); +void print_fld_uint(field_def *fld, unsigned int size); +void print_fld_bar(field_def *fld, int value); +void print_fld_tb(field_def *fld); + +void print_title(void); + +void hide_field(field_def *fld); +void show_field(field_def *fld); +void field_setup(void); + +void add_view(field_view *fv); +int set_view(char *opt); +void next_view(void); +void prev_view(void); + +void set_order(char *opt); +void next_order(void); + +void setup_term(int maxpr); + +void engine_initialize(void); +void engine_loop(int countmax); + +struct command *command_set(struct command *cmd, const char *init); +const char *message_set(const char *msg); + +void foreach_view(void (*callback)(field_view *)); + +extern int sortdir; +extern useconds_t udelay; +extern int dispstart; +extern int interactive; +extern int maxprint; +extern int paused; +extern int rawmode; +extern int rawwidth; +extern int columns, lines; + +extern int need_update; +extern int need_sort; + +extern volatile sig_atomic_t gotsig_close; +extern volatile sig_atomic_t gotsig_resize; +extern volatile sig_atomic_t gotsig_alarm; + +extern field_view *curr_view; +extern struct view_manager *curr_mgr; + +extern char tmp_buf[MAX_LINE_BUF]; +extern char cmdbuf[MAX_LINE_BUF]; + +extern int curr_line; /* XXX temp */ +extern u_int32_t num_disp; +#endif diff --git a/usr.bin/systat/extern.h b/usr.bin/systat/extern.h index 264827da14a..e69de29bb2d 100644 --- a/usr.bin/systat/extern.h +++ b/usr.bin/systat/extern.h @@ -1,141 +0,0 @@ -/* $OpenBSD: extern.h,v 1.19 2007/08/09 02:38:09 ray Exp $ */ -/* $NetBSD: extern.h,v 1.3 1996/05/10 23:16:34 thorpej Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)extern.h 8.1 (Berkeley) 6/6/93 - */ - -#include <sys/cdefs.h> -#include <fcntl.h> -#include <kvm.h> - -extern struct cmdtab *curcmd; -extern struct cmdtab cmdtab[]; -extern WINDOW *wnd; -extern char **dr_name; -extern char hostname[]; -extern double avenrun[3]; -extern kvm_t *kd; -extern long ntext; -extern int *dk_select; -extern int CMDLINE; -extern int dk_ndrive; -extern int hz, stathz; -extern double naptime; -extern size_t nhosts; -extern size_t nports; -extern int protos; -extern int verbose; -extern int nflag; - -struct inpcb; - -int checkhost(struct inpcb *); -int checkport(struct inpcb *); -void closeifstat(WINDOW *); -void closeiostat(WINDOW *); -void closekre(WINDOW *); -void closembufs(WINDOW *); -void closenetstat(WINDOW *); -void closepigs(WINDOW *); -void closesensors(WINDOW *); -void closeswap(WINDOW *); -int cmdifstat(char *, char *); -int cmdiostat(char *, char *); -int cmdkre(char *, char *); -int cmdnetstat(char *, char *); -struct cmdtab *lookup(char *); -void command(char *); -void sigdie(int); -void sigtstp(int); -void die(void); -void sigdisplay(int); -void display(void); -int dkinit(int); -int dkcmd(char *, char *); -void error(const char *fmt, ...); -void fetchifstat(void); -void fetchiostat(void); -void fetchkre(void); -void fetchmbufs(void); -void fetchnetstat(void); -void fetchpigs(void); -void fetchsensors(void); -void fetchswap(void); -int initifstat(void); -int initiostat(void); -int initkre(void); -int initmbufs(void); -int initnetstat(void); -int initpigs(void); -int initsensors(void); -int initswap(void); -void keyboard(void); -int kvm_ckread(void *, void *, size_t); -void labelifstat(void); -void labeliostat(void); -void labelkre(void); -void labelmbufs(void); -void labelnetstat(void); -void labelpigs(void); -void labels(void); -void labelsensors(void); -void labelswap(void); -void load(void); -int netcmd(char *, char *); -void nlisterr(struct nlist []); -WINDOW *openifstat(void); -WINDOW *openiostat(void); -WINDOW *openkre(void); -WINDOW *openmbufs(void); -WINDOW *opennetstat(void); -WINDOW *openpigs(void); -WINDOW *opensensors(void); -WINDOW *openswap(void); -int prefix(char *, char *); -void sigwinch(int); -void showifstat(void); -void showiostat(void); -void showkre(void); -void showmbufs(void); -void shownetstat(void); -void showpigs(void); -void showsensors(void); -void showswap(void); -void status(void); -void gethz(void); - -extern volatile sig_atomic_t gotdie; -extern volatile sig_atomic_t gotdisplay; -extern volatile sig_atomic_t gotwinch; -extern volatile sig_atomic_t gottstp; - -extern double dellave; -extern WINDOW *wload; diff --git a/usr.bin/systat/fetch.c b/usr.bin/systat/fetch.c index ce0cd54871d..e69de29bb2d 100644 --- a/usr.bin/systat/fetch.c +++ b/usr.bin/systat/fetch.c @@ -1,54 +0,0 @@ -/* $OpenBSD: fetch.c,v 1.8 2006/03/31 04:10:59 deraadt Exp $ */ -/* $NetBSD: fetch.c,v 1.2 1995/01/20 08:51:56 jtc Exp $ */ - -/*- - * Copyright (c) 1980, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)fetch.c 8.1 (Berkeley) 6/6/93"; -#endif -static char rcsid[] = "$OpenBSD: fetch.c,v 1.8 2006/03/31 04:10:59 deraadt Exp $"; -#endif /* not lint */ - -#include <sys/types.h> -#include <signal.h> -#include "systat.h" -#include "extern.h" - -int -kvm_ckread(void *a, void *b, size_t l) -{ - if (kvm_read(kd, (u_long)a, b, l) != l) { - if (verbose) - error("error reading kmem at %x\n", a); - return (0); - } else - return (1); -} diff --git a/usr.bin/systat/if.c b/usr.bin/systat/if.c index ce56da5c5d1..2e56471f68f 100644 --- a/usr.bin/systat/if.c +++ b/usr.bin/systat/if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if.c,v 1.11 2007/09/05 20:31:34 mk Exp $ */ +/* $OpenBSD: if.c,v 1.12 2008/06/12 22:26:01 canacar Exp $ */ /* * Copyright (c) 2004 Markus Friedl <markus@openbsd.org> * @@ -26,7 +26,6 @@ #include <string.h> #include "systat.h" -#include "extern.h" static enum state { BOOT, TIME, RUN } state = TIME; @@ -50,32 +49,73 @@ struct ifstat { } *ifstats; static int nifs = 0; +static int num_ifs = 0; -const char *showlinkstate(int); +void print_if(void); +int read_if(void); +int select_if(void); +int if_keyboard_callback(int); -WINDOW * -openifstat(void) -{ +static void fetchifstat(void); +static void showifstat(struct ifstat *); +static void showtotal(void); - return (subwin(stdscr, LINES-1-1, 0, 1, 0)); -} -void -closeifstat(WINDOW *w) -{ +/* Define fields */ +field_def fields_if[] = { + {"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"STATE", 10, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"IPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"IBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"IERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"OPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"OBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"OERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"COLLS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, +}; + + +#define FIELD_ADDR(x) (&fields_if[x]) + +#define FLD_IF_IFACE FIELD_ADDR(0) +#define FLD_IF_STATE FIELD_ADDR(1) +#define FLD_IF_IPKTS FIELD_ADDR(2) +#define FLD_IF_IBYTES FIELD_ADDR(3) +#define FLD_IF_IERRS FIELD_ADDR(4) +#define FLD_IF_OPKTS FIELD_ADDR(5) +#define FLD_IF_OBYTES FIELD_ADDR(6) +#define FLD_IF_OERRS FIELD_ADDR(7) +#define FLD_IF_COLLS FIELD_ADDR(8) + + +/* Define views */ +field_def *view_if_0[] = { + FLD_IF_IFACE, FLD_IF_STATE, FLD_IF_IPKTS, FLD_IF_IBYTES, + FLD_IF_IERRS, FLD_IF_OPKTS, FLD_IF_OBYTES, FLD_IF_OERRS, + FLD_IF_COLLS, NULL +}; + +/* Define view managers */ + +struct view_manager ifstat_mgr = { + "Ifstat", select_if, read_if, NULL, print_header, + print_if, if_keyboard_callback, NULL, NULL +}; + +field_view views_if[] = { + {view_if_0, "ifstat", '1', &ifstat_mgr}, + {NULL, NULL, 0, NULL} +}; - if (w == NULL) - return; - wclear(w); - wrefresh(w); - delwin(w); -} int initifstat(void) { + field_view *v; + read_if(); + for (v = views_if; v->name != NULL; v++) + add_view(v); - fetchifstat(); return(1); } @@ -105,7 +145,45 @@ rt_getaddrinfo(struct sockaddr *sa, int addrs, struct sockaddr **info) } } + + +int +select_if(void) +{ + num_disp = num_ifs + 1; + return (0); +} + +int +read_if(void) +{ + fetchifstat(); + num_disp = num_ifs + 1; + + return 0; +} + void +print_if(void) +{ + int n, i, count = 0; + + for (n = 0, i = 0; n < nifs; n++) { + if (ifstats[n].ifs_name[0] == '\0') + continue; + if (i++ < dispstart) + continue; + if (i == num_disp) + break; + showifstat(ifstats + n); + if (maxprint > 0 && ++count >= maxprint) + return; + } + showtotal(); +} + + +static void fetchifstat(void) { struct ifstat *newstats, *ifs; @@ -133,6 +211,7 @@ fetchifstat(void) } bzero(&sum, sizeof(sum)); + num_ifs = 0; lim = buf + need; for (next = buf; next < lim; next += ifm.ifm_msglen) { @@ -141,12 +220,12 @@ fetchifstat(void) !(ifm.ifm_addrs & RTA_IFP)) continue; if (ifm.ifm_index >= nifs) { - if ((newstats = realloc(ifstats, (ifm.ifm_index + 4) * - sizeof(struct ifstat))) == NULL) + if ((newstats = realloc(ifstats, (ifm.ifm_index + 4) + * sizeof(struct ifstat))) == NULL) continue; ifstats = newstats; for (; nifs < ifm.ifm_index + 4; nifs++) - ifstats[nifs].ifs_name[0] = '\0'; + bzero(&ifstats[nifs], sizeof(*ifstats)); } ifs = &ifstats[ifm.ifm_index]; if (ifs->ifs_name[0] == '\0') { @@ -165,6 +244,7 @@ fetchifstat(void) if (ifs->ifs_name[0] == '\0') continue; } + num_ifs++; UPDATE(ifc_ip, ifm_data.ifi_ipackets); UPDATE(ifc_ib, ifm_data.ifi_ibytes); UPDATE(ifc_ie, ifm_data.ifi_ierrors); @@ -178,107 +258,88 @@ fetchifstat(void) free(buf); } -#define INSET 0 -void -labelifstat(void) +static void +showifstat(struct ifstat *ifs) { + print_fld_str(FLD_IF_IFACE, ifs->ifs_name); - wmove(wnd, 0, 0); - wclrtobot(wnd); - - mvwaddstr(wnd, 1, INSET, "Iface"); - mvwaddstr(wnd, 1, INSET+9, "State"); - mvwaddstr(wnd, 1, INSET+19, "Ibytes"); - mvwaddstr(wnd, 1, INSET+29, "Ipkts"); - mvwaddstr(wnd, 1, INSET+36, "Ierrs"); - mvwaddstr(wnd, 1, INSET+48, "Obytes"); - mvwaddstr(wnd, 1, INSET+58, "Opkts"); - mvwaddstr(wnd, 1, INSET+65, "Oerrs"); - mvwaddstr(wnd, 1, INSET+74, "Colls"); -} - -#define FMT "%-8.8s %2s%2s %10llu %8llu %6llu %10llu %8llu %6llu %6llu " + tb_start(); + tbprintf("%s", ifs->ifs_cur.ifc_flags & IFF_UP ? + "up" : "dn"); -const char * -showlinkstate(int state) -{ - switch (state) { + switch (ifs->ifs_cur.ifc_state) { case LINK_STATE_UP: case LINK_STATE_HALF_DUPLEX: case LINK_STATE_FULL_DUPLEX: - return (":U"); + tbprintf(":U"); + break; case LINK_STATE_DOWN: - return (":D"); - case LINK_STATE_UNKNOWN: - default: - return (""); + tbprintf (":D"); + break; } + + print_fld_tb(FLD_IF_STATE); + + print_fld_size(FLD_IF_IBYTES, ifs->ifs_cur.ifc_ib); + print_fld_size(FLD_IF_IPKTS, ifs->ifs_cur.ifc_ip); + print_fld_size(FLD_IF_IERRS, ifs->ifs_cur.ifc_ie); + + print_fld_size(FLD_IF_OBYTES, ifs->ifs_cur.ifc_ob); + print_fld_size(FLD_IF_OPKTS, ifs->ifs_cur.ifc_op); + print_fld_size(FLD_IF_OERRS, ifs->ifs_cur.ifc_oe); + + print_fld_size(FLD_IF_COLLS, ifs->ifs_cur.ifc_co); + + end_line(); } -void -showifstat(void) +static void +showtotal(void) { - int row; - struct ifstat *ifs; + print_fld_str(FLD_IF_IFACE, "Totals"); + + print_fld_size(FLD_IF_IBYTES, sum.ifc_ib); + print_fld_size(FLD_IF_IPKTS, sum.ifc_ip); + print_fld_size(FLD_IF_IERRS, sum.ifc_ie); + + print_fld_size(FLD_IF_OBYTES, sum.ifc_ob); + print_fld_size(FLD_IF_OPKTS, sum.ifc_op); + print_fld_size(FLD_IF_OERRS, sum.ifc_oe); + + print_fld_size(FLD_IF_COLLS, sum.ifc_co); + + end_line(); - row = 2; - wmove(wnd, 0, 0); - wclrtoeol(wnd); - for (ifs = ifstats; ifs < ifstats + nifs; ifs++) { - if (ifs->ifs_name[0] == '\0') - continue; - mvwprintw(wnd, row++, INSET, FMT, - ifs->ifs_name, - ifs->ifs_cur.ifc_flags & IFF_UP ? "up" : "dn", - showlinkstate(ifs->ifs_cur.ifc_state), - ifs->ifs_cur.ifc_ib, - ifs->ifs_cur.ifc_ip, - ifs->ifs_cur.ifc_ie, - ifs->ifs_cur.ifc_ob, - ifs->ifs_cur.ifc_op, - ifs->ifs_cur.ifc_oe, - ifs->ifs_cur.ifc_co); - } - mvwprintw(wnd, row++, INSET, FMT, - "Totals", - "", "", - sum.ifc_ib, - sum.ifc_ip, - sum.ifc_ie, - sum.ifc_ob, - sum.ifc_op, - sum.ifc_oe, - sum.ifc_co); } int -cmdifstat(char *cmd, char *args) +if_keyboard_callback(int ch) { struct ifstat *ifs; - if (prefix(cmd, "run")) { - if (state != RUN) - for (ifs = ifstats; ifs < ifstats + nifs; ifs++) - ifs->ifs_old = ifs->ifs_now; + switch (ch) { + case 'r': + for (ifs = ifstats; ifs < ifstats + nifs; ifs++) + ifs->ifs_old = ifs->ifs_now; state = RUN; - return (1); - } - if (prefix(cmd, "boot")) { + gotsig_alarm = 1; + + break; + case 'b': state = BOOT; for (ifs = ifstats; ifs < ifstats + nifs; ifs++) bzero(&ifs->ifs_old, sizeof(ifs->ifs_old)); - return (1); - } - if (prefix(cmd, "time")) { + gotsig_alarm = 1; + break; + case 't': state = TIME; - return (1); - } - if (prefix(cmd, "zero")) { - if (state == RUN) - for (ifs = ifstats; ifs < ifstats + nifs; ifs++) - ifs->ifs_old = ifs->ifs_now; - return (1); - } - return (1); + gotsig_alarm = 1; + break; + default: + return keyboard_callback(ch); + }; + + return 1; } + diff --git a/usr.bin/systat/iostat.c b/usr.bin/systat/iostat.c index dde4cbcc93d..da2b7b1f973 100644 --- a/usr.bin/systat/iostat.c +++ b/usr.bin/systat/iostat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: iostat.c,v 1.29 2008/06/12 17:53:49 beck Exp $ */ +/* $OpenBSD: iostat.c,v 1.30 2008/06/12 22:26:01 canacar Exp $ */ /* $NetBSD: iostat.c,v 1.5 1996/05/10 23:16:35 thorpej Exp $ */ /* @@ -30,13 +30,6 @@ * SUCH DAMAGE. */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; -#endif -static char rcsid[] = "$OpenBSD: iostat.c,v 1.29 2008/06/12 17:53:49 beck Exp $"; -#endif /* not lint */ - #include <sys/param.h> #include <sys/dkstat.h> #include <sys/buf.h> @@ -48,7 +41,6 @@ static char rcsid[] = "$OpenBSD: iostat.c,v 1.29 2008/06/12 17:53:49 beck Exp $" #include <stdlib.h> #include <paths.h> #include "systat.h" -#include "extern.h" #include "dkstats.h" extern struct _disk cur, last; @@ -56,158 +48,150 @@ struct bcachestats bclast, bccur; static double etime; -static void numlabels(void); +void showtotal(void); +void showdrive(int); +void print_io(void); +int read_io(void); +int select_io(void); +void showbcache(void); #define ATIME(x,y) ((double)x[y].tv_sec + \ ((double)x[y].tv_usec / (double)1000000)) -#define NFMT "%-6.6s %8.0f %8.0f %6.0f %6.0f %4.1f" -#define SFMT "%-6.6s %8s %8s %6s %6s %4s" -#define BCSCOL 50 -WINDOW * -openiostat(void) -{ - bzero(&bccur, sizeof(bccur)); - return (subwin(stdscr, LINES-1-1, 0, 1, 0)); -} +field_def fields_io[] = { + {"DEVICE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"READ", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"WRITE", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"RTPS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"WTPS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"SEC", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"", 8, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"STATS", 12, 15, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0} +}; + +#define FIELD_ADDR(x) (&fields_io[x]) + +#define FLD_IO_DEVICE FIELD_ADDR(0) +#define FLD_IO_READ FIELD_ADDR(1) +#define FLD_IO_WRITE FIELD_ADDR(2) +#define FLD_IO_RTPS FIELD_ADDR(3) +#define FLD_IO_WTPS FIELD_ADDR(4) +#define FLD_IO_SEC FIELD_ADDR(5) + +/* This is a hack that stuffs bcache statistics to the last two columns! */ +#define FLD_IO_SVAL FIELD_ADDR(6) +#define FLD_IO_SSTR FIELD_ADDR(7) + +/* Define views */ +field_def *view_io_0[] = { + FLD_IO_DEVICE, FLD_IO_READ, FLD_IO_WRITE, FLD_IO_RTPS, + FLD_IO_WTPS, FLD_IO_SEC, FLD_IO_SVAL, FLD_IO_SSTR, NULL +}; + + +/* Define view managers */ +struct view_manager iostat_mgr = { + "Iostat", select_io, read_io, NULL, print_header, + print_io, keyboard_callback, NULL, NULL +}; + + +field_view views_io[] = { + {view_io_0, "iostat", '2', &iostat_mgr}, + {NULL, NULL, 0, NULL} +}; -void -closeiostat(WINDOW *w) -{ - if (w == NULL) - return; - wclear(w); - wrefresh(w); - delwin(w); -} int -initiostat(void) +select_io(void) { - dkinit(1); - dkreadstats(); - return (1); + num_disp = cur.dk_ndrive + 1; + return (0); } -void -fetchiostat(void) +int +read_io(void) { int mib[3]; size_t size; - if (cur.dk_ndrive == 0) - return; dkreadstats(); + dkswap(); + num_disp = cur.dk_ndrive + 1; bclast = bccur; mib[0] = CTL_VFS; mib[1] = VFS_GENERIC; mib[2] = VFS_BCACHESTAT; size = sizeof(bccur); + if (sysctl(mib, 3, &bccur, &size, NULL, 0) < 0) - mvwaddstr(wnd, 20, 0, "cannot get vfs.bcachestat"); + error("cannot get vfs.bcachestat"); + if (bclast.numbufs == 0) bclast = bccur; -} -void -labeliostat(void) -{ - mvwprintw(wnd, 1, 0, SFMT, "Device", "rKBytes", "wKBytes", "rtps", - "wtps", "sec"); - mvwprintw(wnd, 1, BCSCOL + 16, "numbufs"); - mvwprintw(wnd, 2, BCSCOL + 16, "freebufs"); - mvwprintw(wnd, 3, BCSCOL + 16, "numbufpages"); - mvwprintw(wnd, 4, BCSCOL + 16, "numfreepages"); - mvwprintw(wnd, 5, BCSCOL + 16, "numdirtypages"); - mvwprintw(wnd, 6, BCSCOL + 16, "numcleanpages"); - mvwprintw(wnd, 7, BCSCOL + 16, "pendingwrites"); - mvwprintw(wnd, 8, BCSCOL + 16, "pendingreads"); - mvwprintw(wnd, 9, BCSCOL + 16, "numwrites"); - mvwprintw(wnd, 10, BCSCOL + 16, "numreads"); - mvwprintw(wnd, 11, BCSCOL + 16, "cachehits"); + return 0; } + void -showiostat(void) +print_io(void) { - int i; + int n, count = 0; - dkswap(); + int i, curr; etime = 0.0; - for (i = 0; i < CPUSTATES; i++) { + for (i = 0; i < CPUSTATES; i++) etime += cur.cp_time[i]; - } if (etime == 0.0) etime = 1.0; etime /= (float) hz; - if (last.dk_ndrive != cur.dk_ndrive) - labeliostat(); - - if (cur.dk_ndrive == 0) - return; - - numlabels(); - - mvwprintw(wnd, 1, BCSCOL, "%15ld", bccur.numbufs); - mvwprintw(wnd, 2, BCSCOL, "%15ld", bccur.freebufs); - mvwprintw(wnd, 3, BCSCOL, "%15ld", bccur.numbufpages); - if (bccur.numfreepages) - mvwprintw(wnd, 4, BCSCOL, "%15ld", bccur.numfreepages); - else - mvwprintw(wnd, 4, BCSCOL, "%15s", ""); - if (bccur.numdirtypages) - mvwprintw(wnd, 5, BCSCOL, "%15ld", bccur.numdirtypages); - else - mvwprintw(wnd, 5, BCSCOL, "%15s", ""); - if (bccur.numcleanpages) - mvwprintw(wnd, 6, BCSCOL, "%15ld", bccur.numcleanpages); - else - mvwprintw(wnd, 6, BCSCOL, "%15s", ""); - if (bccur.pendingwrites) - mvwprintw(wnd, 7, BCSCOL, "%15ld", bccur.pendingwrites); - else - mvwprintw(wnd, 7, BCSCOL, "%15s", ""); - if (bccur.pendingreads) - mvwprintw(wnd, 8, BCSCOL, "%15ld", bccur.pendingreads); - else - mvwprintw(wnd, 8, BCSCOL, "%15s", ""); - if (bccur.numwrites - bclast.numwrites) - mvwprintw(wnd, 9, BCSCOL, "%15ld", - bccur.numwrites - bclast.numwrites); - else - mvwprintw(wnd, 9, BCSCOL, "%15s", ""); - if (bccur.numreads - bclast.numreads) - mvwprintw(wnd, 10, BCSCOL, "%15ld", - bccur.numreads - bclast.numreads); - else - mvwprintw(wnd, 10, BCSCOL, "%15s", ""); - if (bccur.cachehits - bclast.cachehits) - mvwprintw(wnd, 11, BCSCOL, "%15ld", - bccur.cachehits - bclast.cachehits); - else - mvwprintw(wnd, 11, BCSCOL, "%15s", ""); + + /* XXX engine internals: save and restore curr_line for bcache */ + curr = curr_line; + + for (n = dispstart; n < num_disp - 1; n++) { + showdrive(n); + count++; + if (maxprint > 0 && count >= maxprint) + break; + } + + + if (maxprint == 0 || count < maxprint) + showtotal(); + + curr_line = curr; + showbcache(); } -void -numlabels(void) +int +initiostat(void) { - double rsum, wsum, rtsum, wtsum, mssum; - int row, dn; + field_view *v; - row = 2; - wmove(wnd, 0, 0); - wclrtoeol(wnd); + dkinit(1); + dkreadstats(); - if (cur.dk_ndrive == 0) { - mvwaddstr(wnd, row, 0, "No drives attached."); - return; - } + bzero(&bccur, sizeof(bccur)); + + for (v = views_io; v->name != NULL; v++) + add_view(v); + + return(1); +} + +void +showtotal(void) +{ + double rsum, wsum, rtsum, wtsum, mssum; + int dn; rsum = wsum = rtsum = wtsum = mssum = 0.0; @@ -217,23 +201,84 @@ numlabels(void) rtsum += cur.dk_rxfer[dn] / etime; wtsum += cur.dk_wxfer[dn] / etime; mssum += ATIME(cur.dk_time, dn) / etime; - mvwprintw(wnd, row++, 0, NFMT, - cur.dk_name[dn], - cur.dk_rbytes[dn] / 1024.0 / etime, - cur.dk_wbytes[dn] / 1024.0 / etime, - cur.dk_rxfer[dn] / etime, - cur.dk_wxfer[dn] / etime, - ATIME(cur.dk_time, dn) / etime); } - mvwprintw(wnd, row++, 0, NFMT, - "Totals", rsum / 1024.0, wsum / 1024.0, rtsum, wtsum, mssum); + + print_fld_str(FLD_IO_DEVICE, "Totals"); + print_fld_size(FLD_IO_READ, rsum); + print_fld_size(FLD_IO_WRITE, wsum); + print_fld_size(FLD_IO_RTPS, rtsum); + print_fld_size(FLD_IO_WTPS, wtsum); + print_fld_size(FLD_IO_SEC, mssum); + + end_line(); } -int -cmdiostat(char *cmd, char *args) +void +showdrive(int dn) { - wclear(wnd); - labeliostat(); - refresh(); - return (1); + print_fld_str(FLD_IO_DEVICE, cur.dk_name[dn]); + print_fld_size(FLD_IO_READ, cur.dk_rbytes[dn]/etime); + print_fld_size(FLD_IO_WRITE, cur.dk_wbytes[dn]/ etime); + print_fld_size(FLD_IO_RTPS, cur.dk_rxfer[dn] / etime); + print_fld_size(FLD_IO_WTPS, cur.dk_wxfer[dn] / etime); + print_fld_size(FLD_IO_SEC, ATIME(cur.dk_time, dn) / etime); + + end_line(); +} + + +#define ENDLINE do { \ + count++; \ + if (maxprint > 0 && count >= maxprint) \ + return; \ + } while(0) + +void +showbcache(void) +{ + int count = 0; + + print_fld_str(FLD_IO_SSTR, "numbufs"); + print_fld_size(FLD_IO_SVAL, bccur.numbufs); + end_line(); + + print_fld_str(FLD_IO_SSTR, "freebufs"); + print_fld_size(FLD_IO_SVAL, bccur.freebufs); + end_line(); + + print_fld_str(FLD_IO_SSTR, "numbufpages"); + print_fld_size(FLD_IO_SVAL, bccur.numbufpages); + end_line(); + + print_fld_str(FLD_IO_SSTR, "numfreepages"); + print_fld_size(FLD_IO_SVAL, bccur.numfreepages); + end_line(); + + print_fld_str(FLD_IO_SSTR, "numdirtypages"); + print_fld_size(FLD_IO_SVAL, bccur.numdirtypages); + end_line(); + + print_fld_str(FLD_IO_SSTR, "numcleanpages"); + print_fld_size(FLD_IO_SVAL, bccur.numcleanpages); + end_line(); + + print_fld_str(FLD_IO_SSTR, "pendingwrites"); + print_fld_size(FLD_IO_SVAL, bccur.pendingwrites); + end_line(); + + print_fld_str(FLD_IO_SSTR, "pendingreads"); + print_fld_size(FLD_IO_SVAL, bccur.pendingreads); + end_line(); + + print_fld_str(FLD_IO_SSTR, "numwrites"); + print_fld_size(FLD_IO_SVAL, bccur.numwrites - bclast.numwrites); + end_line(); + + print_fld_str(FLD_IO_SSTR, "numreads"); + print_fld_size(FLD_IO_SVAL, bccur.numreads - bclast.numreads); + end_line(); + + print_fld_str(FLD_IO_SSTR, "cachehits"); + print_fld_size(FLD_IO_SVAL, bccur.cachehits - bclast.cachehits); + end_line(); } diff --git a/usr.bin/systat/keyboard.c b/usr.bin/systat/keyboard.c index 03b85760af2..e69de29bb2d 100644 --- a/usr.bin/systat/keyboard.c +++ b/usr.bin/systat/keyboard.c @@ -1,165 +0,0 @@ -/* $OpenBSD: keyboard.c,v 1.19 2007/04/15 16:25:08 matthieu Exp $ */ -/* $NetBSD: keyboard.c,v 1.2 1995/01/20 08:51:59 jtc Exp $ */ - -/*- - * Copyright (c) 1980, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)keyboard.c 8.1 (Berkeley) 6/6/93"; -#endif -static char rcsid[] = "$OpenBSD: keyboard.c,v 1.19 2007/04/15 16:25:08 matthieu Exp $"; -#endif /* not lint */ - -#include <sys/types.h> -#include <ctype.h> -#include <signal.h> -#include <stdlib.h> -#include <unistd.h> -#include <termios.h> -#include <errno.h> - -#include "systat.h" -#include "extern.h" - -void -keyboard(void) -{ - char line[80]; - sigset_t mask, omask; - int ch, col; - - for (;;) { - col = 0; - move(CMDLINE, 0); - do { - if (gottstp) { - endwin(); - signal(SIGTSTP, SIG_DFL); - kill(getpid(), SIGTSTP); - signal(SIGTSTP, sigtstp); - siginterrupt(SIGTSTP, 1); - gotwinch = 1; - gottstp = 0; - } - if (gotdisplay) { - display(); - gotdisplay = 0; - } - if (gotdie) { - die(); - } - if (gotwinch) { - clearok(curscr, TRUE); - wrefresh(curscr); - gotwinch = 0; - } - - refresh(); - if ((ch = getch()) == ERR) { - if (errno == EINTR) - continue; - exit(1); - } - ch &= 0177; - if (ch == 0177 && ferror(stdin)) { - clearerr(stdin); - continue; - } - if (ch >= 'A' && ch <= 'Z') - ch += 'a' - 'A'; - if (col == 0) { - switch (ch) { - case CTRL('l'): - case CTRL('g'): - sigemptyset(&mask); - sigaddset(&mask, SIGALRM); - sigprocmask(SIG_BLOCK, &mask, &omask); - if (ch == CTRL('l')) - wrefresh(curscr); - else - status(); - sigprocmask(SIG_SETMASK, &omask, NULL); - continue; - case ':': - break; - case 'q': - gotdie=1; - break; - default: - continue; - } - move(CMDLINE, 0); - clrtoeol(); - } - if (ch == erasechar() && col > 0) { - if (col == 1 && line[0] == ':') - continue; - col--; - goto doerase; - } - if (ch == CTRL('w') && col > 0) { - while (--col >= 0 && isspace(line[col])) - ; - col++; - while (--col >= 0 && !isspace(line[col])) - if (col == 0 && line[0] == ':') - break; - col++; - goto doerase; - } - if (ch == killchar() && col > 0) { - col = 0; - if (line[0] == ':') - col++; - doerase: - move(CMDLINE, col); - clrtoeol(); - continue; - } - if (col >= sizeof(line) - 1) { - /* line too long */ - beep(); - continue; - } - if (isprint(ch) || ch == ' ') { - line[col] = ch; - mvaddch(CMDLINE, col, (chtype)ch); - col++; - } - } while (col == 0 || (ch != '\r' && ch != '\n')); - line[col] = '\0'; - sigemptyset(&mask); - sigaddset(&mask, SIGALRM); - sigprocmask(SIG_BLOCK, &mask, &omask); - command(line + 1); - sigprocmask(SIG_SETMASK, &omask, NULL); - } - /*NOTREACHED*/ -} diff --git a/usr.bin/systat/main.c b/usr.bin/systat/main.c index 5676b83235b..3896455ab82 100644 --- a/usr.bin/systat/main.c +++ b/usr.bin/systat/main.c @@ -1,65 +1,57 @@ -/* $OpenBSD: main.c,v 1.37 2007/05/21 21:15:37 cnst Exp $ */ -/* $NetBSD: main.c,v 1.8 1996/05/10 23:16:36 thorpej Exp $ */ - -/*- - * Copyright (c) 1980, 1992, 1993 - * The Regents of the University of California. All rights reserved. +/* $Id: main.c,v 1.38 2008/06/12 22:26:01 canacar Exp $ */ +/* + * Copyright (c) 2001, 2007 Can Erkin Acar + * Copyright (c) 2001 Daniel Hartmeier + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * */ -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1980, 1992, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; -#endif -static char rcsid[] = "$OpenBSD: main.c,v 1.37 2007/05/21 21:15:37 cnst Exp $"; -#endif /* not lint */ - +#include <sys/types.h> #include <sys/param.h> #include <sys/sysctl.h> + +#include <ctype.h> +#include <curses.h> #include <err.h> -#include <nlist.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <netdb.h> #include <signal.h> -#include <ctype.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> +#include <stdarg.h> #include <unistd.h> #include <utmp.h> -#include <stdlib.h> -#include <limits.h> -#include <stdarg.h> +#include "engine.h" #include "systat.h" -#include "extern.h" double dellave; @@ -69,300 +61,450 @@ char *memf = NULL; double avenrun[3]; double naptime = 5.0; int verbose = 1; /* to report kvm read errs */ -int nflag = 0; +int nflag = 1; int ut, hz, stathz; char hostname[MAXHOSTNAMELEN]; WINDOW *wnd; int CMDLINE; -WINDOW *wload; /* one line window for load average */ +#define TIMEPOS 55 + +/* command prompt */ + +void cmd_delay(void); +void cmd_count(void); +void cmd_compat(void); + +struct command cm_compat = {"Command", cmd_compat}; +struct command cm_delay = {"Seconds to delay", cmd_delay}; +struct command cm_count = {"Number of lines to display", cmd_count}; -static void usage(void); + +/* display functions */ int -main(int argc, char *argv[]) +print_header(void) { - char errbuf[_POSIX2_LINE_MAX]; - gid_t gid; - int ch; + struct tm *tp; + time_t t; + order_type *ordering; - ut = open(_PATH_UTMP, O_RDONLY); - if (ut < 0) { - error("No utmp"); - exit(1); - } + int start = dispstart + 1; + int end = dispstart + maxprint; - kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); - if (kd == NULL) { - error("%s", errbuf); - exit(1); + if (end > num_disp) + end = num_disp; + + tb_start(); + +#if 0 + if (curr_mgr && curr_mgr->sort_fn != NULL) { + ordering = curr_mgr->order_curr; + if (ordering != NULL) { + tbprintf(", Order: %s", ordering->name); + if (sortdir < 0 && ordering->func != NULL) + tbprintf(" (rev)"); + } } +#endif - gid = getgid(); - if (setresgid(gid, gid, gid) == -1) - err(1, "setresgid"); + getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); + extern int ucount(); + char tbuf[26]; + time_t now; - while ((ch = getopt(argc, argv, "nw:")) != -1) - switch (ch) { - case 'n': - nflag = 1; - break; - case 'w': + time(&now); + strlcpy(tbuf, ctime(&now), sizeof tbuf); + tbprintf(" %d users", ucount()); + tbprintf(" Load %.2f %.2f %.2f", avenrun[0], avenrun[1], avenrun[2]); + if (num_disp && (start > 1 || end != num_disp)) + tbprintf(" (%u-%u of %u)", start, end, num_disp); - naptime = strtod(optarg, NULL); - if (naptime < 0.09 || naptime > 1000.0) - errx(1, "invalid interval: %s", optarg); - break; - default: - usage(); - } - argc -= optind; - argv += optind; + if (paused) + tbprintf(" PAUSED"); - while (argc > 0) { - if (isdigit(argv[0][0])) { - naptime = strtod(argv[0], NULL); - if (naptime < 0.09 || naptime > 1000.0) - naptime = 5.0; - } else { - struct cmdtab *p; - - p = lookup(&argv[0][0]); - if (p == (struct cmdtab *)-1) - errx(1, "ambiguous request: %s", &argv[0][0]); - if (p == 0) - errx(1, "unknown request: %s", &argv[0][0]); - curcmd = p; - } - argc--; - argv++; - } + if (rawmode) + printf("\n\n%s\n", tmp_buf); + else + mvprintw(0, 0, "%s", tmp_buf); - signal(SIGINT, sigdie); - siginterrupt(SIGINT, 1); - signal(SIGQUIT, sigdie); - siginterrupt(SIGQUIT, 1); - signal(SIGTERM, sigdie); - siginterrupt(SIGTERM, 1); - signal(SIGTSTP, sigtstp); - siginterrupt(SIGTSTP, 1); - - /* - * Initialize display. Load average appears in a one line - * window of its own. Current command's display appears in - * an overlapping sub-window of stdscr configured by the display - * routines to minimize update work by curses. - */ - if (initscr() == NULL) { - warnx("couldn't initialize screen"); - exit(0); - } + mvprintw(0, TIMEPOS, "%s", tbuf); - CMDLINE = LINES - 1; - wnd = (*curcmd->c_open)(); - if (wnd == NULL) { - warnx("couldn't initialize display"); - die(); - } - wload = newwin(1, 0, 1, 20); - if (wload == NULL) { - warnx("couldn't set up load average window"); - die(); - } - gethostname(hostname, sizeof (hostname)); - gethz(); - (*curcmd->c_init)(); - curcmd->c_flags |= CF_INIT; - labels(); - - dellave = 0.0; - - signal(SIGALRM, sigdisplay); - siginterrupt(SIGALRM, 1); - signal(SIGWINCH, sigwinch); - siginterrupt(SIGWINCH, 1); - gotdisplay = 1; - noecho(); - crmode(); - keyboard(); - /*NOTREACHED*/ + + return (1); } +/* compatibility functions, rearrange later */ void -gethz(void) +error(const char *fmt, ...) { - struct clockinfo cinf; - size_t size = sizeof(cinf); - int mib[2]; + va_list ap; + char buf[MAX_LINE_BUF]; - mib[0] = CTL_KERN; - mib[1] = KERN_CLOCKRATE; - if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) - return; - stathz = cinf.stathz; - hz = cinf.hz; -} + va_start(ap, fmt); + vsnprintf(buf, sizeof buf, fmt, ap); + va_end(ap); -static void -usage(void) -{ - fprintf(stderr, "usage: systat [-n] [-w wait] [display] [refresh-interval]\n"); - exit(1); + message_set(buf); } - void -labels(void) +nlisterr(struct nlist namelist[]) { - if (curcmd->c_flags & CF_LOADAV) - mvprintw(0, 2 + 4, "users Load"); - (*curcmd->c_label)(); -#ifdef notdef - mvprintw(21, 25, "CPU usage on %s", hostname); -#endif + int i, n; + + n = 0; + clear(); + mvprintw(2, 10, "systat: nlist: can't find following symbols:"); + for (i = 0; + namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++) + if (namelist[i].n_value == 0) + mvprintw(2 + ++n, 10, "%s", namelist[i].n_name); + move(CMDLINE, 0); + clrtoeol(); refresh(); + endwin(); + exit(1); } -/*ARGSUSED*/ void -sigdisplay(int signo) +die(void) { - gotdisplay = 1; + if (!rawmode) + endwin(); + exit(0); } -void -display(void) + +int +prefix(char *s1, char *s2) { - /* Get the load average over the last minute. */ - (void) getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); - (*curcmd->c_fetch)(); - if (curcmd->c_flags & CF_LOADAV) { - extern int ucount(); - char tbuf[26]; - time_t now; - - time(&now); - strlcpy(tbuf, ctime(&now), sizeof tbuf); - - putint(ucount(), 0, 2, 3); - putfloat(avenrun[0], 0, 2 + 17, 6, 2, 0); - putfloat(avenrun[1], 0, 2 + 23, 6, 2, 0); - putfloat(avenrun[2], 0, 2 + 29, 6, 2, 0); - mvaddstr(0, 2 + 53, tbuf); + + while (*s1 == *s2) { + if (*s1 == '\0') + return (1); + s1++, s2++; } - (*curcmd->c_refresh)(); - if (curcmd->c_flags & CF_LOADAV) - wrefresh(wload); - wrefresh(wnd); - move(CMDLINE, 0); - refresh(); - ualarm(naptime * 1000000, 0); + return (*s1 == '\0'); } -void -load(void) +/* calculate number of users on the system */ +int +ucount(void) { + int nusers = 0; + struct utmp utmp; - (void) getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])); - mvprintw(CMDLINE, 0, "%4.1f %4.1f %4.1f", - avenrun[0], avenrun[1], avenrun[2]); - clrtoeol(); + if (ut < 0) + return (0); + lseek(ut, (off_t)0, SEEK_SET); + while (read(ut, &utmp, sizeof(utmp))) + if (utmp.ut_name[0] != '\0') + nusers++; + + return (nusers); } -volatile sig_atomic_t gotdie; -volatile sig_atomic_t gotdisplay; -volatile sig_atomic_t gotwinch; -volatile sig_atomic_t gottstp; +/* main program functions */ -/*ARGSUSED*/ void -sigdie(int signo) +usage() { - gotdie = 1; + extern char *__progname; + fprintf(stderr, "usage: %s [-abhir] [-c cache] [-d cnt]", __progname); + fprintf(stderr, " [-o field] [-s time] [-w width] [view] [num]\n"); + exit(1); } -/*ARGSUSED*/ + void -sigtstp(int signo) +add_view_tb(field_view *v) { - gottstp = 1; + if (curr_view == v) + tbprintf("[%s] ", v->name); + else + tbprintf("%s ", v->name); } void -die(void) +show_help(void) { - if (wnd) { - move(CMDLINE, 0); - clrtoeol(); - refresh(); - endwin(); + int line = 0; + + if (rawmode) + return; + + tb_start(); + foreach_view(add_view_tb); + tb_end(); + message_set(tmp_buf); + +#if 0 + erase(); + mvprintw(line, 2, "Systat Help"); + line += 2; + mvprintw(line, 5, " h - Help (this page)"); + mvprintw(line++, 40, " l - set number of Lines"); + mvprintw(line, 5, " p - Pause display"); + mvprintw(line++, 40, " s - Set update interval"); + mvprintw(line, 5, " v - next View"); + mvprintw(line++, 40, " q - Quit"); + line++; + mvprintw(line++, 5, "0-7 - select view directly"); + mvprintw(line++, 5, "SPC - update immediately"); + mvprintw(line++, 5, "^L - refresh display"); + line++; + mvprintw(line++, 5, "cursor keys - scroll display"); + line++; + mvprintw(line++, 3, "Netstat specific keys::"); + mvprintw(line, 5, " t - toggle TCP display"); + mvprintw(line++, 40, " u - toggle UDP display"); + mvprintw(line++, 5, " n - toggle Name resolution"); + line++; + mvprintw(line++, 3, "Ifstat specific keys::"); + mvprintw(line, 5, " r - initialize RUN mode"); + mvprintw(line++, 40, " b - set BOOT mode"); + mvprintw(line, 5, " t - set TIME mode (default)"); + line++; + line++; + mvprintw(line++, 3, "VMstat specific keys::"); + mvprintw(line, 5, " r - initialize RUN mode"); + mvprintw(line++, 40, " b - set BOOT mode"); + mvprintw(line, 5, " t - set TIME mode (default)"); + mvprintw(line++, 40, " z - zero in RUN mode"); + line++; + mvprintw(line++, 6, "press any key to continue ..."); + + while (getch() == ERR) { + if (gotsig_close) + break; } - exit(0); +#endif } -/*ARGSUSED*/ void -sigwinch(int signo) +cmd_compat(void) { - gotwinch = 1; + char *s; + + if (strcasecmp(cmdbuf, "help") == 0) { + show_help(); + need_update = 1; + return; + } + if (strcasecmp(cmdbuf, "quit") == 0) { + gotsig_close = 1; + return; + } + + for (s = cmdbuf; *s && strchr("0123456789+-.eE", *s) != NULL; s++) + ; + if (*s) { + if (set_view(cmdbuf)) + error("Invalid/ambigious view: %s", cmdbuf); + } else + cmd_delay(); } void -error(const char *fmt, ...) +cmd_delay(void) { - va_list ap; - char buf[255]; - int oy, ox; - - va_start(ap, fmt); - if (wnd) { - getyx(stdscr, oy, ox); - (void) vsnprintf(buf, sizeof buf, fmt, ap); - clrtoeol(); - standout(); - mvaddstr(CMDLINE, 0, buf); - standend(); - move(oy, ox); - refresh(); - } else { - (void) vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); + double del; + del = atof(cmdbuf); + error("delay: %g", del); + if (del > 0) { + udelay = (useconds_t)(del * 1000000); + gotsig_alarm = 1; } - va_end(ap); } void -nlisterr(struct nlist namelist[]) +cmd_count(void) { - int i, n; + int ms; + ms = atoi(cmdbuf); - n = 0; - clear(); - mvprintw(2, 10, "systat: nlist: can't find following symbols:"); - for (i = 0; - namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++) - if (namelist[i].n_value == 0) - mvprintw(2 + ++n, 10, "%s", namelist[i].n_name); - move(CMDLINE, 0); - clrtoeol(); - refresh(); - endwin(); - exit(1); + if (ms <= 0 || ms > lines - HEADER_LINES) + maxprint = lines - HEADER_LINES; + else + maxprint = ms; } -/* calculate number of users on the system */ + int -ucount(void) +keyboard_callback(int ch) { - int nusers = 0; - struct utmp utmp; + switch (ch) { + case '?': + /* FALLTHROUGH */ + case 'h': + show_help(); + need_update = 1; + break; + case 'l': + command_set(&cm_count, NULL); + break; + case 's': + command_set(&cm_delay, NULL); + break; + case ':': + command_set(&cm_compat, NULL); + break; + default: + return 0; + }; + + return 1; +} - if (ut < 0) - return (0); - lseek(ut, (off_t)0, SEEK_SET); - while (read(ut, &utmp, sizeof(utmp))) - if (utmp.ut_name[0] != '\0') - nusers++; +void +initialize(void) +{ + engine_initialize(); + + initvmstat(); + initpigs(); + initifstat(); + initiostat(); + initsensors(); + initmembufs(); + initnetstat(); + initswap(); + initpftop(); + initpf(); +} - return (nusers); +void +gethz(void) +{ + struct clockinfo cinf; + size_t size = sizeof(cinf); + int mib[2]; + + mib[0] = CTL_KERN; + mib[1] = KERN_CLOCKRATE; + if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) + return; + stathz = cinf.stathz; + hz = cinf.hz; +} + +int +main(int argc, char *argv[]) +{ + char errbuf[_POSIX2_LINE_MAX]; + extern char *optarg; + extern int optind; + double delay = 5; + + char *viewstr = NULL; + + gid_t gid; + int countmax = 0; + int maxlines = 0; + + int ch; + + ut = open(_PATH_UTMP, O_RDONLY); + if (ut < 0) { + warn("No utmp"); + } + + kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); + if (kd == NULL) + warnx("kvm_openfiles: %s", errbuf); + + gid = getgid(); + if (setresgid(gid, gid, gid) == -1) + err(1, "setresgid"); + + while ((ch = getopt(argc, argv, "abd:hins:S:w:")) != -1) { + switch (ch) { + case 'a': + maxlines = -1; + break; + case 'b': + rawmode = 1; + interactive = 0; + break; + case 'd': + countmax = atoi(optarg); + if (countmax < 0) + countmax = 0; + break; + case 'i': + interactive = 1; + break; + case 'n': + nflag = 1; + break; + case 's': + delay = atof(optarg); + if (delay < 0) + delay = 5; + break; + case 'S': + dispstart = atoi(optarg); + if (dispstart < 0) + dispstart = 0; + break; + case 'w': + rawwidth = atoi(optarg); + if (rawwidth < 1) + rawwidth = DEFAULT_WIDTH; + if (rawwidth >= MAX_LINE_BUF) + rawwidth = MAX_LINE_BUF - 1; + break; + case 'h': + /* FALLTHROUGH */ + default: + usage(); + /* NOTREACHED */ + } + } + + argc -= optind; + argv += optind; + + if (argc == 1) { + double del = atof(argv[0]); + if (del == 0) + viewstr = argv[0]; + else + delay = del; + } else if (argc == 2) { + viewstr = argv[0]; + delay = atof(argv[1]); + } + + udelay = (useconds_t)(delay * 1000000.0); + if (udelay < 1) + udelay = 1; + + gethostname(hostname, sizeof (hostname)); + gethz(); + + initialize(); + + set_order(NULL); + if (viewstr && set_view(viewstr)) { + fprintf(stderr, "Unknown/ambigious view name: %s\n", viewstr); + return 1; + } + + if (!isatty(STDOUT_FILENO)) { + rawmode = 1; + interactive = 0; + } + + setup_term(maxlines); + + if (rawmode && countmax == 0) + countmax = 1; + + gotsig_alarm = 1; + + engine_loop(countmax); + + return 0; } diff --git a/usr.bin/systat/mbufs.c b/usr.bin/systat/mbufs.c index 357dc9126bf..b947c97489d 100644 --- a/usr.bin/systat/mbufs.c +++ b/usr.bin/systat/mbufs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mbufs.c,v 1.17 2007/02/25 18:21:24 deraadt Exp $ */ +/* $OpenBSD: mbufs.c,v 1.18 2008/06/12 22:26:01 canacar Exp $ */ /* $NetBSD: mbufs.c,v 1.2 1995/01/20 08:52:02 jtc Exp $ */ /*- @@ -30,13 +30,6 @@ * SUCH DAMAGE. */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)mbufs.c 8.1 (Berkeley) 6/6/93"; -#endif -static char rcsid[] = "$OpenBSD: mbufs.c,v 1.17 2007/02/25 18:21:24 deraadt Exp $"; -#endif /* not lint */ - #include <sys/param.h> #include <sys/types.h> #include <sys/mbuf.h> @@ -47,7 +40,12 @@ static char rcsid[] = "$OpenBSD: mbufs.c,v 1.17 2007/02/25 18:21:24 deraadt Exp #include <err.h> #include <paths.h> #include "systat.h" -#include "extern.h" + + +void print_mb(void); +int read_mb(void); +int select_mb(void); +static void showmbuf(int); static struct mbstat mb; @@ -68,85 +66,128 @@ char *mtnames[] = { "ifaddrs", }; +#define NUM_TYPES (sizeof(mb.m_mtypes) / sizeof(mb.m_mtypes[0])) #define NNAMES (sizeof (mtnames) / sizeof (mtnames[0])) -WINDOW * -openmbufs(void) -{ - return (subwin(stdscr, LINES-1-2, 0, 2, 0)); -} +int mb_index[NUM_TYPES]; +int mbuf_cnt = 0; -void -closembufs(WINDOW *w) + +field_def fields_mb[] = { + {"TYPE", 6, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"VALUE", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"", 40, 80, 1, FLD_ALIGN_BAR, -1, 0, 0, 60}, +}; + +#define FIELD_ADDR(x) (&fields_mb[x]) + +#define FLD_MB_NAME FIELD_ADDR(0) +#define FLD_MB_VALUE FIELD_ADDR(1) +#define FLD_MB_BAR FIELD_ADDR(2) + +/* Define views */ +field_def *view_mb_0[] = { + FLD_MB_NAME, FLD_MB_VALUE, FLD_MB_BAR, NULL +}; + + +/* Define view managers */ +struct view_manager mbuf_mgr = { + "Mbufs", select_mb, read_mb, NULL, print_header, + print_mb, keyboard_callback, NULL, NULL +}; + +field_view views_mb[] = { + {view_mb_0, "mbufs", '4', &mbuf_mgr}, + {NULL, NULL, 0, NULL} +}; + + +int +select_mb(void) { - if (w == NULL) - return; - wclear(w); - wrefresh(w); - delwin(w); + int i, w = 50; + + read_mb(); + for (i = 0; i < NUM_TYPES; i++) + if (w < (5 * mb.m_mtypes[i] / 4)) + w = 5 * mb.m_mtypes[i] / 4; + + w -= w % 10; + FLD_MB_BAR->arg = w; + + return (0); } -void -labelmbufs(void) +int +read_mb(void) { - wmove(wnd, 0, 0); - wclrtoeol(wnd); - mvwaddstr(wnd, 0, 10, - "/0 /5 /10 /15 /20 /25 /30 /35 /40 /45 /50 /55 /60"); + int mib[2], i; + size_t size = sizeof (mb); + + mib[0] = CTL_KERN; + mib[1] = KERN_MBSTAT; + + if (sysctl(mib, 2, &mb, &size, NULL, 0) < 0) { + error("sysctl(KERN_MBSTAT) failed"); + return 1; + } + + mbuf_cnt = 0; + memset(mb_index, 0, sizeof(mb_index)); + + for (i = 0; i < NUM_TYPES; i++) { + if (mb.m_mtypes[i]) + mb_index[mbuf_cnt++] = i; + } + + num_disp = mbuf_cnt; + + return 0; } + void -showmbufs(void) +print_mb(void) { - int i, j, max, ind; - char buf[13]; - - for (j = 0; j < wnd->_maxy; j++) { - max = 0, ind = -1; - for (i = 0; i < wnd->_maxy; i++) - if (mb.m_mtypes[i] > max) { - max = mb.m_mtypes[i]; - ind = i; - } - if (max == 0) + int n, count = 0; + + for (n = dispstart; n < num_disp; n++) { + showmbuf(n); + count++; + if (maxprint > 0 && count >= maxprint) break; - if (j > NNAMES) - mvwprintw(wnd, 1+j, 0, "%10d", ind); - else - mvwprintw(wnd, 1+j, 0, "%-10.10s", mtnames[ind]); - wmove(wnd, 1 + j, 10); - if (max > 60) { - snprintf(buf, sizeof buf, " %d", max); - max = 60; - while (max--) - waddch(wnd, 'X'); - waddstr(wnd, buf); - } else { - while (max--) - waddch(wnd, 'X'); - wclrtoeol(wnd); - } - mb.m_mtypes[ind] = 0; } - wmove(wnd, 1+j, 0); - wclrtobot(wnd); } - -void -fetchmbufs(void) +int +initmembufs(void) { - int mib[2]; - size_t size = sizeof (mb); + field_view *v; - mib[0] = CTL_KERN; - mib[1] = KERN_MBSTAT; - if (sysctl(mib, 2, &mb, &size, NULL, 0) < 0) - err(1, "sysctl(KERN_MBSTAT) failed"); + for (v = views_mb; v->name != NULL; v++) + add_view(v); + + return(1); } -int -initmbufs(void) + +static void +showmbuf(int m) { - return (1); + int i; + + i = mb_index[m]; + + if (i < NNAMES) + print_fld_str(FLD_MB_NAME, mtnames[i]); + else + print_fld_uint(FLD_MB_NAME, i); + + print_fld_uint(FLD_MB_VALUE, mb.m_mtypes[i]); + print_fld_bar(FLD_MB_BAR, mb.m_mtypes[i]); + + end_line(); } + + diff --git a/usr.bin/systat/netcmds.c b/usr.bin/systat/netcmds.c index 527b33f87e3..e69de29bb2d 100644 --- a/usr.bin/systat/netcmds.c +++ b/usr.bin/systat/netcmds.c @@ -1,360 +0,0 @@ -/* $OpenBSD: netcmds.c,v 1.19 2007/09/11 15:47:17 gilles Exp $ */ -/* $NetBSD: netcmds.c,v 1.4 1995/05/21 17:14:38 mycroft Exp $ */ - -/*- - * Copyright (c) 1980, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)netcmds.c 8.1 (Berkeley) 6/6/93"; -#endif -static char rcsid[] = "$OpenBSD: netcmds.c,v 1.19 2007/09/11 15:47:17 gilles Exp $"; -#endif /* not lint */ - -/* - * Common network command support routines. - */ -#include <sys/param.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/mbuf.h> -#include <sys/protosw.h> - -#include <net/route.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/in_pcb.h> - -#include <arpa/inet.h> - -#include <errno.h> -#include <netdb.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include "systat.h" -#include "extern.h" - -#define streq(a,b) (strcmp(a,b)==0) - -static struct hitem { - struct sockaddr_storage addr; - int onoff; -} *hosts; - -size_t nports, nhosts; -int protos; - -static void changeitems(char *, int); -static int selectproto(char *); -static void showprotos(void); -static int selectport(long, int); -static void showports(void); -static int addrcmp(struct sockaddr *, struct sockaddr *); -static int selecthost(struct sockaddr *, int); -static void showhosts(void); - -int -netcmd(char *cmd, char *args) -{ - - if (prefix(cmd, "tcp") || prefix(cmd, "udp")) { - selectproto(cmd); - return (1); - } - if (prefix(cmd, "ignore") || prefix(cmd, "display")) { - changeitems(args, prefix(cmd, "display")); - return (1); - } - if (prefix(cmd, "reset")) { - selectproto(0); - selecthost(0, 0); - selectport(htons(-1), 0); - return (1); - } - if (prefix(cmd, "show")) { - move(CMDLINE, 0); - clrtoeol(); - if (*args == '\0') { - showprotos(); - showhosts(); - showports(); - return (1); - } - if (prefix(args, "protos")) - showprotos(); - else if (prefix(args, "hosts")) - showhosts(); - else if (prefix(args, "ports")) - showports(); - else - addstr("show what?"); - return (1); - } - return (0); -} - - -static void -changeitems(char *args, int onoff) -{ - char *cp; - struct servent *sp; - struct addrinfo hints, *res0, *res; - - args[strcspn(args, "\n")] = '\0'; - - for (;;args = cp) { - for (cp = args; isspace(*cp); cp++) - ; - args = cp; - for (; *cp && !isspace(*cp); cp++) - ; - if (*cp) - *cp++ = '\0'; - if (cp - args == 0) - break; - sp = getservbyname(args, - protos == TCP ? "tcp" : protos == UDP ? "udp" : 0); - if (sp) { - selectport(sp->s_port, onoff); - continue; - } - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - if (getaddrinfo(args, "0", &hints, &res0) != 0) { - error("%s: unknown host or port", args); - continue; - } - for (res = res0; res; res = res->ai_next) - selecthost(res->ai_addr, onoff); - freeaddrinfo(res0); - } -} - -static int -selectproto(char *proto) -{ - int new = protos; - - if (proto == 0 || streq(proto, "all")) - new = TCP|UDP; - else if (streq(proto, "tcp")) - new = TCP; - else if (streq(proto, "udp")) - new = UDP; - return (protos = new); -} - -static void -showprotos(void) -{ - - if ((protos&TCP) == 0) - addch('!'); - addstr("tcp "); - if ((protos&UDP) == 0) - addch('!'); - addstr("udp "); -} - -static struct pitem { - long port; - int onoff; -} *ports; - -static int -selectport(long port, int onoff) -{ - struct pitem *p; - - if (ntohs(port) == -1) { - if (ports == 0) - return (0); - free(ports); - ports = NULL; - nports = 0; - return (1); - } - for (p = ports; p < ports+nports; p++) - if (p->port == port) { - p->onoff = onoff; - return (0); - } - if (nports + 1 > SIZE_MAX / sizeof(*p) || - (p = realloc(ports, (nports + 1) * sizeof(*p))) == NULL) { - error("selectport: %s", strerror(ENOMEM)); - die(); - } - ports = p; - - p = &ports[nports++]; - p->port = port; - p->onoff = onoff; - return (1); -} - -int -checkport(struct inpcb *inp) -{ - struct pitem *p; - - if (ports) - for (p = ports; p < ports+nports; p++) - if (p->port == inp->inp_lport || p->port == inp->inp_fport) - return (p->onoff); - return (1); -} - -static void -showports(void) -{ - struct pitem *p; - struct servent *sp; - - for (p = ports; p < ports+nports; p++) { - sp = getservbyport(p->port, - protos == (TCP|UDP) ? 0 : protos == TCP ? "tcp" : "udp"); - if (!p->onoff) - addch('!'); - if (sp) - printw("%s ", sp->s_name); - else - printw("%d ", ntohs(p->port)); - } -} - -static int -addrcmp(struct sockaddr *sa1, struct sockaddr *sa2) -{ - if (sa1->sa_family != sa2->sa_family) - return 0; - if (sa1->sa_len != sa2->sa_len) - return 0; - switch (sa1->sa_family) { - case AF_INET: - if (((struct sockaddr_in *)sa1)->sin_addr.s_addr == - ((struct sockaddr_in *)sa2)->sin_addr.s_addr) - return 1; - break; - case AF_INET6: - if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)sa1)->sin6_addr, - &((struct sockaddr_in6 *)sa2)->sin6_addr)) - return 1; - break; - default: - if (memcmp(sa1, sa2, sa1->sa_len) == 0) - return 1; - break; - } - return 0; -} - -static int -selecthost(struct sockaddr *sa, int onoff) -{ - struct hitem *p; - - if (sa == 0) { - if (hosts == 0) - return (0); - free(hosts); - hosts = NULL; - nhosts = 0; - return (1); - } - for (p = hosts; p < hosts+nhosts; p++) - if (addrcmp((struct sockaddr *)&p->addr, sa)) { - p->onoff = onoff; - return (0); - } - if (sa->sa_len > sizeof(struct sockaddr_storage)) - return (-1); /*XXX*/ - if (nhosts + 1 > SIZE_MAX / sizeof(*p) || - (p = realloc(hosts, (nhosts + 1) * sizeof(*p))) == NULL) { - error("selecthost: %s", strerror(ENOMEM)); - die(); - } - hosts = p; - - p = &hosts[nhosts++]; - memcpy(&p->addr, sa, sa->sa_len); - p->onoff = onoff; - return (1); -} - -int -checkhost(struct inpcb *inp) -{ - struct hitem *p; - - if (hosts) - for (p = hosts; p < hosts+nhosts; p++) { - if (((struct sockaddr *)&p->addr)->sa_family == AF_INET && - !(inp->inp_flags & INP_IPV6)) { - struct sockaddr_in *sin; - sin = (struct sockaddr_in *)&p->addr; - if (sin->sin_addr.s_addr == inp->inp_laddr.s_addr || - sin->sin_addr.s_addr == inp->inp_faddr.s_addr) - return (p->onoff); - } - if (((struct sockaddr *)&p->addr)->sa_family == AF_INET6 && - (inp->inp_flags & INP_IPV6)) { - struct sockaddr_in6 *sin6; - sin6 = (struct sockaddr_in6 *)&p->addr; - if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &inp->inp_laddr6) || - IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &inp->inp_faddr6)) - return (p->onoff); - } - } - return (1); -} - -static void -showhosts(void) -{ - struct hitem *p; - char hbuf[NI_MAXHOST]; - struct sockaddr *sa; - int flags; - - flags = nflag ? NI_NUMERICHOST : 0; - for (p = hosts; p < hosts+nhosts; p++) { - sa = (struct sockaddr *)&p->addr; - if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, - flags) != 0) - strlcpy(hbuf, "(invalid)", sizeof hbuf); - if (!p->onoff) - addch('!'); - printw("%s ", hbuf); - } -} diff --git a/usr.bin/systat/netstat.c b/usr.bin/systat/netstat.c index b4a29e89f12..62052910532 100644 --- a/usr.bin/systat/netstat.c +++ b/usr.bin/systat/netstat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: netstat.c,v 1.30 2007/02/25 18:21:24 deraadt Exp $ */ +/* $OpenBSD: netstat.c,v 1.31 2008/06/12 22:26:01 canacar Exp $ */ /* $NetBSD: netstat.c,v 1.3 1995/06/18 23:53:07 cgd Exp $ */ /*- @@ -30,13 +30,6 @@ * SUCH DAMAGE. */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)netstat.c 8.1 (Berkeley) 6/6/93"; -#endif -static char rcsid[] = "$OpenBSD: netstat.c,v 1.30 2007/02/25 18:21:24 deraadt Exp $"; -#endif /* not lint */ - /* * netstat */ @@ -73,139 +66,214 @@ static char rcsid[] = "$OpenBSD: netstat.c,v 1.30 2007/02/25 18:21:24 deraadt Ex #include <nlist.h> #include <paths.h> #include "systat.h" -#include "extern.h" +#include "engine.h" + +struct netinfo { + union { + struct in_addr nif_laddr; /* local address */ + struct in6_addr nif_laddr6; /* local address */ + } l; + union { + struct in_addr nif_faddr; /* foreign address */ + struct in6_addr nif_faddr6; /* foreign address */ + } f; + char *nif_proto; /* protocol */ + long nif_rcvcc; /* rcv buffer character count */ + long nif_sndcc; /* snd buffer character count */ + short nif_lport; /* local port */ + short nif_fport; /* foreign port */ + short nif_state; /* tcp state */ + short nif_family; +}; + +#define nif_laddr l.nif_laddr +#define nif_laddr6 l.nif_laddr6 +#define nif_faddr f.nif_faddr +#define nif_faddr6 f.nif_faddr6 static void enter(struct inpcb *, struct socket *, int, char *); static const char *inetname(struct in_addr); -static void inetprint(struct in_addr *, int, char *); +static void inetprint(struct in_addr *, int, char *, field_def *); static const char *inet6name(struct in6_addr *); -static void inet6print(struct in6_addr *, int, char *); +static void inet6print(struct in6_addr *, int, char *, field_def *); +static void shownetstat(struct netinfo *p); + +void print_ns(void); +int read_ns(void); +int select_ns(void); +int ns_keyboard_callback(int); #define streq(a,b) (strcmp(a,b)==0) -#define YMAX(w) ((w)->_maxy-1) -WINDOW * -opennetstat(void) -{ - sethostent(1); - setnetent(1); - return (subwin(stdscr, LINES-1-2, 0, 2, 0)); -} +static int aflag = 0; -struct netinfo { - struct netinfo *nif_forw, *nif_prev; - int nif_family; - short nif_line; /* line on screen */ - short nif_seen; /* 0 when not present in list */ - short nif_flags; -#define NIF_LACHG 0x1 /* local address changed */ -#define NIF_FACHG 0x2 /* foreign address changed */ - short nif_state; /* tcp state */ - char *nif_proto; /* protocol */ - struct in_addr nif_laddr; /* local address */ - struct in6_addr nif_laddr6; /* local address */ - long nif_lport; /* local port */ - struct in_addr nif_faddr; /* foreign address */ - struct in6_addr nif_faddr6; /* foreign address */ - long nif_fport; /* foreign port */ - long nif_rcvcc; /* rcv buffer character count */ - long nif_sndcc; /* snd buffer character count */ +static struct nlist namelist[] = { +#define X_TCBTABLE 0 /* no sysctl */ + { "_tcbtable" }, +#define X_UDBTABLE 1 /* no sysctl */ + { "_udbtable" }, + { "" }, }; +#define ADD_ALLOC 1000 -static struct { - struct netinfo *nif_forw, *nif_prev; -} netcb; -static int aflag = 0; -static int lastrow = 1; +int protos; -void -closenetstat(WINDOW *w) +struct netinfo *netinfos = NULL; +size_t num_ns = 0; +static size_t num_alloc = 0; + + +field_def fields_ns[] = { + {"LOCAL ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"FOREIGN ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"PROTO", 4, 9, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"RECV-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"SEND-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"STATE", 5, 11, 6, FLD_ALIGN_LEFT, -1, 0, 0, 0}, +}; + +#define FIELD_ADDR(x) (&fields_ns[x]) + +#define FLD_NS_LOCAL FIELD_ADDR(0) +#define FLD_NS_FOREIGN FIELD_ADDR(1) +#define FLD_NS_PROTO FIELD_ADDR(2) +#define FLD_NS_RECV_Q FIELD_ADDR(3) +#define FLD_NS_SEND_Q FIELD_ADDR(4) +#define FLD_NS_STATE FIELD_ADDR(5) + +/* Define views */ +field_def *view_ns_0[] = { + FLD_NS_LOCAL, FLD_NS_FOREIGN, FLD_NS_PROTO, + FLD_NS_RECV_Q, FLD_NS_SEND_Q, FLD_NS_STATE, NULL +}; + +/* Define view managers */ +struct view_manager netstat_mgr = { + "Netstat", select_ns, read_ns, NULL, print_header, + print_ns, ns_keyboard_callback, NULL, NULL +}; + +field_view views_ns[] = { + {view_ns_0, "netstat", '0', &netstat_mgr}, + {NULL, NULL, 0, NULL} +}; + + + + +struct netinfo * +next_ns(void) +{ + if (num_alloc <= num_ns) { + struct netinfo *ni; + size_t a = num_alloc + ADD_ALLOC; + if (a < num_alloc) + return NULL; + ni = realloc(netinfos, a * sizeof(*ni)); + if (ni == NULL) + return NULL; + netinfos = ni; + num_alloc = a; + } + + return &netinfos[num_ns++]; +} + +static void +enter(struct inpcb *inp, struct socket *so, int state, char *proto) { struct netinfo *p; - endhostent(); - endnetent(); - p = (struct netinfo *)netcb.nif_forw; - while (p != (struct netinfo *)&netcb) { - if (p->nif_line != -1) - lastrow--; - p->nif_line = -1; - p = p->nif_forw; + p = next_ns(); + if (p == NULL) { + error("Out of Memory!"); + return; } - if (w != NULL) { - wclear(w); - wrefresh(w); - delwin(w); + + p->nif_lport = inp->inp_lport; + p->nif_fport = inp->inp_fport; + p->nif_proto = proto; + + if (inp->inp_flags & INP_IPV6) { + p->nif_laddr6 = inp->inp_laddr6; + p->nif_faddr6 = inp->inp_faddr6; + p->nif_family = AF_INET6; + } else { + p->nif_laddr = inp->inp_laddr; + p->nif_faddr = inp->inp_faddr; + p->nif_family = AF_INET; } + + p->nif_rcvcc = so->so_rcv.sb_cc; + p->nif_sndcc = so->so_snd.sb_cc; + p->nif_state = state; } -static struct nlist namelist[] = { -#define X_TCBTABLE 0 /* no sysctl */ - { "_tcbtable" }, -#define X_UDBTABLE 1 /* no sysctl */ - { "_udbtable" }, - { "" }, -}; + +/* netstat callback functions */ int -initnetstat(void) +select_ns(void) { - int ret; + static int init = 0; + if (kd == NULL) { + num_disp = 1; + return (0); + } - if ((ret = kvm_nlist(kd, namelist)) == -1) - errx(1, "%s", kvm_geterr(kd)); - else if (ret) - nlisterr(namelist); - if (namelist[X_TCBTABLE].n_value == 0) { - error("No symbols in namelist"); - return(0); + if (!init) { + sethostent(1); + setnetent(1); + init = 1; } - netcb.nif_forw = netcb.nif_prev = (struct netinfo *)&netcb; - protos = TCP|UDP; - return(1); + + num_disp = num_ns; + return (0); } -void -fetchnetstat(void) +int +read_ns(void) { struct inpcbtable pcbtable; struct inpcb *head, *prev, *next; - struct netinfo *p; struct inpcb inpcb; struct socket sockb; struct tcpcb tcpcb; void *off; int istcp; + if (kd == NULL) { + return (0); + } + + num_ns = 0; + if (namelist[X_TCBTABLE].n_value == 0) - return; - for (p = netcb.nif_forw; p != (struct netinfo *)&netcb; p = p->nif_forw) - p->nif_seen = 0; - if (protos&TCP) { + return 0; + + if (protos & TCP) { off = NPTR(X_TCBTABLE); istcp = 1; - } else if (protos&UDP) { + } else if (protos & UDP) { off = NPTR(X_UDBTABLE); istcp = 0; } else { error("No protocols to display"); - return; + return 0; } + again: KREAD(off, &pcbtable, sizeof (struct inpcbtable)); + prev = head = (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue; next = CIRCLEQ_FIRST(&pcbtable.inpt_queue); + while (next != head) { KREAD(next, &inpcb, sizeof (inpcb)); if (CIRCLEQ_PREV(&inpcb, inp_queue) != prev) { - printf("prev = %p, head = %p, next = %p, inpcb...prev = %p\n", - prev, head, next, CIRCLEQ_PREV(&inpcb, inp_queue)); - p = netcb.nif_forw; - for (; p != (struct netinfo *)&netcb; p = p->nif_forw) - p->nif_seen = 1; error("Kernel state in transition"); - return; + return 0; } prev = next; next = CIRCLEQ_NEXT(&inpcb, inp_queue); @@ -218,10 +286,6 @@ again: IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_laddr6)) continue; } - if (nhosts && !checkhost(&inpcb)) - continue; - if (nports && !checkport(&inpcb)) - continue; KREAD(inpcb.inp_socket, &sockb, sizeof (sockb)); if (istcp) { KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb)); @@ -229,198 +293,97 @@ again: } else enter(&inpcb, &sockb, 0, "udp"); } - if (istcp && (protos&UDP)) { + if (istcp && (protos & UDP)) { istcp = 0; off = NPTR(X_UDBTABLE); goto again; } + + num_disp = num_ns; + return 0; } -static void -enter(struct inpcb *inp, struct socket *so, int state, char *proto) +void +print_ns(void) { - struct netinfo *p; + int n, count = 0; - /* - * Only take exact matches, any sockets with - * previously unbound addresses will be deleted - * below in the display routine because they - * will appear as ``not seen'' in the kernel - * data structures. - */ - for (p = netcb.nif_forw; p != (struct netinfo *)&netcb; p = p->nif_forw) { - if (p->nif_family == AF_INET && (inp->inp_flags & INP_IPV6)) - continue; - if (p->nif_family == AF_INET6 && !(inp->inp_flags & INP_IPV6)) - continue; - if (!streq(proto, p->nif_proto)) - continue; - if (p->nif_family == AF_INET) { - if (p->nif_lport != inp->inp_lport || - p->nif_laddr.s_addr != inp->inp_laddr.s_addr) - continue; - if (p->nif_faddr.s_addr == inp->inp_faddr.s_addr && - p->nif_fport == inp->inp_fport) - break; - - } else if (p->nif_family == AF_INET6) { - if (p->nif_lport != inp->inp_lport || - !IN6_ARE_ADDR_EQUAL(&p->nif_laddr6, &inp->inp_laddr6)) - continue; - if (IN6_ARE_ADDR_EQUAL(&p->nif_faddr6, &inp->inp_faddr6) && - p->nif_fport == inp->inp_fport) - break; - } else - continue; + if (kd == NULL) { + print_fld_str(FLD_NS_LOCAL, "Failed to initialize KVM!"); + print_fld_str(FLD_NS_FOREIGN, "Failed to initialize KVM!"); + end_line(); + return; } - if (p == (struct netinfo *)&netcb) { - if ((p = malloc(sizeof(*p))) == NULL) { - error("Out of memory"); - return; - } - p->nif_prev = (struct netinfo *)&netcb; - p->nif_forw = netcb.nif_forw; - netcb.nif_forw->nif_prev = p; - netcb.nif_forw = p; - p->nif_line = -1; - p->nif_lport = inp->inp_lport; - p->nif_fport = inp->inp_fport; - p->nif_proto = proto; - p->nif_flags = NIF_LACHG|NIF_FACHG; - if (inp->inp_flags & INP_IPV6) { - p->nif_laddr6 = inp->inp_laddr6; - p->nif_faddr6 = inp->inp_faddr6; - p->nif_family = AF_INET6; - } else { - p->nif_laddr = inp->inp_laddr; - p->nif_faddr = inp->inp_faddr; - p->nif_family = AF_INET; - } + + for (n = dispstart; n < num_disp; n++) { + shownetstat(netinfos + n); + count++; + if (maxprint > 0 && count >= maxprint) + break; } - p->nif_rcvcc = so->so_rcv.sb_cc; - p->nif_sndcc = so->so_snd.sb_cc; - p->nif_state = state; - p->nif_seen = 1; } -/* column locations */ -#define LADDR 0 -#define FADDR LADDR+23 -#define PROTO FADDR+23 -#define RCVCC PROTO+6 -#define SNDCC RCVCC+7 -#define STATE SNDCC+7 - -void -labelnetstat(void) +int +initnetstat(void) { - if (namelist[X_TCBTABLE].n_type == 0) - return; - wmove(wnd, 0, 0); - wclrtobot(wnd); - mvwaddstr(wnd, 0, LADDR, "Local Address"); - mvwaddstr(wnd, 0, FADDR, "Foreign Address"); - mvwaddstr(wnd, 0, PROTO, "Proto"); - mvwaddstr(wnd, 0, RCVCC, "Recv-Q"); - mvwaddstr(wnd, 0, SNDCC, "Send-Q"); - mvwaddstr(wnd, 0, STATE, "(state)"); -} + field_view *v; + int ret; -void -shownetstat(void) -{ - struct netinfo *p, *q; - - /* - * First, delete any connections that have gone - * away and adjust the position of connections - * below to reflect the deleted line. - */ - p = netcb.nif_forw; - while (p != (struct netinfo *)&netcb) { - if (p->nif_line == -1 || p->nif_seen) { - p = p->nif_forw; - continue; + if (kd) { + if ((ret = kvm_nlist(kd, namelist)) == -1) + errx(1, "%s", kvm_geterr(kd)); + else if (ret) + nlisterr(namelist); + + if (namelist[X_TCBTABLE].n_value == 0) { + error("No symbols in namelist"); + return(0); } - wmove(wnd, p->nif_line, 0); - wdeleteln(wnd); - q = netcb.nif_forw; - for (; q != (struct netinfo *)&netcb; q = q->nif_forw) - if (q != p && q->nif_line > p->nif_line) { - q->nif_line--; - /* this shouldn't be necessary */ - q->nif_flags |= NIF_LACHG|NIF_FACHG; - } - lastrow--; - q = p->nif_forw; - p->nif_prev->nif_forw = p->nif_forw; - p->nif_forw->nif_prev = p->nif_prev; - free(p); - p = q; } - /* - * Update existing connections and add new ones. - */ - for (p = netcb.nif_forw; p != (struct netinfo *)&netcb; p = p->nif_forw) { - if (p->nif_line == -1) { - /* - * Add a new entry if possible. - */ - if (lastrow > YMAX(wnd)) - continue; - p->nif_line = lastrow++; - p->nif_flags |= NIF_LACHG|NIF_FACHG; - } - if (p->nif_flags & NIF_LACHG) { - wmove(wnd, p->nif_line, LADDR); - switch (p->nif_family) { - case AF_INET: - inetprint(&p->nif_laddr, p->nif_lport, - p->nif_proto); - break; - case AF_INET6: - inet6print(&p->nif_laddr6, p->nif_lport, - p->nif_proto); - break; - } - p->nif_flags &= ~NIF_LACHG; - } - if (p->nif_flags & NIF_FACHG) { - wmove(wnd, p->nif_line, FADDR); - switch (p->nif_family) { - case AF_INET: - inetprint(&p->nif_faddr, p->nif_fport, - p->nif_proto); - break; - case AF_INET6: - inet6print(&p->nif_faddr6, p->nif_fport, - p->nif_proto); - break; - } - p->nif_flags &= ~NIF_FACHG; - } - mvwaddstr(wnd, p->nif_line, PROTO, p->nif_proto); - if (p->nif_family == AF_INET6) - waddstr(wnd, "6"); - mvwprintw(wnd, p->nif_line, RCVCC, "%6d", p->nif_rcvcc); - mvwprintw(wnd, p->nif_line, SNDCC, "%6d", p->nif_sndcc); - if (streq(p->nif_proto, "tcp")) { - if (p->nif_state < 0 || p->nif_state >= TCP_NSTATES) - mvwprintw(wnd, p->nif_line, STATE, "%d", - p->nif_state); - else - mvwaddstr(wnd, p->nif_line, STATE, - tcpstates[p->nif_state]); - } - wclrtoeol(wnd); + protos = TCP|UDP; + + for (v = views_ns; v->name != NULL; v++) + add_view(v); + + return(1); +} + +static void +shownetstat(struct netinfo *p) +{ + switch (p->nif_family) { + case AF_INET: + inetprint(&p->nif_laddr, p->nif_lport, + p->nif_proto, FLD_NS_LOCAL); + inetprint(&p->nif_faddr, p->nif_fport, + p->nif_proto, FLD_NS_FOREIGN); + break; + case AF_INET6: + inet6print(&p->nif_laddr6, p->nif_lport, + p->nif_proto, FLD_NS_LOCAL); + inet6print(&p->nif_faddr6, p->nif_fport, + p->nif_proto, FLD_NS_FOREIGN); + break; } - if (lastrow < YMAX(wnd)) { - wmove(wnd, lastrow, 0); - wclrtobot(wnd); - wmove(wnd, YMAX(wnd), 0); - wdeleteln(wnd); /* XXX */ + + tb_start(); + tbprintf("%s", p->nif_proto); + if (p->nif_family == AF_INET6) + tbprintf("6"); + + print_fld_tb(FLD_NS_PROTO); + + print_fld_size(FLD_NS_RECV_Q, p->nif_rcvcc); + print_fld_size(FLD_NS_SEND_Q, p->nif_sndcc); + + if (streq(p->nif_proto, "tcp")) { + if (p->nif_state < 0 || p->nif_state >= TCP_NSTATES) + print_fld_uint(FLD_NS_STATE, p->nif_state); + else + print_fld_str(FLD_NS_STATE, tcpstates[p->nif_state]); } + end_line(); } /* @@ -428,92 +391,39 @@ shownetstat(void) * If the nflag was specified, use numbers instead of names. */ static void -inetprint(struct in_addr *in, int port, char *proto) +inetprint(struct in_addr *in, int port, char *proto, field_def *fld) { struct servent *sp = 0; - char line[80], *cp; - snprintf(line, sizeof line, "%.*s.", 16, inetname(*in)); - cp = strchr(line, '\0'); + tb_start(); + tbprintf("%s", inetname(*in)); + if (!nflag && port) sp = getservbyport(port, proto); if (sp || port == 0) - snprintf(cp, sizeof line - strlen(cp), "%.8s", - sp ? sp->s_name : "*"); + tbprintf(":%s", sp ? sp->s_name : "*"); else - snprintf(cp, sizeof line - strlen(cp), "%d", - ntohs((u_short)port)); - /* pad to full column to clear any garbage */ - cp = strchr(line, '\0'); - while (cp - line < 22 && cp - line < sizeof line-1) - *cp++ = ' '; - *cp = '\0'; - waddstr(wnd, line); + tbprintf(":%d", ntohs((u_short)port)); + + print_fld_tb(fld); } static void -inet6print(struct in6_addr *in6, int port, char *proto) +inet6print(struct in6_addr *in6, int port, char *proto, field_def *fld) { struct servent *sp = 0; - char line[80], *cp; - snprintf(line, sizeof line, "%.*s.", 16, inet6name(in6)); - cp = strchr(line, '\0'); + tb_start(); + + tbprintf("%s", inet6name(in6)); if (!nflag && port) sp = getservbyport(port, proto); if (sp || port == 0) - snprintf(cp, sizeof line - strlen(cp), "%.8s", - sp ? sp->s_name : "*"); + tbprintf(":%s", sp ? sp->s_name : "*"); else - snprintf(cp, sizeof line - strlen(cp), "%d", - ntohs((u_short)port)); - /* pad to full column to clear any garbage */ - cp = strchr(line, '\0'); - while (cp - line < 22 && cp - line < sizeof line-1) - *cp++ = ' '; - *cp = '\0'; - waddstr(wnd, line); -} + tbprintf(":%d", ntohs((u_short)port)); -/* - * Construct an Internet address representation. - * If the nflag has been supplied, give - * numeric value, otherwise try for symbolic name. - */ -static const char * -inetname(struct in_addr in) -{ - char *cp = 0; - static char line[50]; - struct hostent *hp; - struct netent *np; - - if (!nflag && in.s_addr != INADDR_ANY) { - int net = inet_netof(in); - int lna = inet_lnaof(in); - - if (lna == INADDR_ANY) { - np = getnetbyaddr(net, AF_INET); - if (np) - cp = np->n_name; - } - if (cp == 0) { - hp = gethostbyaddr(&in, sizeof (in), AF_INET); - if (hp) - cp = hp->h_name; - } - } - if (in.s_addr == INADDR_ANY) { - strlcpy(line, "*", sizeof line); - } else if (cp) { - strlcpy(line, cp, sizeof line); - } else { - in.s_addr = ntohl(in.s_addr); -#define C(x) ((x) & 0xff) - snprintf(line, sizeof line, "%u.%u.%u.%u", C(in.s_addr >> 24), - C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); - } - return (line); + print_fld_tb(fld); } static const char * @@ -536,38 +446,65 @@ inet6name(struct in6_addr *in6) return "?"; } -int -cmdnetstat(char *cmd, char *args) +static const char * +inetname(struct in_addr in) { - struct netinfo *p; + static char line[NI_MAXHOST]; + struct sockaddr_in sin; + int flags, e; - if (prefix(cmd, "all")) { - aflag = !aflag; - goto fixup; - } - if (prefix(cmd, "numbers") || prefix(cmd, "names")) { - int new; - - new = prefix(cmd, "numbers"); - if (new == nflag) - return (1); - p = netcb.nif_forw; - for (; p != (struct netinfo *)&netcb; p = p->nif_forw) { - if (p->nif_line == -1) - continue; - p->nif_flags |= NIF_LACHG|NIF_FACHG; - } - nflag = new; - wclear(wnd); - labelnetstat(); - goto redisplay; - } - if (!netcmd(cmd, args)) + flags = nflag ? NI_NUMERICHOST : 0; + if (in.s_addr == INADDR_ANY) + return "*"; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_addr = in; + + e = getnameinfo((struct sockaddr *)&sin, sin.sin_len, + line, sizeof(line), NULL, 0, flags); + + if (e == 0) + return line; + + error("Lookup: %s", gai_strerror(e)); + + return "?"; +} + +int +kvm_ckread(void *a, void *b, size_t l) +{ + if (kvm_read(kd, (u_long)a, b, l) != l) { + if (verbose) + error("error reading kmem at %x\n", a); return (0); -fixup: - fetchnetstat(); -redisplay: - shownetstat(); - refresh(); - return (1); + } else + return (1); +} + + +int +ns_keyboard_callback(int ch) +{ + switch (ch) { + case 'n': + nflag = !nflag; + gotsig_alarm = 1; + break; + case 't': + protos ^= TCP; + gotsig_alarm = 1; + break; + case 'u': + protos ^= UDP; + gotsig_alarm = 1; + break; + default: + return keyboard_callback(ch); + }; + + return 1; } + diff --git a/usr.bin/systat/pf.c b/usr.bin/systat/pf.c new file mode 100644 index 00000000000..1a2e0f9fb9e --- /dev/null +++ b/usr.bin/systat/pf.c @@ -0,0 +1,326 @@ +/* $OpenBSD: pf.c,v 1.1 2008/06/12 22:26:01 canacar Exp $ */ +/* + * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/param.h> +#include <sys/proc.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <netinet/icmp6.h> +#include <net/pfvar.h> +#include <arpa/inet.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <netdb.h> +#include <stdarg.h> +#include <errno.h> +#include <err.h> +#include <ifaddrs.h> +#include <unistd.h> +#include <net/pfvar.h> +#include "pfctl_parser.h" +#include "engine.h" +#include "systat.h" + +void print_pf(void); +int read_pf(void); +int select_pf(void); + +const char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES; +const char *pf_lcounters[LCNT_MAX+1] = LCNT_NAMES; +const char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES; +const char *pf_scounters[FCNT_MAX+1] = FCNT_NAMES; + +static struct pf_status status; +extern int pf_dev; +int num_pf = 0; + +field_def fields_pf[] = { + {"TYPE", 13, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"NAME", 12, 24, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"VALUE", 8, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"RATE", 8, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 60}, + {"NOTES", 10, 20, 1, FLD_ALIGN_LEFT, -1, 0, 0, 60}, +}; + +#define FIELD_ADDR(x) (&fields_pf[x]) + +#define FLD_PF_TYPE FIELD_ADDR(0) +#define FLD_PF_NAME FIELD_ADDR(1) +#define FLD_PF_VALUE FIELD_ADDR(2) +#define FLD_PF_RATE FIELD_ADDR(3) +#define FLD_PF_DESC FIELD_ADDR(4) + +/* Define views */ +field_def *view_pf_0[] = { + FLD_PF_TYPE, FLD_PF_NAME, FLD_PF_VALUE, FLD_PF_RATE, FLD_PF_DESC, NULL +}; + + +/* Define view managers */ +struct view_manager pf_mgr = { + "PF", select_pf, read_pf, NULL, print_header, + print_pf, keyboard_callback, NULL, NULL +}; + +field_view views_pf[] = { + {view_pf_0, "pf", 'P', &pf_mgr}, + {NULL, NULL, 0, NULL} +}; + + + +int +select_pf(void) +{ + return (0); +} + +int +read_pf(void) +{ + if (pf_dev < 0) { + num_disp = 0; + return 0; + } + + if (ioctl(pf_dev, DIOCGETSTATUS, &status)) { + error("DIOCGETSTATUS: %s", strerror(errno)); + return (-1); + } + + num_disp = 4; + + if (status.ifname[0] != 0) + num_disp += 13; + + num_disp += FCNT_MAX + 2; + num_disp += SCNT_MAX + 2; + num_disp += PFRES_MAX + 1; + num_disp += LCNT_MAX + 1; + + return (0); +} + +int +initpf(void) +{ + field_view *v; + + for (v = views_pf; v->name != NULL; v++) + add_view(v); + + return(1); +} + +void +print_fld_double(field_def *fld, double val) +{ + int len; + + if (fld == NULL) + return; + + len = fld->width; + if (len < 1) + return; + + tb_start(); + if (tbprintf("%.2f", val) > len) + print_fld_str(fld, "*"); + else + print_fld_tb(fld); + tb_end(); +} + +#define ADD_LINE_A(t, n, v) \ + do { \ + if (cur >= dispstart && cur < end) { \ + print_fld_str(FLD_PF_TYPE, (t)); \ + print_fld_str(FLD_PF_NAME, (n)); \ + print_fld_age(FLD_PF_VALUE, (v)); \ + end_line(); \ + } \ + if (++cur >= end) \ + return; \ + } while (0) + +#define ADD_EMPTY_LINE \ + do { \ + if (cur >= dispstart && cur < end) \ + end_line(); \ + if (++cur >= end) \ + return; \ + } while (0) + +#define ADD_LINE_S(t, n, v) \ + do { \ + if (cur >= dispstart && cur < end) { \ + print_fld_str(FLD_PF_TYPE, (t)); \ + print_fld_str(FLD_PF_NAME, (n)); \ + print_fld_str(FLD_PF_VALUE, (v)); \ + end_line(); \ + } \ + if (++cur >= end) \ + return; \ + } while (0) + +#define ADD_LINE_V(t, n, v) \ + do { \ + if (cur >= dispstart && cur < end) { \ + print_fld_str(FLD_PF_TYPE, (t)); \ + print_fld_str(FLD_PF_NAME, (n)); \ + print_fld_size(FLD_PF_VALUE, (v)); \ + end_line(); \ + } \ + if (++cur >= end) \ + return; \ + } while (0) + +#define ADD_LINE_VD(t, n, v, d) \ + do { \ + if (cur >= dispstart && cur < end) { \ + print_fld_str(FLD_PF_TYPE, (t)); \ + print_fld_str(FLD_PF_NAME, (n)); \ + print_fld_size(FLD_PF_VALUE, (v)); \ + print_fld_str(FLD_PF_DESC, (d)); \ + end_line(); \ + } \ + if (++cur >= end) \ + return; \ + } while (0) + +#define ADD_LINE_VR(t, n, v, r) \ + do { \ + if (cur >= dispstart && cur < end) { \ + print_fld_str(FLD_PF_TYPE, (t)); \ + print_fld_str(FLD_PF_NAME, (n)); \ + print_fld_size(FLD_PF_VALUE, (v)); \ + print_fld_double(FLD_PF_RATE, (r)); \ + end_line(); \ + } \ + if (++cur >= end) \ + return; \ + } while (0) + + +void +print_pf(void) +{ + char *debug; + time_t tm; + int i; + struct pf_status *s = &status; + + int cur = 0; + int end = dispstart + maxprint; + if (end > num_disp) + end = num_disp; + + tm = time(NULL) - s->since; + + ADD_LINE_S("pf", "Status", s->running ? "Enabled" : "Disabled"); + ADD_LINE_A("pf", "Since", tm); + + switch (s->debug) { + case PF_DEBUG_NONE: + debug = "None"; + break; + case PF_DEBUG_URGENT: + debug = "Urgent"; + break; + case PF_DEBUG_MISC: + debug = "Misc"; + break; + case PF_DEBUG_NOISY: + debug = "Loud"; + break; + } + ADD_LINE_S("pf", "Debug", debug); + + tb_start(); + tbprintf("0x%08x\n", ntohl(s->hostid)); + tb_end(); + + ADD_LINE_S("pf", "Hostid", tmp_buf); + + if (s->ifname[0] != 0) { + ADD_EMPTY_LINE; + ADD_LINE_VD(s->ifname, "Bytes In", s->bcounters[0][0], "IPv4"); + ADD_LINE_VD(s->ifname, "Bytes In", s->bcounters[1][0], "IPv6"); + ADD_LINE_VD(s->ifname, "Bytes Out", s->bcounters[0][1], "IPv4"); + ADD_LINE_VD(s->ifname, "Bytes Out", s->bcounters[1][1], "IPv6"); + ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[0][0][PF_PASS], "IPv4, Passed"); + ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[1][0][PF_PASS], "IPv6, Passed"); + ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[0][0][PF_DROP], "IPv4, Blocked"); + ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[1][0][PF_DROP], "IPv6, Blocked"); + ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[0][1][PF_PASS], "IPv4, Passed"); + ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[1][1][PF_PASS], "IPv6, Passed"); + ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[0][1][PF_DROP], "IPv4, Blocked"); + ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[1][1][PF_DROP], "IPv6, Blocked"); + } + + + ADD_EMPTY_LINE; + ADD_LINE_V("state", "Count", s->states); + + for (i = 0; i < FCNT_MAX; i++) { + if (tm > 0) + ADD_LINE_VR("state", pf_fcounters[i], s->fcounters[i], + (double)s->fcounters[i] / (double)tm); + else + ADD_LINE_V("state", pf_fcounters[i], s->fcounters[i]); + } + + + ADD_EMPTY_LINE; + ADD_LINE_V("src track", "Count", s->src_nodes); + + for (i = 0; i < SCNT_MAX; i++) { + if (tm > 0) + ADD_LINE_VR("src track", pf_scounters[i], s->scounters[i], + (double)s->scounters[i] / (double)tm); + else + ADD_LINE_V("src track", pf_scounters[i], s->scounters[i]); + } + + ADD_EMPTY_LINE; + for (i = 0; i < PFRES_MAX; i++) { + if (tm > 0) + ADD_LINE_VR("counter", pf_reasons[i], s->counters[i], + (double)s->counters[i] / (double)tm); + else + ADD_LINE_V("counter", pf_reasons[i], s->counters[i]); + } + + ADD_EMPTY_LINE; + for (i = 0; i < LCNT_MAX; i++) { + if (tm > 0) + ADD_LINE_VR("limit counter", pf_lcounters[i], s->lcounters[i], + (double)s->lcounters[i] / (double)tm); + else + ADD_LINE_V("limit counter", pf_lcounters[i], s->lcounters[i]); + } +} diff --git a/usr.bin/systat/pftop.c b/usr.bin/systat/pftop.c new file mode 100644 index 00000000000..fdad0e540f7 --- /dev/null +++ b/usr.bin/systat/pftop.c @@ -0,0 +1,2160 @@ +/* $Id: pftop.c,v 1.1 2008/06/12 22:26:01 canacar Exp $ */ +/* + * Copyright (c) 2001, 2007 Can Erkin Acar + * Copyright (c) 2001 Daniel Hartmeier + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/tcp_fsm.h> +#include <net/pfvar.h> +#include <arpa/inet.h> + +#ifdef HAVE_ALTQ +#include <altq/altq.h> +#include <altq/altq_cbq.h> +#include <altq/altq_priq.h> +#include <altq/altq_hfsc.h> +#endif + +#include <ctype.h> +#include <curses.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdarg.h> + +#include "engine.h" +#include "cache.h" + +extern const char *tcpstates[]; + +#define MIN_NUM_STATES 1024 +#define NUM_STATE_INC 1024 + +#define DEFAULT_CACHE_SIZE 10000 + +#ifndef HAVE_PROTO_NAMES +/* UDP state enumeration */ +#define PFUDPS_NSTATES 3 /* number of state levels */ + +#define PFUDPS_NAMES { \ + "NO TRAFFIC", \ + "SINGLE", \ + "MULTIPLE", \ + NULL \ +} + +/* Other protocol state enumeration */ +#define PFOTHERS_NSTATES 3 /* number of state levels */ + +#define PFOTHERS_NAMES { \ + "NO TRAFFIC", \ + "SINGLE", \ + "MULTIPLE", \ + NULL \ +} +#endif + +#ifdef HAVE_ADDR_WRAP +#ifdef HAVE_ADDR_TYPE +/* XXX must also check type before use */ +#define PT_ADDR(x) (&(x)->addr.v.a.addr) +#else +#define PT_ADDR(x) (&(x)->addr.addr) +#endif +#else +#define PT_ADDR(x) (&(x)->addr) +#endif + +#ifdef HAVE_ADDR_MASK +#ifdef HAVE_ADDR_TYPE +/* XXX must also check type before use */ +#define PT_MASK(x) (&(x)->addr.v.a.mask) +#else +#define PT_MASK(x) (&(x)->addr.mask) +#endif +#else +#define PT_MASK(x) (&(x)->mask) +#endif + +#ifdef HAVE_STATE_NOROUTE +#ifdef HAVE_ADDR_TYPE +#define PT_NOROUTE(x) ((x)->addr.type == PF_ADDR_NOROUTE) +#else +#define PT_NOROUTE(x) ((x)->noroute) +#endif +#else +#define PT_NOROUTE(x) (0) +#endif + +/* view management */ +int select_states(void); +int read_states(void); +void sort_states(void); +void print_states(void); + +int select_rules(void); +int read_rules(void); +void print_rules(void); + +int print_header(void); +int keyboard_callback(int ch); + +#ifdef HAVE_ALTQ +int select_queues(void); +int read_queues(void); +void print_queues(void); +#endif + +/* qsort callbacks */ +int sort_size_callback(const void *s1, const void *s2); +int sort_exp_callback(const void *s1, const void *s2); +int sort_pkt_callback(const void *s1, const void *s2); +int sort_age_callback(const void *s1, const void *s2); +int sort_sa_callback(const void *s1, const void *s2); +int sort_sp_callback(const void *s1, const void *s2); +int sort_da_callback(const void *s1, const void *s2); +int sort_dp_callback(const void *s1, const void *s2); +int sort_rate_callback(const void *s1, const void *s2); +int sort_peak_callback(const void *s1, const void *s2); +int pf_dev = -1; + +struct sc_ent **state_cache = NULL; +pf_state_t *state_buf = NULL; +int state_buf_len = 0; +u_int32_t *state_ord = NULL; +u_int32_t num_states = 0; +u_int32_t num_states_all = 0; +u_int32_t num_rules = 0; +u_int32_t num_queues = 0; +int cachestates = 0; + +char *filter_string = NULL; +int dumpfilter = 0; + +#ifndef HAVE_RULE_LABELS +#define PF_RULE_LABEL_SIZE 20 +#endif + +#define MIN_LABEL_SIZE 5 +#define ANCHOR_FLD_SIZE 12 + +/* Define fields */ +field_def fields[] = { + {"SRC", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"DEST", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"GW", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"STATE", 5, 23, 18, FLD_ALIGN_COLUMN, -1, 0, 0, 0}, + {"AGE", 5, 9, 4, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"EXP", 5, 9, 4, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"PR ", 4, 9, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"DIR", 1, 3, 2, FLD_ALIGN_CENTER, -1, 0, 0, 0}, + {"PKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"BYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"RULE", 2, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"LABEL", MIN_LABEL_SIZE, MIN_LABEL_SIZE, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"STATES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"EVAL", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"ACTION", 1, 8, 4, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"LOG", 1, 3, 2, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"QUICK", 1, 1, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"KS", 1, 1, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"IF", 4, 6, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"INFO", 40, 80, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"MAX", 3, 5, 2, FLD_ALIGN_RIGHT, -1, 0, FLD_FLAG_HIDDEN, 0}, + {"RATE", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"AVG", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"PEAK", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"ANCHOR", 6, 16, 1, FLD_ALIGN_LEFT, -1, 0, FLD_FLAG_HIDDEN, 0}, + {"QUEUE", 15, 30, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"BW", 4, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"SCH", 3, 4, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"PRIO", 1, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"DROP_P", 6, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"DROP_B", 6, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"QLEN", 4, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"BORROW", 4, 6, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"SUSPENDS", 4, 6, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"P/S", 3, 7, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"B/S", 4, 7, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0} +}; + + +#define FIELD_ADDR(x) (&fields[x]) + +/* for states */ +#define FLD_SRC FIELD_ADDR(0) +#define FLD_DEST FIELD_ADDR(1) +#define FLD_GW FIELD_ADDR(2) +#define FLD_STATE FIELD_ADDR(3) +#define FLD_AGE FIELD_ADDR(4) +#define FLD_EXP FIELD_ADDR(5) +/* common */ +#define FLD_PROTO FIELD_ADDR(6) +#define FLD_DIR FIELD_ADDR(7) +#define FLD_PKTS FIELD_ADDR(8) +#define FLD_BYTES FIELD_ADDR(9) +#define FLD_RULE FIELD_ADDR(10) +/* for rules */ +#define FLD_LABEL FIELD_ADDR(11) +#define FLD_STATS FIELD_ADDR(12) +#define FLD_EVAL FIELD_ADDR(13) +#define FLD_ACTION FIELD_ADDR(14) +#define FLD_LOG FIELD_ADDR(15) +#define FLD_QUICK FIELD_ADDR(16) +#define FLD_KST FIELD_ADDR(17) +#define FLD_IF FIELD_ADDR(18) +#define FLD_RINFO FIELD_ADDR(19) +#define FLD_STMAX FIELD_ADDR(20) +/* other */ +#define FLD_SI FIELD_ADDR(21) /* instantaneous speed */ +#define FLD_SA FIELD_ADDR(22) /* average speed */ +#define FLD_SP FIELD_ADDR(23) /* peak speed */ +#define FLD_ANCHOR FIELD_ADDR(24) +/* for queues */ +#define FLD_QUEUE FIELD_ADDR(25) +#define FLD_BANDW FIELD_ADDR(26) +#define FLD_SCHED FIELD_ADDR(27) +#define FLD_PRIO FIELD_ADDR(28) +#define FLD_DROPP FIELD_ADDR(29) +#define FLD_DROPB FIELD_ADDR(30) +#define FLD_QLEN FIELD_ADDR(31) +#define FLD_BORR FIELD_ADDR(32) +#define FLD_SUSP FIELD_ADDR(33) +#define FLD_PKTSPS FIELD_ADDR(34) +#define FLD_BYTESPS FIELD_ADDR(35) + +/* Define views */ +field_def *view0[] = { + FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_STATE, + FLD_AGE, FLD_EXP, FLD_PKTS, FLD_BYTES, NULL +}; + +field_def *view1[] = { + FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_GW, FLD_STATE, FLD_AGE, + FLD_EXP, FLD_PKTS, FLD_BYTES, FLD_SI, FLD_SP, FLD_SA, FLD_RULE, NULL +}; + +field_def *view2[] = { + FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_STATE, FLD_AGE, FLD_EXP, + FLD_PKTS, FLD_BYTES, FLD_SI, FLD_SP, FLD_SA, FLD_RULE, FLD_GW, NULL +}; + +field_def *view3[] = { + FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_AGE, FLD_EXP, FLD_PKTS, + FLD_BYTES, FLD_STATE, FLD_SI, FLD_SP, FLD_SA, FLD_RULE, FLD_GW, NULL +}; + +field_def *view4[] = { + FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_PKTS, FLD_BYTES, FLD_STATE, + FLD_AGE, FLD_EXP, FLD_SI, FLD_SP, FLD_SA, FLD_RULE, FLD_GW, NULL +}; + +field_def *view5[] = { + FLD_RULE, FLD_ANCHOR, FLD_ACTION, FLD_DIR, FLD_LOG, FLD_QUICK, FLD_IF, + FLD_PROTO, FLD_KST, FLD_PKTS, FLD_BYTES, FLD_STATS, FLD_STMAX, + FLD_RINFO, NULL +}; + +field_def *view6[] = { + FLD_RULE, FLD_LABEL, FLD_PKTS, FLD_BYTES, FLD_STATS, FLD_STMAX, + FLD_ACTION, FLD_DIR, FLD_LOG, FLD_QUICK, FLD_IF, FLD_PROTO, + FLD_ANCHOR, FLD_KST, NULL +}; + +field_def *view7[] = { + FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_SI, FLD_SP, FLD_SA, + FLD_BYTES, FLD_STATE, FLD_PKTS, FLD_AGE, FLD_EXP, FLD_RULE, FLD_GW, NULL +}; + +field_def *view8[] = { + FLD_QUEUE, FLD_BANDW, FLD_SCHED, FLD_PRIO, FLD_PKTS, FLD_BYTES, + FLD_DROPP, FLD_DROPB, FLD_QLEN, FLD_BORR, FLD_SUSP, FLD_PKTSPS, + FLD_BYTESPS, NULL +}; + +/* Define orderings */ +order_type order_list[] = { + {"none", "none", 'N', NULL}, + {"bytes", "bytes", 'B', sort_size_callback}, + {"expiry", "exp", 'E', sort_exp_callback}, + {"packets", "pkt", 'P', sort_pkt_callback}, + {"age", "age", 'A', sort_age_callback}, + {"source addr", "src", 'F', sort_sa_callback}, + {"dest. addr", "dest", 'T', sort_da_callback}, + {"source port", "sport", 'S', sort_sp_callback}, + {"dest. port", "dport", 'D', sort_dp_callback}, + {"rate", "rate", 'R', sort_rate_callback}, + {"peak", "peak", 'K', sort_peak_callback}, + {NULL, NULL, 0, NULL} +}; + +/* Define view managers */ +struct view_manager state_mgr = { + "States", select_states, read_states, sort_states, print_header, + print_states, keyboard_callback, order_list, NULL +}; + +struct view_manager rule_mgr = { + "Rules", select_rules, read_rules, NULL, print_header, + print_rules, keyboard_callback, NULL, NULL +}; + +#ifdef HAVE_ALTQ +struct view_manager queue_mgr = { + "Queues", select_queues, read_queues, NULL, print_header, + print_queues, keyboard_callback, NULL, NULL +}; +#endif + +field_view views[] = { + {view2, "states", '8', &state_mgr}, + {view5, "rules", '9', &rule_mgr}, + {view8, "queues", 'Q', &queue_mgr}, + {NULL, NULL, 0, NULL} +}; + + +/* altq structures from pfctl */ + +#ifdef HAVE_ALTQ +union class_stats { + class_stats_t cbq_stats; + struct priq_classstats priq_stats; + struct hfsc_classstats hfsc_stats; +}; + +struct queue_stats { + union class_stats data; + struct timeval timestamp; + u_int8_t valid; +}; + +struct pf_altq_node { + struct pf_altq altq; + struct pf_altq_node *next; + struct pf_altq_node *children; + struct pf_altq_node *next_flat; + struct queue_stats qstats; + struct queue_stats qstats_last; + u_int8_t depth; + u_int8_t visited; +}; +#endif /* HAVE_ALTQ */ + + +/* ordering functions */ + +int +sort_size_callback(const void *s1, const void *s2) +{ +#ifdef HAVE_INOUT_COUNT + u_int64_t b1 = COUNTER(state_buf[* (u_int32_t *) s1].bytes[0]) + + COUNTER(state_buf[* (u_int32_t *) s1].bytes[1]); + u_int64_t b2 = COUNTER(state_buf[* (u_int32_t *) s2].bytes[0]) + + COUNTER(state_buf[* (u_int32_t *) s2].bytes[1]); +#else + u_int64_t b1 = COUNTER(state_buf[* (u_int32_t *) s1].bytes); + u_int64_t b2 = COUNTER(state_buf[* (u_int32_t *) s2].bytes); +#endif + if (b2 > b1) + return sortdir; + if (b2 < b1) + return -sortdir; + return 0; +} + +int +sort_pkt_callback(const void *s1, const void *s2) +{ +#ifdef HAVE_INOUT_COUNT + u_int64_t p1 = COUNTER(state_buf[* (u_int32_t *) s1].packets[0]) + + COUNTER(state_buf[* (u_int32_t *) s1].packets[1]); + u_int64_t p2 = COUNTER(state_buf[* (u_int32_t *) s2].packets[0]) + + COUNTER(state_buf[* (u_int32_t *) s2].packets[1]); +#else + u_int64_t p1 = COUNTER(state_buf[* (u_int32_t *) s1].packets); + u_int64_t p2 = COUNTER(state_buf[* (u_int32_t *) s2].packets); +#endif + if (p2 > p1) + return sortdir; + if (p2 < p1) + return -sortdir; + return 0; +} + +int +sort_age_callback(const void *s1, const void *s2) +{ + if (state_buf[* (u_int32_t *) s2].creation > + state_buf[* (u_int32_t *) s1].creation) + return sortdir; + if (state_buf[* (u_int32_t *) s2].creation < + state_buf[* (u_int32_t *) s1].creation) + return -sortdir; + return 0; +} + +int +sort_exp_callback(const void *s1, const void *s2) +{ + if (state_buf[* (u_int32_t *) s2].expire > + state_buf[* (u_int32_t *) s1].expire) + return sortdir; + if (state_buf[* (u_int32_t *) s2].expire < + state_buf[* (u_int32_t *) s1].expire) + return -sortdir; + return 0; +} + +int +sort_rate_callback(const void *s1, const void *s2) +{ + struct sc_ent *e1 = state_cache[* (u_int32_t *) s1]; + struct sc_ent *e2 = state_cache[* (u_int32_t *) s2]; + + if (e1 == NULL) + return sortdir; + if (e2 == NULL) + return -sortdir; + + if (e2->rate > e1 -> rate) + return sortdir; + if (e2->rate < e1 -> rate) + return -sortdir; + return 0; +} + +int +sort_peak_callback(const void *s1, const void *s2) +{ + struct sc_ent *e1 = state_cache[* (u_int32_t *) s1]; + struct sc_ent *e2 = state_cache[* (u_int32_t *) s2]; + + if (e2 == NULL) + return -sortdir; + if (e1 == NULL || e2 == NULL) + return 0; + + if (e2->peak > e1 -> peak) + return sortdir; + if (e2->peak < e1 -> peak) + return -sortdir; + return 0; +} + +int +compare_addr(int af, const struct pf_addr *a, const struct pf_addr *b) +{ + switch (af) { + case AF_INET: + if (ntohl(a->addr32[0]) > ntohl(b->addr32[0])) + return 1; + if (a->addr32[0] != b->addr32[0]) + return -1; + break; + case AF_INET6: + if (ntohl(a->addr32[0]) > ntohl(b->addr32[0])) + return 1; + if (a->addr32[0] != b->addr32[0]) + return -1; + if (ntohl(a->addr32[1]) > ntohl(b->addr32[1])) + return 1; + if (a->addr32[1] != b->addr32[1]) + return -1; + if (ntohl(a->addr32[2]) > ntohl(b->addr32[2])) + return 1; + if (a->addr32[2] != b->addr32[2]) + return -1; + if (ntohl(a->addr32[3]) > ntohl(b->addr32[3])) + return 1; + if (a->addr32[3] != b->addr32[3]) + return -1; + break; + } + + return 0; +} + +#ifdef HAVE_PFSYNC_KEY + +#ifdef __GNUC__ +__inline__ +#endif +int +sort_addr_callback(const pf_state_t *s1, + const pf_state_t *s2, int dir) +{ + const struct pf_addr *aa, *ab; + u_int16_t pa, pb; + int af, ret, ii, io; + + af = s1->af; + + if (af > s2->af) + return sortdir; + if (af < s2->af) + return -sortdir; + + ii = io = 0; + + if (dir == PF_OUT) /* looking for source addr */ + io = 1; + else /* looking for dest addr */ + ii = 1; + + if (s1->direction == PF_IN) { + aa = &s1->key[PF_SK_STACK].addr[ii]; + pa = s1->key[PF_SK_STACK].port[ii]; + } else { + aa = &s1->key[PF_SK_WIRE].addr[io]; + pa = s1->key[PF_SK_WIRE].port[io]; + } + + if (s2->direction == PF_IN) { + ab = &s2->key[PF_SK_STACK].addr[ii];; + pb = s2->key[PF_SK_STACK].port[ii]; + } else { + ab = &s2->key[PF_SK_WIRE].addr[io];; + pb = s2->key[PF_SK_WIRE].port[io]; + } + + ret = compare_addr(af, aa, ab); + if (ret) + return ret * sortdir; + + if (ntohs(pa) > ntohs(pb)) + return sortdir; + return -sortdir; +} + +#ifdef __GNUC__ +__inline__ +#endif +int +sort_port_callback(const pf_state_t *s1, + const pf_state_t *s2, int dir) +{ + const struct pf_addr *aa, *ab; + u_int16_t pa, pb; + int af, ret, ii, io; + + af = s1->af; + + + if (af > s2->af) + return sortdir; + if (af < s2->af) + return -sortdir; + + ii = io = 0; + + if (dir == PF_OUT) /* looking for source addr */ + io = 1; + else /* looking for dest addr */ + ii = 1; + + if (s1->direction == PF_IN) { + aa = &s1->key[PF_SK_STACK].addr[ii]; + pa = s1->key[PF_SK_STACK].port[ii]; + } else { + aa = &s1->key[PF_SK_WIRE].addr[io]; + pa = s1->key[PF_SK_WIRE].port[io]; + } + + if (s2->direction == PF_IN) { + ab = &s2->key[PF_SK_STACK].addr[ii];; + pb = s2->key[PF_SK_STACK].port[ii]; + } else { + ab = &s2->key[PF_SK_WIRE].addr[io];; + pb = s2->key[PF_SK_WIRE].port[io]; + } + + + if (ntohs(pa) > ntohs(pb)) + return sortdir; + if (ntohs(pa) < ntohs(pb)) + return - sortdir; + + ret = compare_addr(af, aa, ab); + if (ret) + return ret * sortdir; + return -sortdir; +} + +#else /* HAVE_PFSYNC_KEY */ + +#ifdef __GNUC__ +__inline__ +#endif +int +sort_addr_callback(const pf_state_t *s1, + const pf_state_t *s2, int dir) +{ + const pf_state_host_t *a, *b; + int af, ret; + + af = s1->af; + + if (af > s2->af) + return sortdir; + if (af < s2->af) + return -sortdir; + + if (s1->direction == dir) { + a = &s1->lan; + } else { + a = &s1->ext; + } + + if (s2->direction == dir) { + b = &s2->lan; + } else { + b = &s2->ext; + } + + ret = compare_addr(af, &a->addr, &b->addr); + if (ret) + return ret * sortdir; + + if (ntohs(a->port) > ntohs(b->port)) + return sortdir; + return -sortdir; +} + +#ifdef __GNUC__ +__inline__ +#endif +int +sort_port_callback(const pf_state_t *s1, + const pf_state_t *s2, int dir) +{ + const pf_state_host_t *a, *b; + int af; + + af = s1->af; + + if (af > s2->af) + return sortdir; + if (af < s2->af) + return -sortdir; + + if (s1->direction == dir) { + a = &s1->lan; + } else { + a = &s1->ext; + } + + if (s2->direction == dir) { + b = &s2->lan; + } else { + b = &s2->ext; + } + + if (ntohs(a->port) > ntohs(b->port)) + return sortdir; + if (ntohs(a->port) < ntohs(b->port)) + return -sortdir; + + if (compare_addr(af, &a->addr, &b->addr) > 0) + return sortdir; + return -sortdir; +} +#endif /* HAVE_PFSYNC_KEY */ + +int sort_sa_callback(const void *p1, const void *p2) +{ + pf_state_t *s1 = state_buf + (* (u_int32_t *) p1); + pf_state_t *s2 = state_buf + (* (u_int32_t *) p2); + return sort_addr_callback(s1, s2, PF_OUT); +} + +int sort_da_callback(const void *p1, const void *p2) +{ + pf_state_t *s1 = state_buf + (* (u_int32_t *) p1); + pf_state_t *s2 = state_buf + (* (u_int32_t *) p2); + return sort_addr_callback(s1, s2, PF_IN); +} + +int +sort_sp_callback(const void *p1, const void *p2) +{ + pf_state_t *s1 = state_buf + (* (u_int32_t *) p1); + pf_state_t *s2 = state_buf + (* (u_int32_t *) p2); + return sort_port_callback(s1, s2, PF_OUT); +} + +int +sort_dp_callback(const void *p1, const void *p2) +{ + pf_state_t *s1 = state_buf + (* (u_int32_t *) p1); + pf_state_t *s2 = state_buf + (* (u_int32_t *) p2); + return sort_port_callback(s1, s2, PF_IN); +} + +void +sort_states(void) +{ + order_type *ordering; + + if (curr_mgr == NULL) + return; + + ordering = curr_mgr->order_curr; + + if (ordering == NULL) + return; + if (ordering->func == NULL) + return; + if (state_buf == NULL) + return; + if (num_states <= 0) + return; + + mergesort(state_ord, num_states, sizeof(u_int32_t), ordering->func); +} + +/* state management functions */ + +void +alloc_buf(int ns) +{ + int len; + + if (ns < MIN_NUM_STATES) + ns = MIN_NUM_STATES; + + len = ns; + + if (len >= state_buf_len) { + len += NUM_STATE_INC; + state_buf = realloc(state_buf, len * sizeof(pf_state_t)); + state_ord = realloc(state_ord, len * sizeof(u_int32_t)); + state_cache = realloc(state_cache, + len * sizeof(struct sc_ent *)); + if (state_buf == NULL || state_ord == NULL || + state_cache == NULL) + err(1, "realloc"); + state_buf_len = len; + } +} + +int +select_states(void) +{ + num_disp = num_states; + return (0); +} + +int +read_states(void) +{ + struct pfioc_states ps; + int n; + + if (pf_dev == -1) + return -1; + + for (;;) { + int sbytes = state_buf_len * sizeof(pf_state_t); + + ps.ps_len = sbytes; + ps.ps_buf = (char *) state_buf; + + if (ioctl(pf_dev, DIOCGETSTATES, &ps) < 0) { + error("DIOCGETSTATES"); + } + num_states_all = ps.ps_len / sizeof(pf_state_t); + + if (ps.ps_len < sbytes) + break; + + alloc_buf(num_states_all); + } + + if (dumpfilter) { + int fd = open("state.dmp", O_WRONLY|O_CREAT|O_EXCL, 0); + if (fd > 0) { + write(fd, state_buf, ps.ps_len); + close(fd); + } + } + + num_states = num_states_all; + for (n = 0; n<num_states_all; n++) + state_ord[n] = n; + + if (cachestates) { + for (n = 0; n < num_states; n++) + state_cache[n] = cache_state(state_buf + n); + cache_endupdate(); + } + + num_disp = num_states; + return 0; +} + +int +unmask(struct pf_addr * m, u_int8_t af) +{ + int i = 31, j = 0, b = 0, msize; + u_int32_t tmp; + + if (af == AF_INET) + msize = 1; + else + msize = 4; + while (j < msize && m->addr32[j] == 0xffffffff) { + b += 32; + j++; + } + if (j < msize) { + tmp = ntohl(m->addr32[j]); + for (i = 31; tmp & (1 << i); --i) + b++; + } + return (b); +} + +/* display functions */ + +void +tb_print_addr(struct pf_addr * addr, struct pf_addr * mask, int af) +{ + static char buf[48]; + const char *bf; + + bf = inet_ntop(af, addr, buf, sizeof(buf)); + tbprintf("%s", bf); + + if (mask != NULL) { + if (!PF_AZERO(mask, af)) + tbprintf("/%u", unmask(mask, af)); + } +} +#ifdef HAVE_PFSYNC_KEY +void +print_fld_host2(field_def *fld, struct pfsync_state_key *ks, + struct pfsync_state_key *kn, int idx, int af) +{ + struct pf_addr *as = &ks->addr[idx]; + struct pf_addr *an = &kn->addr[idx]; + + u_int16_t ps = ntohs(ks->port[idx]); + u_int16_t pn = ntohs(kn->port[idx]); + + if (fld == NULL) + return; + + if (fld->width < 3) { + print_fld_str(fld, "*"); + return; + } + + tb_start(); + tb_print_addr(as, NULL, af); + + if (af == AF_INET) + tbprintf(":%u", ps); + else + tbprintf("[%u]", ps); + + print_fld_tb(fld); + + if (PF_ANEQ(as, an, af) || ps != pn) { + tb_start(); + tb_print_addr(an, NULL, af); + + if (af == AF_INET) + tbprintf(":%u", pn); + else + tbprintf("[%u]", pn); + print_fld_tb(FLD_GW); + } + +} +#else +void +print_fld_host(field_def *fld, pf_state_host_t * h, int af) +{ + u_int16_t p = ntohs(h->port); + + if (fld == NULL) + return; + + if (fld->width < 3) { + print_fld_str(fld, "*"); + return; + } + + tb_start(); + tb_print_addr(&h->addr, NULL, af); + + if (af == AF_INET) + tbprintf(":%u", p); + else + tbprintf("[%u]", p); + + print_fld_tb(fld); +} +#endif + +void +print_fld_state(field_def *fld, unsigned int proto, + unsigned int s1, unsigned int s2) +{ + int len; + + if (fld == NULL) + return; + + len = fld->width; + if (len < 1) + return; + + tb_start(); + + if (proto == IPPROTO_TCP) { + if (s1 <= TCPS_TIME_WAIT && s2 <= TCPS_TIME_WAIT) + tbprintf("%s:%s", tcpstates[s1], tcpstates[s2]); +#ifdef PF_TCPS_PROXY_SRC + else if (s1 == PF_TCPS_PROXY_SRC || + s2 == PF_TCPS_PROXY_SRC) + tbprintf("PROXY:SRC\n"); + else if (s1 == PF_TCPS_PROXY_DST || + s2 == PF_TCPS_PROXY_DST) + tbprintf("PROXY:DST\n"); +#endif + else + tbprintf("<BAD STATE LEVELS>"); + } else if (proto == IPPROTO_UDP && s1 < PFUDPS_NSTATES && + s2 < PFUDPS_NSTATES) { + const char *states[] = PFUDPS_NAMES; + tbprintf("%s:%s", states[s1], states[s2]); + } else if (proto != IPPROTO_ICMP && s1 < PFOTHERS_NSTATES && + s2 < PFOTHERS_NSTATES) { + /* XXX ICMP doesn't really have state levels */ + const char *states[] = PFOTHERS_NAMES; + tbprintf("%s:%s", states[s1], states[s2]); + } else { + tbprintf("%u:%u", s1, s2); + } + + if (strlen(tmp_buf) > len) { + tb_start(); + tbprintf("%u:%u", s1, s2); + } + + print_fld_tb(fld); +} + +int +print_state(pf_state_t * s, struct sc_ent * ent) +{ + pf_state_peer_t *src, *dst; + struct protoent *p; + + if (s->direction == PF_OUT) { + src = &s->src; + dst = &s->dst; + } else { + src = &s->dst; + dst = &s->src; + } + + p = getprotobynumber(s->proto); + + if (p != NULL) + print_fld_str(FLD_PROTO, p->p_name); + else + print_fld_uint(FLD_PROTO, s->proto); + +#ifdef HAVE_PFSYNC_KEY + if (s->direction == PF_OUT) { + print_fld_host2(FLD_SRC, &s->key[PF_SK_WIRE], + &s->key[PF_SK_STACK], 1, s->af); + print_fld_host2(FLD_DEST, &s->key[PF_SK_WIRE], + &s->key[PF_SK_STACK], 0, s->af); + } else { + print_fld_host2(FLD_SRC, &s->key[PF_SK_STACK], + &s->key[PF_SK_WIRE], 0, s->af); + print_fld_host2(FLD_DEST, &s->key[PF_SK_STACK], + &s->key[PF_SK_WIRE], 1, s->af); + } +#else + if (s->direction == PF_OUT) { + print_fld_host(FLD_SRC, &s->lan, s->af); + print_fld_host(FLD_DEST, &s->ext, s->af); + } else { + print_fld_host(FLD_SRC, &s->ext, s->af); + print_fld_host(FLD_DEST, &s->lan, s->af); + } + + if (PF_ANEQ(&s->lan.addr, &s->gwy.addr, s->af) || + (s->lan.port != s->gwy.port)) { + print_fld_host(FLD_GW, &s->gwy, s->af); + } +#endif + + if (s->direction == PF_OUT) + print_fld_str(FLD_DIR, "Out"); + else + print_fld_str(FLD_DIR, "In"); + + print_fld_state(FLD_STATE, s->proto, src->state, dst->state); + print_fld_age(FLD_AGE, s->creation); + print_fld_age(FLD_EXP, s->expire); +#ifdef HAVE_INOUT_COUNT + { + u_int64_t sz = COUNTER(s->bytes[0]) + COUNTER(s->bytes[1]); + + print_fld_size(FLD_PKTS, COUNTER(s->packets[0]) + + COUNTER(s->packets[1])); + print_fld_size(FLD_BYTES, sz); + print_fld_rate(FLD_SA, (s->creation > 0) ? + ((double)sz/(double)s->creation) : -1); + } +#else + print_fld_size(FLD_PKTS, s->packets); + print_fld_size(FLD_BYTES, s->bytes); + print_fld_rate(FLD_SA, (s->creation > 0) ? + ((double)s->bytes/(double)s->creation) : -1); + +#endif +#ifdef HAVE_PFSYNC_STATE + print_fld_uint(FLD_RULE, s->rule); +#else +#ifdef HAVE_RULE_NUMBER + print_fld_uint(FLD_RULE, s->rule.nr); +#endif +#endif + if (cachestates && ent != NULL) { + print_fld_rate(FLD_SI, ent->rate); + print_fld_rate(FLD_SP, ent->peak); + } + + end_line(); + return 1; +} + +void +print_states(void) +{ + int n, count = 0; + + for (n = dispstart; n < num_disp; n++) { + count += print_state(state_buf + state_ord[n], + state_cache[state_ord[n]]); + if (maxprint > 0 && count >= maxprint) + break; + } +} + +/* rule display */ + +struct pf_rule *rules = NULL; +u_int32_t alloc_rules = 0; + +int +select_rules(void) +{ + num_disp = num_rules; + return (0); +} + + +void +add_rule_alloc(u_int32_t nr) +{ + if (nr == 0) + return; + + num_rules += nr; + + if (rules == NULL) { + rules = malloc(num_rules * sizeof(struct pf_rule)); + if (rules == NULL) + err(1, "malloc"); + alloc_rules = num_rules; + } else if (num_rules > alloc_rules) { + rules = realloc(rules, num_rules * sizeof(struct pf_rule)); + if (rules == NULL) + err(1, "realloc"); + alloc_rules = num_rules; + } +} + +#ifdef HAVE_RULE_LABELS +int label_length; +#endif + +int +read_anchor_rules(char *anchor) +{ + struct pfioc_rule pr; + u_int32_t nr, num, off; + + if (pf_dev < 0) + return (-1); + + memset(&pr, 0, sizeof(pr)); +#ifdef HAVE_RULESETS + strlcpy(pr.anchor, anchor, sizeof(pr.anchor)); +#endif + if (ioctl(pf_dev, DIOCGETRULES, &pr)) { + error("anchor %s: %s", anchor, strerror(errno)); + return (-1); + } + + off = num_rules; + num = pr.nr; + add_rule_alloc(num); + + for (nr = 0; nr < num; ++nr) { + pr.nr = nr; + if (ioctl(pf_dev, DIOCGETRULE, &pr)) { + error("DIOCGETRULE: %s", strerror(errno)); + return (-1); + } +#ifdef HAVE_RULESETS + /* XXX overload pr.anchor, to store a pointer to + * anchor name */ + pr.rule.anchor = (struct pf_anchor *) anchor; +#endif +#ifdef HAVE_RULE_LABELS + { + int len = strlen(pr.rule.label); + if (len > label_length) + label_length = len; + } +#endif + rules[off + nr] = pr.rule; + } + + return (num); +} + +#ifdef HAVE_RULESETS +struct anchor_name { + char name[MAXPATHLEN]; + struct anchor_name *next; + u_int32_t ref; +}; + +struct anchor_name *anchor_root = NULL; +struct anchor_name *anchor_end = NULL; +struct anchor_name *anchor_free = NULL; + +struct anchor_name* +alloc_anchor_name(const char *path) +{ + struct anchor_name *a; + + a = anchor_free; + if (a == NULL) { + a = (struct anchor_name *)malloc(sizeof(struct anchor_name)); + if (a == NULL) + return (NULL); + } else + anchor_free = a->next; + + if (anchor_root == NULL) + anchor_end = a; + + a->next = anchor_root; + anchor_root = a; + + a->ref = 0; + strlcpy(a->name, path, sizeof(a->name)); + return (a); +} + +void +reset_anchor_names(void) +{ + if (anchor_end == NULL) + return; + + anchor_end->next = anchor_free; + anchor_free = anchor_root; + anchor_root = anchor_end = NULL; +} + +struct pfioc_ruleset ruleset; +char *rs_end = NULL; + +int +read_rulesets(const char *path) +{ + char *pre; + struct anchor_name *a; + u_int32_t nr, ns; + int len; + + if (path == NULL) + ruleset.path[0] = '\0'; + else if (strlcpy(ruleset.path, path, sizeof(ruleset.path)) >= + sizeof(ruleset.path)) + return (-1); + + /* a persistent storage for anchor names */ + a = alloc_anchor_name(ruleset.path); + if (a == NULL) + return (-1); + + len = read_anchor_rules(a->name); + if (len < 0) + return (-1); + + a->ref += len; + + if (ioctl(pf_dev, DIOCGETRULESETS, &ruleset)) { + error("DIOCGETRULESETS: %s", strerror(errno)); + return (-1); + } + + ns = ruleset.nr; + + if (rs_end == NULL) + rs_end = ruleset.path + sizeof(ruleset.path); + + /* 'pre' tracks the previous level on the anchor */ + pre = strchr(ruleset.path, 0); + len = rs_end - pre; + if (len < 1) + return (-1); + --len; + + for (nr = 0; nr < ns; ++nr) { + ruleset.nr = nr; + if (ioctl(pf_dev, DIOCGETRULESET, &ruleset)) { + error("DIOCGETRULESET: %s", strerror(errno)); + return (-1); + } + *pre = '/'; + if (strlcpy(pre + 1, ruleset.name, len) < len) + read_rulesets(ruleset.path); + *pre = '\0'; + } + + return (0); +} + +void +compute_anchor_field(void) +{ + struct anchor_name *a; + int sum, cnt, mx, nx; + sum = cnt = mx = 0; + + for (a = anchor_root; a != NULL; a = a->next, cnt++) { + int len; + if (a->ref == 0) + continue; + len = strlen(a->name); + sum += len; + if (len > mx) + mx = len; + } + + nx = sum/cnt; + if (nx < ANCHOR_FLD_SIZE) + nx = (mx < ANCHOR_FLD_SIZE) ? mx : ANCHOR_FLD_SIZE; + + if (FLD_ANCHOR->max_width != mx || + FLD_ANCHOR->norm_width != nx) { + FLD_ANCHOR->max_width = mx; + FLD_ANCHOR->norm_width = nx; + field_setup(); + need_update = 1; + } +} +#endif + +int +read_rules(void) +{ + int ret; + num_rules = 0; + + if (pf_dev == -1) + return (-1); + +#ifdef HAVE_RULE_LABELS + label_length = MIN_LABEL_SIZE; +#endif + +#ifdef HAVE_RULESETS + reset_anchor_names(); + ret = read_rulesets(NULL); + compute_anchor_field(); +#else + ret = read_anchor_rules(NULL); +#endif + +#ifdef HAVE_RULE_LABELS + { + int nw, mw; + nw = mw = label_length; + if (nw > 16) + nw = 16; + + if (FLD_LABEL->norm_width != nw || + FLD_LABEL->max_width != mw) { + FLD_LABEL->norm_width = nw; + FLD_LABEL->max_width = mw; + field_setup(); + need_update = 1; + } + } +#endif + + num_disp = num_rules; + return (ret); +} + +#ifdef HAVE_ADDR_WRAP +void +tb_print_addrw(struct pf_addr_wrap *addr, struct pf_addr *mask, u_int8_t af) +{ +#ifdef HAVE_ADDR_TYPE + switch (addr->type) { + case PF_ADDR_ADDRMASK: + tb_print_addr(&addr->v.a.addr, mask, af); + break; + case PF_ADDR_NOROUTE: + tbprintf("noroute"); + break; + case PF_ADDR_DYNIFTL: + tbprintf("(%s)", addr->v.ifname); + break; + case PF_ADDR_TABLE: + tbprintf("<%s>", addr->v.tblname); + break; + default: + tbprintf("UNKNOWN"); + break; + } +#else + if (addr->addr_dyn != NULL) + tbprintf("(%s)", addr->addr.pfa.ifname); + else + tb_print_addr(&addr->addr, mask, af); +#endif +} +#endif + +void +tb_print_op(u_int8_t op, const char *a1, const char *a2) +{ + if (op == PF_OP_IRG) + tbprintf("%s >< %s ", a1, a2); + else if (op == PF_OP_XRG) + tbprintf("%s <> %s ", a1, a2); +#ifdef HAVE_OP_RRG + else if (op == PF_OP_RRG) + tbprintf("%s:%s ", a1, a2); +#endif + else if (op == PF_OP_EQ) + tbprintf("= %s ", a1); + else if (op == PF_OP_NE) + tbprintf("!= %s ", a1); + else if (op == PF_OP_LT) + tbprintf("< %s ", a1); + else if (op == PF_OP_LE) + tbprintf("<= %s ", a1); + else if (op == PF_OP_GT) + tbprintf("> %s ", a1); + else if (op == PF_OP_GE) + tbprintf(">= %s ", a1); +} + +void +tb_print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto) +{ + char a1[6], a2[6]; + struct servent *s = getservbyport(p1, proto); + + p1 = ntohs(p1); + p2 = ntohs(p2); + snprintf(a1, sizeof(a1), "%u", p1); + snprintf(a2, sizeof(a2), "%u", p2); + tbprintf("port "); + if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE)) + tb_print_op(op, s->s_name, a2); + else + tb_print_op(op, a1, a2); +} + +void +tb_print_fromto(struct pf_rule_addr *src, struct pf_rule_addr *dst, + u_int8_t af, u_int8_t proto) +{ + if ( + PF_AZERO(PT_ADDR(src), AF_INET6) && + PF_AZERO(PT_ADDR(dst), AF_INET6) && + ! PT_NOROUTE(src) && ! PT_NOROUTE(dst) && + PF_AZERO(PT_MASK(src), AF_INET6) && + PF_AZERO(PT_MASK(dst), AF_INET6) && + !src->port_op && !dst->port_op) + tbprintf("all "); + else { + tbprintf("from "); + if (PT_NOROUTE(src)) + tbprintf("no-route "); + else if (PF_AZERO(PT_ADDR(src), AF_INET6) && + PF_AZERO(PT_MASK(src), AF_INET6)) + tbprintf("any "); + else { +#ifdef HAVE_NEG + if (src->neg) +#else + if (src->not) +#endif + tbprintf("! "); +#ifdef HAVE_ADDR_WRAP + tb_print_addrw(&src->addr, PT_MASK(src), af); +#else + tb_print_addr(&src->addr, PT_MASK(src), af); +#endif + tbprintf(" "); + } + if (src->port_op) + tb_print_port(src->port_op, src->port[0], + src->port[1], + proto == IPPROTO_TCP ? "tcp" : "udp"); + + tbprintf("to "); + if (PT_NOROUTE(dst)) + tbprintf("no-route "); + else if (PF_AZERO(PT_ADDR(dst), AF_INET6) && + PF_AZERO(PT_MASK(dst), AF_INET6)) + tbprintf("any "); + else { +#ifdef HAVE_NEG + if (dst->neg) +#else + if (dst->not) +#endif + tbprintf("! "); +#ifdef HAVE_ADDR_WRAP + tb_print_addrw(&dst->addr, PT_MASK(dst), af); +#else + tb_print_addr(&dst->addr, PT_MASK(dst), af); +#endif + tbprintf(" "); + } + if (dst->port_op) + tb_print_port(dst->port_op, dst->port[0], + dst->port[1], + proto == IPPROTO_TCP ? "tcp" : "udp"); + } +} + +#ifdef HAVE_RULE_UGID +void +tb_print_ugid(u_int8_t op, unsigned u1, unsigned u2, + const char *t, unsigned umax) +{ + char a1[11], a2[11]; + + snprintf(a1, sizeof(a1), "%u", u1); + snprintf(a2, sizeof(a2), "%u", u2); + + tbprintf("%s ", t); + if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE)) + tb_print_op(op, "unknown", a2); + else + tb_print_op(op, a1, a2); +} +#endif + +void +tb_print_flags(u_int8_t f) +{ + const char *tcpflags = "FSRPAUEW"; + int i; + + for (i = 0; tcpflags[i]; ++i) + if (f & (1 << i)) + tbprintf("%c", tcpflags[i]); +} + +void +print_rule(struct pf_rule *pr) +{ + static const char *actiontypes[] = { "Pass", "Block", "Scrub", "Nat", + "no Nat", "Binat", "no Binat", "Rdr", "no Rdr" }; + int numact = sizeof(actiontypes) / sizeof(char *); + +#ifdef HAVE_PF_ROUTE + static const char *routetypes[] = { "", "fastroute", "route-to", + "dup-to", "reply-to" }; + + int numroute = sizeof(routetypes) / sizeof(char *); +#endif + + if (pr == NULL) return; + +#ifdef HAVE_RULE_LABELS + print_fld_str(FLD_LABEL, pr->label); +#endif +#ifdef HAVE_RULE_STATES +#ifdef HAVE_PFSYNC_KEY + print_fld_size(FLD_STATS, pr->states_tot); +#else + print_fld_size(FLD_STATS, pr->states); +#endif +#endif + +#ifdef HAVE_INOUT_COUNT_RULES + print_fld_size(FLD_PKTS, pr->packets[0] + pr->packets[1]); + print_fld_size(FLD_BYTES, pr->bytes[0] + pr->bytes[1]); +#else + print_fld_size(FLD_PKTS, pr->packets); + print_fld_size(FLD_BYTES, pr->bytes); +#endif + print_fld_uint(FLD_RULE, pr->nr); + print_fld_str(FLD_DIR, pr->direction == PF_OUT ? "Out" : "In"); + if (pr->quick) + print_fld_str(FLD_QUICK, "Quick"); + + if (pr->keep_state == PF_STATE_NORMAL) + print_fld_str(FLD_KST, "Keep"); + else if (pr->keep_state == PF_STATE_MODULATE) + print_fld_str(FLD_KST, "Mod"); +#ifdef PF_STATE_SYNPROXY + else if (pr->keep_state == PF_STATE_MODULATE) + print_fld_str(FLD_KST, "Syn"); +#endif + if (pr->log == 1) + print_fld_str(FLD_LOG, "Log"); + else if (pr->log == 2) + print_fld_str(FLD_LOG, "All"); + + if (pr->action >= numact) + print_fld_uint(FLD_ACTION, pr->action); + else print_fld_str(FLD_ACTION, actiontypes[pr->action]); + + if (pr->proto) { + struct protoent *p = getprotobynumber(pr->proto); + + if (p != NULL) + print_fld_str(FLD_PROTO, p->p_name); + else + print_fld_uint(FLD_PROTO, pr->proto); + } + + if (pr->ifname[0]) { + tb_start(); +#ifdef HAVE_RULE_IFNOT + if (pr->ifnot) + tbprintf("!"); +#endif + tbprintf("%s", pr->ifname); + print_fld_tb(FLD_IF); + } +#ifdef HAVE_MAX_STATES + if (pr->max_states) + print_fld_uint(FLD_STMAX, pr->max_states); +#endif + /* print info field */ + + tb_start(); + +#ifdef HAVE_RULE_NATPASS + if (pr->natpass) + tbprintf("pass "); +#endif + if (pr->action == PF_DROP) { + if (pr->rule_flag & PFRULE_RETURNRST) + tbprintf("return-rst "); +#ifdef PFRULE_RETURN + else if (pr->rule_flag & PFRULE_RETURN) + tbprintf("return "); +#endif +#ifdef PFRULE_RETURNICMP + else if (pr->rule_flag & PFRULE_RETURNICMP) + tbprintf("return-icmp "); +#endif + else + tbprintf("drop "); + } + +#ifdef HAVE_PF_ROUTE + if (pr->rt > 0 && pr->rt < numroute) { + tbprintf("%s ", routetypes[pr->rt]); + if (pr->rt != PF_FASTROUTE) + tbprintf("... "); + } +#endif + if (pr->af) { + if (pr->af == AF_INET) + tbprintf("inet "); + else + tbprintf("inet6 "); + } + + tb_print_fromto(&pr->src, &pr->dst, pr->af, pr->proto); +#ifdef HAVE_RULE_UGID + if (pr->uid.op) + tb_print_ugid(pr->uid.op, pr->uid.uid[0], pr->uid.uid[1], + "user", UID_MAX); + if (pr->gid.op) + tb_print_ugid(pr->gid.op, pr->gid.gid[0], pr->gid.gid[1], + "group", GID_MAX); +#endif + + if (pr->flags || pr->flagset) { + tbprintf(" flags "); + tb_print_flags(pr->flags); + tbprintf("/"); + tb_print_flags(pr->flagset); + } + + tbprintf(" "); + +#ifdef HAVE_RULE_TOS + if (pr->tos) + tbprintf("tos 0x%2.2x ", pr->tos); +#endif +#ifdef PFRULE_FRAGMENT + if (pr->rule_flag & PFRULE_FRAGMENT) + tbprintf("fragment "); +#endif +#ifdef PFRULE_NODF + if (pr->rule_flag & PFRULE_NODF) + tbprintf("no-df "); +#endif +#ifdef PFRULE_RANDOMID + if (pr->rule_flag & PFRULE_RANDOMID) + tbprintf("random-id "); +#endif + if (pr->min_ttl) + tbprintf("min-ttl %d ", pr->min_ttl); +#ifdef HAVE_MAX_MSS + if (pr->max_mss) + tbprintf("max-mss %d ", pr->max_mss); +#endif + if (pr->allow_opts) + tbprintf("allow-opts "); + + if (pr->action == PF_SCRUB) { +#ifdef PFRULE_REASSEMBLE_TCP + if (pr->rule_flag & PFRULE_REASSEMBLE_TCP) + tbprintf("reassemble tcp "); +#endif +#ifdef PFRULE_FRAGDROP + if (pr->rule_flag & PFRULE_FRAGDROP) + tbprintf("fragment drop-ovl "); + else +#endif +#ifdef PFRULE_FRAGCROP + if (pr->rule_flag & PFRULE_FRAGCROP) + tbprintf("fragment crop "); + else +#endif + tbprintf("fragment reassemble "); + } + +#ifdef HAVE_ALTQ + if (pr->qname[0] && pr->pqname[0]) + tbprintf("queue(%s, %s) ", pr->qname, pr->pqname); + else if (pr->qname[0]) + tbprintf("queue %s ", pr->qname); +#endif +#ifdef HAVE_TAGS + if (pr->tagname[0]) + tbprintf("tag %s ", pr->tagname); + if (pr->match_tagname[0]) { + if (pr->match_tag_not) + tbprintf("! "); + tbprintf("tagged %s ", pr->match_tagname); + } +#endif + print_fld_tb(FLD_RINFO); + +#ifdef HAVE_RULESETS + /* XXX anchor field overloaded with anchor name */ + print_fld_str(FLD_ANCHOR, (char *)pr->anchor); +#endif + tb_end(); + + end_line(); +} + +void +print_rules(void) +{ + u_int32_t n, count = 0; + + for (n = dispstart; n < num_rules; n++) { + print_rule(rules + n); + count ++; + if (maxprint > 0 && count >= maxprint) + break; + } +} + +/* queue display */ + +#ifdef HAVE_ALTQ + +struct pf_altq_node * +pfctl_find_altq_node(struct pf_altq_node *root, const char *qname, + const char *ifname) +{ + struct pf_altq_node *node, *child; + + for (node = root; node != NULL; node = node->next) { + if (!strcmp(node->altq.qname, qname) + && !(strcmp(node->altq.ifname, ifname))) + return (node); + if (node->children != NULL) { + child = pfctl_find_altq_node(node->children, qname, + ifname); + if (child != NULL) + return (child); + } + } + return (NULL); +} + +void +pfctl_insert_altq_node(struct pf_altq_node **root, + const struct pf_altq altq, const struct queue_stats qstats) +{ + struct pf_altq_node *node; + + node = calloc(1, sizeof(struct pf_altq_node)); + if (node == NULL) + err(1, "pfctl_insert_altq_node: calloc"); + memcpy(&node->altq, &altq, sizeof(struct pf_altq)); + memcpy(&node->qstats, &qstats, sizeof(qstats)); + node->next = node->children = node->next_flat = NULL; + node->depth = 0; + node->visited = 1; + + if (*root == NULL) + *root = node; + else if (!altq.parent[0]) { + struct pf_altq_node *prev = *root; + + while (prev->next != NULL) + prev = prev->next; + prev->next = node; + } else { + struct pf_altq_node *parent; + + parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname); + if (parent == NULL) + errx(1, "parent %s not found", altq.parent); + node->depth = parent->depth+1; + if (parent->children == NULL) + parent->children = node; + else { + struct pf_altq_node *prev = parent->children; + + while (prev->next != NULL) + prev = prev->next; + prev->next = node; + } + } + if (*root != node) { + struct pf_altq_node *prev_flat = *root; + while (prev_flat->next_flat != NULL) { + prev_flat = prev_flat->next_flat; + } + prev_flat->next_flat = node; + } +} + +int +pfctl_update_qstats(struct pf_altq_node **root, int *inserts) +{ + struct pf_altq_node *node; + struct pfioc_altq pa; + struct pfioc_qstats pq; + u_int32_t nr; + struct queue_stats qstats; + u_int32_t nr_queues; + + *inserts = 0; + memset(&pa, 0, sizeof(pa)); + memset(&pq, 0, sizeof(pq)); + memset(&qstats, 0, sizeof(qstats)); + + if (pf_dev < 0) + return (-1); + + if (ioctl(pf_dev, DIOCGETALTQS, &pa)) { + error("DIOCGETALTQS: %s", strerror(errno)); + return (-1); + } + num_queues = nr_queues = pa.nr; + for (nr = 0; nr < nr_queues; ++nr) { + pa.nr = nr; + if (ioctl(pf_dev, DIOCGETALTQ, &pa)) { + error("DIOCGETALTQ: %s", strerror(errno)); + return (-1); + } + if (pa.altq.qid > 0) { + pq.nr = nr; + pq.ticket = pa.ticket; + pq.buf = &qstats; + pq.nbytes = sizeof(qstats); + if (ioctl(pf_dev, DIOCGETQSTATS, &pq)) { + error("DIOCGETQSTATS: %s", strerror(errno)); + return (-1); + } + qstats.valid = 1; + gettimeofday(&qstats.timestamp, NULL); + if ((node = pfctl_find_altq_node(*root, pa.altq.qname, + pa.altq.ifname)) != NULL) { + // update altq data too as bandwidth may have changed + memcpy(&node->altq, &pa.altq, sizeof(struct pf_altq)); + memcpy(&node->qstats_last, &node->qstats, + sizeof(struct queue_stats)); + memcpy(&node->qstats, &qstats, + sizeof(qstats)); + node->visited = 1; + } else { + pfctl_insert_altq_node(root, pa.altq, qstats); + *inserts = 1; + } + } + else + --num_queues; + } + return (0); +} + +void +pfctl_free_altq_node(struct pf_altq_node *node) +{ + while (node != NULL) { + struct pf_altq_node *prev; + + if (node->children != NULL) + pfctl_free_altq_node(node->children); + prev = node; + node = node->next; + free(prev); + } +} + +void +pfctl_mark_all_unvisited(struct pf_altq_node *root) +{ + if (root != NULL) { + struct pf_altq_node *node = root; + while (node != NULL) { + node->visited = 0; + node = node->next_flat; + } + } +} + +int +pfctl_have_unvisited(struct pf_altq_node *root) +{ + if (root == NULL) + return(0); + else { + struct pf_altq_node *node = root; + while (node != NULL) { + if (node->visited == 0) + return(1); + node = node->next_flat; + } + return(0); + } +} + +struct pf_altq_node *altq_root = NULL; + +int +select_queues(void) +{ + num_disp = num_queues; + return (0); +} + +int +read_queues(void) +{ + static int first_read = 1; + int inserts; + num_disp = num_queues = 0; + + pfctl_mark_all_unvisited(altq_root); + if (pfctl_update_qstats(&altq_root, &inserts)) + return (-1); + + // Allow inserts only on first read; + // on subsequent reads clear and reload + if (first_read == 0 && + (inserts != 0 || pfctl_have_unvisited(altq_root) != 0)) { + pfctl_free_altq_node(altq_root); + altq_root = NULL; + first_read = 1; + if (pfctl_update_qstats(&altq_root, &inserts)) + return (-1); + } + + first_read = 0; + num_disp = num_queues; + + return(0); +} + +double +calc_interval(struct timeval *cur_time, struct timeval *last_time) +{ + double sec; + + sec = (double)(cur_time->tv_sec - last_time->tv_sec) + + (double)(cur_time->tv_usec - last_time->tv_usec) / 1000000; + + return (sec); +} + +double +calc_rate(u_int64_t new_bytes, u_int64_t last_bytes, double interval) +{ + double rate; + + rate = (double)(new_bytes - last_bytes) / interval; + return (rate); +} + +double +calc_pps(u_int64_t new_pkts, u_int64_t last_pkts, double interval) +{ + double pps; + + pps = (double)(new_pkts - last_pkts) / interval; + return (pps); +} + +#define DEFAULT_PRIORITY 1 + +void +print_queue(struct pf_altq_node *node) +{ + u_int8_t d; + double interval, pps, bps; + pps = bps = 0; + + tb_start(); + for (d = 0; d < node->depth; d++) + tbprintf(" "); + tbprintf(node->altq.qname); + print_fld_tb(FLD_QUEUE); + + if (node->altq.scheduler == ALTQT_CBQ || + node->altq.scheduler == ALTQT_HFSC + ) + print_fld_bw(FLD_BANDW, (double)node->altq.bandwidth); + + if (node->altq.priority != DEFAULT_PRIORITY) + print_fld_uint(FLD_PRIO, + node->altq.priority); + + if (node->qstats.valid && node->qstats_last.valid) + interval = calc_interval(&node->qstats.timestamp, + &node->qstats_last.timestamp); + else + interval = 0; + + switch (node->altq.scheduler) { + case ALTQT_CBQ: + print_fld_str(FLD_SCHED, "cbq"); + print_fld_size(FLD_PKTS, + node->qstats.data.cbq_stats.xmit_cnt.packets); + print_fld_size(FLD_BYTES, + node->qstats.data.cbq_stats.xmit_cnt.bytes); + print_fld_size(FLD_DROPP, + node->qstats.data.cbq_stats.drop_cnt.packets); + print_fld_size(FLD_DROPB, + node->qstats.data.cbq_stats.drop_cnt.bytes); + print_fld_size(FLD_QLEN, node->qstats.data.cbq_stats.qcnt); + print_fld_size(FLD_BORR, node->qstats.data.cbq_stats.borrows); + print_fld_size(FLD_SUSP, node->qstats.data.cbq_stats.delays); + if (interval > 0) { + pps = calc_pps(node->qstats.data.cbq_stats.xmit_cnt.packets, + node->qstats_last.data.cbq_stats.xmit_cnt.packets, interval); + bps = calc_rate(node->qstats.data.cbq_stats.xmit_cnt.bytes, + node->qstats_last.data.cbq_stats.xmit_cnt.bytes, interval); + } + break; + case ALTQT_PRIQ: + print_fld_str(FLD_SCHED, "priq"); + print_fld_size(FLD_PKTS, + node->qstats.data.priq_stats.xmitcnt.packets); + print_fld_size(FLD_BYTES, + node->qstats.data.priq_stats.xmitcnt.bytes); + print_fld_size(FLD_DROPP, + node->qstats.data.priq_stats.dropcnt.packets); + print_fld_size(FLD_DROPB, + node->qstats.data.priq_stats.dropcnt.bytes); + print_fld_size(FLD_QLEN, node->qstats.data.priq_stats.qlength); + if (interval > 0) { + pps = calc_pps(node->qstats.data.priq_stats.xmitcnt.packets, + node->qstats_last.data.priq_stats.xmitcnt.packets, interval); + bps = calc_rate(node->qstats.data.priq_stats.xmitcnt.bytes, + node->qstats_last.data.priq_stats.xmitcnt.bytes, interval); + } + break; + case ALTQT_HFSC: + print_fld_str(FLD_SCHED, "hfsc"); + print_fld_size(FLD_PKTS, + node->qstats.data.hfsc_stats.xmit_cnt.packets); + print_fld_size(FLD_BYTES, + node->qstats.data.hfsc_stats.xmit_cnt.bytes); + print_fld_size(FLD_DROPP, + node->qstats.data.hfsc_stats.drop_cnt.packets); + print_fld_size(FLD_DROPB, + node->qstats.data.hfsc_stats.drop_cnt.bytes); + print_fld_size(FLD_QLEN, node->qstats.data.hfsc_stats.qlength); + if (interval > 0) { + pps = calc_pps(node->qstats.data.hfsc_stats.xmit_cnt.packets, + node->qstats_last.data.hfsc_stats.xmit_cnt.packets, interval); + bps = calc_rate(node->qstats.data.hfsc_stats.xmit_cnt.bytes, + node->qstats_last.data.hfsc_stats.xmit_cnt.bytes, interval); + } + break; + } + + /* if (node->altq.scheduler != ALTQT_HFSC && interval > 0) { */ + if (node->altq.scheduler && interval > 0) { + tb_start(); + if (pps > 0 && pps < 1) + tbprintf("%-3.1lf", pps); + else + tbprintf("%u", (unsigned int) pps); + + print_fld_tb(FLD_PKTSPS); + print_fld_bw(FLD_BYTESPS, bps); + } +} + +void +print_queues(void) +{ + u_int32_t n, count = 0; + struct pf_altq_node *node = altq_root; + + for (n = 0; n < dispstart; n++) + node = node->next_flat; + + for (; n < num_disp; n++) { + print_queue(node); + node = node->next_flat; + end_line(); + count ++; + if (maxprint > 0 && count >= maxprint) + break; + } +} + +#endif /* HAVE_ALTQ */ + +/* main program functions */ + +void +update_cache() +{ + static int pstate = -1; + if (pstate == cachestates) + return; + + pstate = cachestates; + if (cachestates) { + show_field(FLD_SI); + show_field(FLD_SP); + gotsig_alarm = 1; + } else { + hide_field(FLD_SI); + hide_field(FLD_SP); + need_update = 1; + } + field_setup(); +} + +void +initpftop(void) +{ + struct pf_status status; + field_view *v; + int cachesize = DEFAULT_CACHE_SIZE; + + v = views; + while(v->name != NULL) + add_view(v++); + + pf_dev = open("/dev/pf", O_RDONLY); + if (pf_dev == -1) { + alloc_buf(0); + warn("open(\"/dev/pf\")"); + } else if (ioctl(pf_dev, DIOCGETSTATUS, &status)) { + warn("DIOCGETSTATUS"); + alloc_buf(0); + } else + alloc_buf(status.states); + + /* initialize cache with given size */ + if (cache_init(cachesize)) + warnx("Failed to initialize cache."); + else if (interactive && cachesize > 0) + cachestates = 1; + + update_cache(); + +#ifdef HAVE_MAX_STATES + show_field(FLD_STMAX); +#endif +#ifdef HAVE_RULESETS + show_field(FLD_ANCHOR); +#endif + +} diff --git a/usr.bin/systat/pigs.c b/usr.bin/systat/pigs.c index 46b36311559..0d57af6a476 100644 --- a/usr.bin/systat/pigs.c +++ b/usr.bin/systat/pigs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pigs.c,v 1.21 2007/09/02 15:19:35 deraadt Exp $ */ +/* $OpenBSD: pigs.c,v 1.22 2008/06/12 22:26:01 canacar Exp $ */ /* $NetBSD: pigs.c,v 1.3 1995/04/29 05:54:50 cgd Exp $ */ /*- @@ -30,13 +30,6 @@ * SUCH DAMAGE. */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)pigs.c 8.2 (Berkeley) 9/23/93"; -#endif -static char rcsid[] = "$OpenBSD: pigs.c,v 1.21 2007/09/02 15:19:35 deraadt Exp $"; -#endif /* not lint */ - /* * Pigs display from Bill Reeves at Lucasfilm */ @@ -56,178 +49,252 @@ static char rcsid[] = "$OpenBSD: pigs.c,v 1.21 2007/09/02 15:19:35 deraadt Exp $ #include <stdlib.h> #include <string.h> -#include "extern.h" #include "systat.h" int compar(const void *, const void *); +void print_pg(void); +int read_pg(void); +int select_pg(void); +void showpigs(int k); -static int nproc; -static struct p_times { - float pt_pctcpu; - struct kinfo_proc2 *pt_kp; -} *pt; +static struct kinfo_proc2 *procbase = NULL; +static int nproc, pigs_cnt, *pb_indices = NULL; +static int onproc = -1; static long stime[CPUSTATES]; static double lccpu; +struct loadavg sysload; -WINDOW * -openpigs(void) -{ - return (subwin(stdscr, LINES-1-2, 0, 2, 0)); -} -void -closepigs(WINDOW *w) -{ - if (w == NULL) - return; - wclear(w); - wrefresh(w); - delwin(w); -} +field_def fields_pg[] = { + {"USER", 6, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"NAME", 10, 24, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"PID", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"CPU", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"", 30, 60, 1, FLD_ALIGN_BAR, -1, 0, 0, 100}, +}; -void -showpigs(void) -{ - int i, j, y, k; - struct kinfo_proc2 *kp; - float total; - int factor; - char *uname, *pname, pidname[30]; +#define FIELD_ADDR(x) (&fields_pg[x]) - if (pt == NULL) - return; - /* Accumulate the percent of cpu per user. */ - total = 0.0; - for (i = 0; i <= nproc; i++) { - /* Accumulate the percentage. */ - total += pt[i].pt_pctcpu; - } +#define FLD_PG_USER FIELD_ADDR(0) +#define FLD_PG_NAME FIELD_ADDR(1) +#define FLD_PG_PID FIELD_ADDR(2) +#define FLD_PG_VALUE FIELD_ADDR(3) +#define FLD_PG_BAR FIELD_ADDR(4) - if (total < 1.0) - total = 1.0; - factor = 50.0/total; - - qsort(pt, nproc + 1, sizeof (struct p_times), compar); - y = 1; - i = nproc + 1; - if (i > wnd->_maxy-1) - i = wnd->_maxy-1; - for (k = 0; i > 0 && pt[k].pt_pctcpu > 0.01; i--, y++, k++) { - kp = pt[k].pt_kp; - if (kp == NULL) { - uname = ""; - pname = "<idle>"; - } else { - uname = user_from_uid(kp->p_uid, 0); - pname = kp->p_comm; - } - wmove(wnd, y, 0); - wclrtoeol(wnd); - mvwaddstr(wnd, y, 0, uname); - snprintf(pidname, sizeof pidname, "%10.10s", pname); - mvwaddstr(wnd, y, 9, pidname); - wmove(wnd, y, 20); - for (j = pt[k].pt_pctcpu*factor + 0.5; j > 0; j--) - waddch(wnd, 'X'); - } - wmove(wnd, y, 0); wclrtobot(wnd); +/* Define views */ +field_def *view_pg_0[] = { + FLD_PG_PID, FLD_PG_USER, FLD_PG_NAME, FLD_PG_VALUE, FLD_PG_BAR, NULL +}; + + +/* Define view managers */ +struct view_manager pigs_mgr = { + "Pigs", select_pg, read_pg, NULL, print_header, + print_pg, keyboard_callback, NULL, NULL +}; + +field_view views_pg[] = { + {view_pg_0, "pigs", '5', &pigs_mgr}, + {NULL, NULL, 0, NULL} +}; + + +#ifdef FSCALE +# define FIXED_LOADAVG FSCALE +# define FIXED_PCTCPU FSCALE +#endif + +#ifdef FIXED_PCTCPU + typedef long pctcpu; +# define pctdouble(p) ((double)(p) / FIXED_PCTCPU) +#else +typedef double pctcpu; +# define pctdouble(p) (p) +#endif + +int +select_pg(void) +{ + num_disp = pigs_cnt; + return (0); } -struct loadavg sysload; int -initpigs(void) +getprocs(void) { - static int sysload_mib[] = {CTL_VM, VM_LOADAVG}; - static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME }; - static int ccpu_mib[] = { CTL_KERN, KERN_CCPU }; size_t size; - fixpt_t ccpu; + int mib[6] = {CTL_KERN, KERN_PROC2, KERN_PROC_KTHREAD, 0, sizeof(struct kinfo_proc2), 0}; + + int st; - size = sizeof(stime); - (void) sysctl(cp_time_mib, 2, &stime, &size, NULL, 0); + free(procbase); + procbase = NULL; - size = sizeof(sysload); - (void) sysctl(sysload_mib, 2, &sysload, &size, NULL, 0); + st = sysctl(mib, 6, NULL, &size, NULL, 0); + if (st == -1) + return (1); - size = sizeof(ccpu); - (void) sysctl(ccpu_mib, 2, &ccpu, &size, NULL, 0); + size = 5 * size / 4; /* extra slop */ + if ((procbase = malloc(size + 1)) == NULL) + return (1); - lccpu = log((double) ccpu / sysload.fscale); + mib[5] = (int)(size / sizeof(struct kinfo_proc2)); + st = sysctl(mib, 6, procbase, &size, NULL, 0); + if (st == -1) + return (1); - return(1); + nproc = (int)(size / sizeof(struct kinfo_proc2)); + return (0); } -void -fetchpigs(void) + +int +read_pg(void) { static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME }; - static int lastnproc = 0; - struct kinfo_proc2 *kpp; long ctime[CPUSTATES]; double t; - int i; + int i, k; size_t size; - float *pctp; - kpp = kvm_getproc2(kd, KERN_PROC_KTHREAD, 0, sizeof(*kpp), &nproc); - if (kpp == NULL) { - error("%s", kvm_geterr(kd)); - if (pt) - free(pt); - return; + num_disp = pigs_cnt = 0; + + if (getprocs()) { + error("Failed to read process info!"); + return 1; } - if (nproc > lastnproc) { - free(pt); - if ((pt = calloc(nproc + 1, sizeof(struct p_times))) == NULL) { - error("Out of memory"); - die(); + + if (nproc > onproc) { + int *p; + p = realloc(pb_indices, (nproc + 1) * sizeof(int)); + if (p == NULL) { + error("Out of Memory!"); + return 1; } + pb_indices = p; + onproc = nproc; } - lastnproc = nproc; - /* - * calculate %cpu for each proc - */ - for (i = 0; i < nproc; i++) { - pt[i].pt_kp = &kpp[i]; - pctp = &pt[i].pt_pctcpu; - if (kpp->p_swtime == 0) - *pctp = 0; - else - *pctp = ((double) kpp->p_pctcpu / sysload.fscale) / - (1.0 - exp(kpp->p_swtime * lccpu)); - } + + memset(&procbase[nproc], 0, sizeof(*procbase)); + + for (i = 0; i <= nproc; i++) + pb_indices[i] = i; + /* * and for the imaginary "idle" process */ size = sizeof(ctime); - (void) sysctl(cp_time_mib, 2, &ctime, &size, NULL, 0); + sysctl(cp_time_mib, 2, &ctime, &size, NULL, 0); t = 0; for (i = 0; i < CPUSTATES; i++) t += ctime[i] - stime[i]; if (t == 0.0) t = 1.0; - pt[nproc].pt_kp = NULL; - pt[nproc].pt_pctcpu = (ctime[CP_IDLE] - stime[CP_IDLE]) / t; + + procbase[nproc].p_pctcpu = (ctime[CP_IDLE] - stime[CP_IDLE]) / t / pctdouble(1); for (i = 0; i < CPUSTATES; i++) stime[i] = ctime[i]; + + qsort(pb_indices, nproc + 1, sizeof (int), compar); + + pigs_cnt = 0; + for (k = 0; k < nproc + 1; k++) { + int i = pb_indices[k]; + if (pctdouble(procbase[i].p_pctcpu) < 0.01) + break; + pigs_cnt++; + } + + num_disp = pigs_cnt; + return 0; } + void -labelpigs(void) +print_pg(void) { - wmove(wnd, 0, 0); - wclrtoeol(wnd); - mvwaddstr(wnd, 0, 20, - "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); + int n, count = 0; + + for (n = dispstart; n < num_disp; n++) { + showpigs(pb_indices[n]); + count++; + if (maxprint > 0 && count >= maxprint) + break; + } } int +initpigs(void) +{ + static int sysload_mib[] = {CTL_VM, VM_LOADAVG}; + static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME }; + static int ccpu_mib[] = { CTL_KERN, KERN_CCPU }; + field_view *v; + size_t size; + fixpt_t ccpu; + + size = sizeof(stime); + sysctl(cp_time_mib, 2, &stime, &size, NULL, 0); + + size = sizeof(sysload); + sysctl(sysload_mib, 2, &sysload, &size, NULL, 0); + + size = sizeof(ccpu); + sysctl(ccpu_mib, 2, &ccpu, &size, NULL, 0); + + lccpu = log((double) ccpu / sysload.fscale); + + for (v = views_pg; v->name != NULL; v++) + add_view(v); + + return(1); +} + +void +showpigs(int k) +{ + struct kinfo_proc2 *kp; + double value; + char *uname, *pname; + + if (procbase == NULL) + return; + + value = pctdouble(procbase[k].p_pctcpu) * 100; + + kp = &procbase[k]; + if (kp->p_comm[0] == '\0') { + uname = ""; + pname = "<idle>"; + } else { + uname = user_from_uid(kp->p_uid, 0); + pname = kp->p_comm; + print_fld_uint(FLD_PG_PID, kp->p_pid); + } + + tb_start(); + tbprintf("%.2f", value); + print_fld_tb(FLD_PG_VALUE); + + print_fld_str(FLD_PG_NAME, pname); + print_fld_str(FLD_PG_USER, uname); + print_fld_bar(FLD_PG_BAR, value); + + end_line(); +} + + +int compar(const void *a, const void *b) { - return (((struct p_times *)a)->pt_pctcpu > - ((struct p_times *)b)->pt_pctcpu) ? -1 : 1; + int i1 = *((int *)a); + int i2 = *((int *)b); + + return procbase[i1].p_pctcpu > + procbase[i2].p_pctcpu ? -1 : 1; } + diff --git a/usr.bin/systat/sensors.c b/usr.bin/systat/sensors.c index 98e6c56ecb9..65c0c28f3d4 100644 --- a/usr.bin/systat/sensors.c +++ b/usr.bin/systat/sensors.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sensors.c,v 1.12 2007/07/29 04:51:59 cnst Exp $ */ +/* $OpenBSD: sensors.c,v 1.13 2008/06/12 22:26:01 canacar Exp $ */ /* * Copyright (c) 2007 Deanna Phillips <deanna@openbsd.org> @@ -27,178 +27,261 @@ #include <errno.h> #include <stdio.h> #include <stdlib.h> - +#include <string.h> #include "systat.h" -#include "extern.h" struct sensor sensor; struct sensordev sensordev; -int row, sensor_cnt; -void printline(void); -static char * fmttime(double); -WINDOW * -opensensors(void) -{ - return (subwin(stdscr, LINES-1-1, 0, 1, 0)); -} +struct sensinfo { + int sn_dev; + struct sensor sn_sensor; +}; +#define sn_type sn_sensor.type +#define sn_numt sn_sensor.numt +#define sn_desc sn_sensor.desc +#define sn_status sn_sensor.status +#define sn_value sn_sensor.value -void -closesensors(WINDOW *w) +char *devnames[MAXSENSORDEVICES]; + +#define ADD_ALLOC 100 +static size_t sensor_cnt = 0; +static size_t num_alloc = 0; +static struct sensinfo *sensors = NULL; + +static char *fmttime(double); +static void showsensor(struct sensinfo *s); + +void print_sn(void); +int read_sn(void); +int select_sn(void); + +const char *drvstat[] = { + NULL, + "empty", "ready", "powerup", "online", "idle", "active", + "rebuild", "powerdown", "fail", "pfail" +}; + + +field_def fields_sn[] = { + {"SENSOR", 16, 32, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"VALUE", 16, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"STATUS", 5, 8, 1, FLD_ALIGN_CENTER, -1, 0, 0, 0}, + {"DESCRIPTION", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0} +}; + +#define FIELD_ADDR(x) (&fields_sn[x]) + +#define FLD_SN_SENSOR FIELD_ADDR(0) +#define FLD_SN_VALUE FIELD_ADDR(1) +#define FLD_SN_STATUS FIELD_ADDR(2) +#define FLD_SN_DESCR FIELD_ADDR(3) + +/* Define views */ +field_def *view_sn_0[] = { + FLD_SN_SENSOR, FLD_SN_VALUE, FLD_SN_STATUS, FLD_SN_DESCR, NULL +}; + + +/* Define view managers */ +struct view_manager sensors_mgr = { + "Sensors", select_sn, read_sn, NULL, print_header, + print_sn, keyboard_callback, NULL, NULL +}; + +field_view views_sn[] = { + {view_sn_0, "sensors", '3', &sensors_mgr}, + {NULL, NULL, 0, NULL} +}; + +struct sensinfo * +next_sn(void) { - if (w == NULL) - return; - wclear(w); - wrefresh(w); - delwin(w); + if (num_alloc <= sensor_cnt) { + struct sensinfo *s; + size_t a = num_alloc + ADD_ALLOC; + if (a < num_alloc) + return NULL; + s = realloc(sensors, a * sizeof(struct sensinfo)); + if (s == NULL) + return NULL; + sensors = s; + num_alloc = a; + } + + return &sensors[sensor_cnt++]; } -void -labelsensors(void) + +int +select_sn(void) { - wmove(wnd, 0, 0); - wclrtobot(wnd); - mvwaddstr(wnd, 1, 0, "Sensor"); - mvwaddstr(wnd, 1, 34, "Value"); - mvwaddstr(wnd, 1, 45, "Status"); - mvwaddstr(wnd, 1, 58, "Description"); + num_disp = sensor_cnt; + return (0); } -void -fetchsensors(void) +int +read_sn(void) { enum sensor_type type; size_t slen, sdlen; int mib[5], dev, numt; + struct sensinfo *s; mib[0] = CTL_HW; mib[1] = HW_SENSORS; - slen = sizeof(struct sensor); - sdlen = sizeof(struct sensordev); - row = 2; sensor_cnt = 0; - wmove(wnd, row, 0); - wclrtobot(wnd); - for (dev = 0; dev < MAXSENSORDEVICES; dev++) { mib[2] = dev; + sdlen = sizeof(struct sensordev); if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) { if (errno != ENOENT) - warn("sysctl"); + error("sysctl: %s", strerror(errno)); continue; } + + if (devnames[dev] && strcmp(devnames[dev], sensordev.xname)) { + free(devnames[dev]); + devnames[dev] = NULL; + } + if (devnames[dev] == NULL) + devnames[dev] = strdup(sensordev.xname); + for (type = 0; type < SENSOR_MAX_TYPES; type++) { mib[3] = type; for (numt = 0; numt < sensordev.maxnumt[type]; numt++) { mib[4] = numt; + slen = sizeof(struct sensor); if (sysctl(mib, 5, &sensor, &slen, NULL, 0) == -1) { if (errno != ENOENT) - warn("sysctl"); + error("sysctl: %s", strerror(errno)); continue; } if (sensor.flags & SENSOR_FINVALID) continue; - sensor_cnt++; - printline(); + + s = next_sn(); + s->sn_sensor = sensor; + s->sn_dev = dev; } } } + + num_disp = sensor_cnt; + return 0; } -const char *drvstat[] = { - NULL, - "empty", "ready", "powerup", "online", "idle", "active", - "rebuild", "powerdown", "fail", "pfail" -}; void -showsensors(void) +print_sn(void) { - if (sensor_cnt == 0) - mvwaddstr(wnd, row, 0, "No sensors found."); + int n, count = 0; + + for (n = dispstart; n < num_disp; n++) { + showsensor(sensors + n); + count++; + if (maxprint > 0 && count >= maxprint) + break; + } } int initsensors(void) { - return (1); + field_view *v; + + memset(devnames, 0, sizeof(devnames)); + + for (v = views_sn; v->name != NULL; v++) + add_view(v); + + return(1); } -void -printline(void) +static void +showsensor(struct sensinfo *s) { - mvwprintw(wnd, row, 0, "%s.%s%d", sensordev.xname, - sensor_type_s[sensor.type], sensor.numt); - switch (sensor.type) { + tb_start(); + tbprintf("%s.%s%d", devnames[s->sn_dev], + sensor_type_s[s->sn_type], s->sn_numt); + print_fld_tb(FLD_SN_SENSOR); + + if (s->sn_desc[0] != '\0') + print_fld_str(FLD_SN_DESCR, s->sn_desc); + + tb_start(); + + switch (s->sn_type) { case SENSOR_TEMP: - mvwprintw(wnd, row, 24, "%10.2f degC", - (sensor.value - 273150000) / 1000000.0); + tbprintf("%10.2f degC", + (s->sn_value - 273150000) / 1000000.0); break; case SENSOR_FANRPM: - mvwprintw(wnd, row, 24, "%11lld RPM", sensor.value); + tbprintf("%11lld RPM", s->sn_value); break; case SENSOR_VOLTS_DC: - mvwprintw(wnd, row, 24, "%10.2f V DC", - sensor.value / 1000000.0); + tbprintf("%10.2f V DC", + s->sn_value / 1000000.0); break; case SENSOR_AMPS: - mvwprintw(wnd, row, 24, "%10.2f A", sensor.value / 1000000.0); + tbprintf("%10.2f A", s->sn_value / 1000000.0); break; case SENSOR_INDICATOR: - mvwprintw(wnd, row, 24, "%15s", sensor.value? "On" : "Off"); + tbprintf("%15s", s->sn_value ? "On" : "Off"); break; case SENSOR_INTEGER: - mvwprintw(wnd, row, 24, "%11lld raw", sensor.value); + tbprintf("%11lld raw", s->sn_value); break; case SENSOR_PERCENT: - mvwprintw(wnd, row, 24, "%14.2f%%", sensor.value / 1000.0); + tbprintf("%14.2f%%", s->sn_value / 1000.0); break; case SENSOR_LUX: - mvwprintw(wnd, row, 24, "%15.2f lx", sensor.value / 1000000.0); + tbprintf("%15.2f lx", s->sn_value / 1000000.0); break; case SENSOR_DRIVE: - if (0 < sensor.value && - sensor.value < sizeof(drvstat)/sizeof(drvstat[0])) { - mvwprintw(wnd, row, 24, "%15s", drvstat[sensor.value]); + if (0 < s->sn_value && + s->sn_value < sizeof(drvstat)/sizeof(drvstat[0])) { + tbprintf("%15s", drvstat[s->sn_value]); break; } break; case SENSOR_TIMEDELTA: - mvwprintw(wnd, row, 24, "%15s", fmttime(sensor.value / 1000000000.0)); + tbprintf("%15s", fmttime(s->sn_value / 1000000000.0)); break; case SENSOR_WATTHOUR: - mvwprintw(wnd, row, 24, "%12.2f Wh", sensor.value / 1000000.0); + tbprintf("%12.2f Wh", s->sn_value / 1000000.0); break; case SENSOR_AMPHOUR: - mvwprintw(wnd, row, 24, "%10.2f Ah", sensor.value / 1000000.0); + tbprintf("%10.2f Ah", s->sn_value / 1000000.0); break; default: - mvwprintw(wnd, row, 24, "%10lld", sensor.value); + tbprintf("%10lld", s->sn_value); break; } - if (sensor.desc[0] != '\0') - mvwprintw(wnd, row, 58, "(%s)", sensor.desc); - switch (sensor.status) { + print_fld_tb(FLD_SN_VALUE); + + switch (s->sn_status) { case SENSOR_S_UNSPEC: break; case SENSOR_S_UNKNOWN: - mvwaddstr(wnd, row, 45, "unknown"); + print_fld_str(FLD_SN_STATUS, "unknown"); break; case SENSOR_S_WARN: - mvwaddstr(wnd, row, 45, "WARNING"); + print_fld_str(FLD_SN_STATUS, "WARNING"); break; case SENSOR_S_CRIT: - mvwaddstr(wnd, row, 45, "CRITICAL"); + print_fld_str(FLD_SN_STATUS, "CRITICAL"); break; case SENSOR_S_OK: - mvwaddstr(wnd, row, 45, "OK"); + print_fld_str(FLD_SN_STATUS, "OK"); break; } - row++; + end_line(); } #define SECS_PER_DAY 86400 diff --git a/usr.bin/systat/swap.c b/usr.bin/systat/swap.c index 84e55190b2b..1d8fb80c481 100644 --- a/usr.bin/systat/swap.c +++ b/usr.bin/systat/swap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: swap.c,v 1.20 2007/09/01 19:32:19 deraadt Exp $ */ +/* $OpenBSD: swap.c,v 1.21 2008/06/12 22:26:01 canacar Exp $ */ /* $NetBSD: swap.c,v 1.9 1998/12/26 07:05:08 marc Exp $ */ /*- @@ -31,13 +31,6 @@ * SUCH DAMAGE. */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)swap.c 8.3 (Berkeley) 4/29/95"; -#endif -static char rcsid[] = "$OpenBSD: swap.c,v 1.20 2007/09/01 19:32:19 deraadt Exp $"; -#endif /* not lint */ - #include <sys/cdefs.h> #include <sys/param.h> #include <sys/buf.h> @@ -53,123 +46,180 @@ static char rcsid[] = "$OpenBSD: swap.c,v 1.20 2007/09/01 19:32:19 deraadt Exp $ #include <unistd.h> #include "systat.h" -#include "extern.h" + static long blocksize; static int hlen, nswap, rnswap; -static int first = 1; static struct swapent *swap_devices; -WINDOW * -openswap(void) -{ - return (subwin(stdscr, LINES-1-2, 0, 2, 0)); -} +void print_sw(void); +int read_sw(void); +int select_sw(void); +static void showswap(int i); +static void showtotal(void); + + +field_def fields_sw[] = { + {"DISK", 6, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, + {"BLOCKS", 5, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"USED", 5, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, + {"", 40, 80, 1, FLD_ALIGN_BAR, -1, 0, 0, 100}, +}; + +#define FIELD_ADDR(x) (&fields_sw[x]) + +#define FLD_SW_NAME FIELD_ADDR(0) +#define FLD_SW_BLOCKS FIELD_ADDR(1) +#define FLD_SW_USED FIELD_ADDR(2) +#define FLD_SW_BAR FIELD_ADDR(3) + +/* Define views */ +field_def *view_sw_0[] = { + FLD_SW_NAME, FLD_SW_BLOCKS, FLD_SW_USED, FLD_SW_BAR, NULL +}; + + +/* Define view managers */ +struct view_manager swap_mgr = { + "Swap", select_sw, read_sw, NULL, print_header, + print_sw, keyboard_callback, NULL, NULL +}; + +field_view views_sw[] = { + {view_sw_0, "swap", '6', &swap_mgr}, + {NULL, NULL, 0, NULL} +}; -void -closeswap(WINDOW *w) -{ - if (w == NULL) - return; - wclear(w); - wrefresh(w); - delwin(w); -} -/* do nothing */ int -initswap(void) +select_sw(void) { - return (1); + if (swap_devices == NULL || nswap == 0) + num_disp = 1; + else + num_disp = nswap; + if (nswap > 1) + num_disp++; + return (0); } -void -fetchswap(void) +int +read_sw(void) { - int update_label = 0; + num_disp = 1; - first = 0; nswap = swapctl(SWAP_NSWAP, 0, 0); + if (nswap < 0) error("error: %s", strerror(errno)); if (nswap == 0) - return; - update_label = (nswap != rnswap); + return 0; if (swap_devices) (void)free(swap_devices); + swap_devices = (struct swapent *)calloc(nswap, sizeof(*swap_devices)); if (swap_devices == NULL) - /* XXX */ ; /* XXX systat doesn't do errors! */ + return 0; rnswap = swapctl(SWAP_STATS, (void *)swap_devices, nswap); - if (nswap < 0) - /* XXX */ ; /* XXX systat doesn't do errors! */ - if (nswap != rnswap) - /* XXX */ ; /* XXX systat doesn't do errors! */ - if (update_label) - labelswap(); + if (rnswap < 0 || nswap != rnswap) + return 0; + + num_disp = nswap; + if (nswap > 1) + num_disp++; + + return 0; } + void -labelswap(void) +print_sw(void) { - char *header; - int row; - - row = 0; - wmove(wnd, row, 0); - wclrtobot(wnd); - if (first) - fetchswap(); - if (nswap == 0) { - mvwprintw(wnd, row++, 0, "No swap"); + int n, count = 0; + + if (swap_devices == NULL || nswap == 0) { + print_fld_str(FLD_SW_BAR, "No swap devices"); return; } - header = getbsize(&hlen, &blocksize); - mvwprintw(wnd, row++, 0, "%-5s%*s%9s %55s", - "Disk", hlen, header, "Used", - "/0% /10% /20% /30% /40% /50% /60% /70% /80% /90% /100%"); + + + for (n = dispstart; n < num_disp; n++) { + if (n >= nswap) + showtotal(); + else + showswap(n); + count++; + if (maxprint > 0 && count >= maxprint) + break; + } + } -void -showswap(void) +int +initswap(void) +{ + field_view *v; + + char *bs = getbsize(&hlen, &blocksize); + + FLD_SW_BLOCKS->title = strdup(bs); + + for (v = views_sw; v->name != NULL; v++) + add_view(v); + + return(1); +} + + +static void +showswap(int i) { - int col, div, i, j, avail, used, xsize, free; + int div, used, xsize; struct swapent *sep; char *p; div = blocksize / 512; - free = avail = 0; - for (sep = swap_devices, i = 0; i < nswap; i++, sep++) { - if (sep == NULL) - continue; - p = strrchr(sep->se_path, '/'); - p = p ? p+1 : sep->se_path; + sep = &swap_devices[i]; + + p = strrchr(sep->se_path, '/'); + p = p ? p+1 : sep->se_path; + + print_fld_str(FLD_SW_NAME, p); + + xsize = sep->se_nblks; + used = sep->se_inuse; + + print_fld_uint(FLD_SW_BLOCKS, xsize / div); + print_fld_uint(FLD_SW_USED, used / div); + print_fld_bar(FLD_SW_BAR, 100 * used / xsize); - mvwprintw(wnd, i + 1, 0, "%-5s", p); + end_line(); +} + +static void +showtotal(void) +{ + struct swapent *sep; + int div, i, avail, used, xsize, free; - col = 5; - mvwprintw(wnd, i + 1, col, "%*d", hlen, sep->se_nblks / div); + div = blocksize / 512; + free = avail = 0; - col += hlen; + for (sep = swap_devices, i = 0; i < nswap; i++, sep++) { xsize = sep->se_nblks; used = sep->se_inuse; avail += xsize; free += xsize - used; - mvwprintw(wnd, i + 1, col, "%9d ", used / div); - for (j = (100 * used / xsize + 1) / 2; j > 0; j--) - waddch(wnd, 'X'); - wclrtoeol(wnd); - } - /* do total if necessary */ - if (nswap > 1) { - used = avail - free; - mvwprintw(wnd, i + 1, 0, "%-5s%*d%9d ", - "Total", hlen, avail / div, used / div); - for (j = (100 * used / avail + 1) / 2; j > 0; j--) - waddch(wnd, 'X'); - wclrtoeol(wnd); } + used = avail - free; + + print_fld_str(FLD_SW_NAME, "Total"); + print_fld_uint(FLD_SW_BLOCKS, avail / div); + print_fld_uint(FLD_SW_USED, used / div); + print_fld_bar(FLD_SW_BAR, 100 * used / avail); + + end_line(); } diff --git a/usr.bin/systat/systat.h b/usr.bin/systat/systat.h index 0175357cde4..dfd6742128a 100644 --- a/usr.bin/systat/systat.h +++ b/usr.bin/systat/systat.h @@ -1,4 +1,4 @@ -/* $OpenBSD: systat.h,v 1.8 2003/06/03 02:56:17 millert Exp $ */ +/* $OpenBSD: systat.h,v 1.9 2008/06/12 22:26:01 canacar Exp $ */ /* $NetBSD: systat.h,v 1.2 1995/01/20 08:52:14 jtc Exp $ */ /*- @@ -32,19 +32,14 @@ * @(#)systat.h 8.1 (Berkeley) 6/6/93 */ -#include <curses.h> +#ifndef _SYSTAT_H_ +#define _SYSTAT_H_ + +#include <sys/cdefs.h> +#include <fcntl.h> +#include <kvm.h> +#include "engine.h" -struct cmdtab { - char *c_name; /* command name */ - void (*c_refresh)(void); /* display refresh */ - void (*c_fetch)(void); /* sets up data structures */ - void (*c_label)(void); /* label display */ - int (*c_init)(void); /* initialize namelist, etc. */ - WINDOW *(*c_open)(void); /* open display */ - void (*c_close)(WINDOW *); /* close display */ - int (*c_cmd)(char *, char *); /* display command interpreter */ - char c_flags; /* see below */ -}; #define CF_INIT 0x1 /* been initialized */ #define CF_LOADAV 0x2 /* display w/ load average */ @@ -56,3 +51,39 @@ struct cmdtab { #define NVAL(indx) namelist[(indx)].n_value #define NPTR(indx) (void *)NVAL((indx)) #define NREAD(indx, buf, len) kvm_ckread(NPTR((indx)), (buf), (len)) +int kvm_ckread(void *, void *, size_t); + +extern char **dr_name; +extern char hostname[]; +extern double avenrun[3]; +extern kvm_t *kd; +extern long ntext; +extern int *dk_select; +extern int dk_ndrive; +extern int hz, stathz; +extern double naptime; +extern size_t nhosts; +extern size_t nports; +extern int protos; +extern int verbose; +extern int nflag; + +struct inpcb; + +void die(void); +int print_header(void); +int keyboard_callback(int); +int initnetstat(void); +int initifstat(void); +int initiostat(void); +int initsensors(void); +int initmembufs(void); +int initpigs(void); +int initswap(void); +int initvmstat(void); +int initpf(void); + +void error(const char *fmt, ...); +void nlisterr(struct nlist []); + +#endif diff --git a/usr.bin/systat/vmstat.c b/usr.bin/systat/vmstat.c index c79b7c7f5ac..c8e33e69a0c 100644 --- a/usr.bin/systat/vmstat.c +++ b/usr.bin/systat/vmstat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmstat.c,v 1.63 2007/09/01 19:32:19 deraadt Exp $ */ +/* $OpenBSD: vmstat.c,v 1.64 2008/06/12 22:26:01 canacar Exp $ */ /* $NetBSD: vmstat.c,v 1.5 1996/05/10 23:16:40 thorpej Exp $ */ /*- @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 1/12/94"; #endif -static char rcsid[] = "$OpenBSD: vmstat.c,v 1.63 2007/09/01 19:32:19 deraadt Exp $"; +static char rcsid[] = "$OpenBSD: vmstat.c,v 1.64 2008/06/12 22:26:01 canacar Exp $"; #endif /* not lint */ /* @@ -62,7 +62,6 @@ static char rcsid[] = "$OpenBSD: vmstat.c,v 1.63 2007/09/01 19:32:19 deraadt Exp #include <unistd.h> #include "systat.h" -#include "extern.h" static struct Info { long time[CPUSTATES]; @@ -71,7 +70,7 @@ static struct Info { struct nchstats nchstats; long nchcount; u_quad_t *intrcnt; -} s, s1, s2, z; +} s, s1, s2, s3, z; #include "dkstats.h" extern struct _disk cur; @@ -94,6 +93,11 @@ void putuint64(u_int64_t, int, int, int); void putfloat(double, int, int, int, int, int); int ucount(void); +void print_vm(void); +int read_vm(void); +int select_vm(void); +int vm_keyboard_callback(int); + static time_t t; static double etime; static float hertz; @@ -145,10 +149,26 @@ closekre(WINDOW *w) #define DRIVESPACE 45 /* max space for drives */ + +field_def *view_vm_0[] = { + NULL +}; + +/* Define view managers */ +struct view_manager vmstat_mgr = { + "VMstat", select_vm, read_vm, NULL, print_header, + print_vm, vm_keyboard_callback, NULL, NULL +}; + +field_view views_vm[] = { + {view_vm_0, "vmstat", '7', &vmstat_mgr}, + {NULL, NULL, 0, NULL} +}; + int ncpu = 1; int -initkre(void) +initvmstat(void) { int mib[4], i; size_t size; @@ -193,17 +213,24 @@ initkre(void) allocinfo(&s); allocinfo(&s1); allocinfo(&s2); + allocinfo(&s3); allocinfo(&z); getinfo(&s2); - copyinfo(&s2, &s1); + copyinfo(&z, &s1); + + field_view *v; + + for (v = views_vm; v->name != NULL; v++) + add_view(v); + return(1); } void fetchkre(void) { - getinfo(&s); + getinfo(&s3); } void @@ -278,10 +305,9 @@ labelkre(void) } } -#define X(fld) {t=s.fld[i]; s.fld[i]-=s1.fld[i]; if (state==TIME) s1.fld[i]=t;} -#define Y(fld) {t = s.fld; s.fld -= s1.fld; if (state == TIME) s1.fld = t;} -#define Z(fld) {t = s.nchstats.fld; s.nchstats.fld -= s1.nchstats.fld; \ - if (state == TIME) s1.nchstats.fld = t;} +#define X(fld) {s.fld[i]; s.fld[i]-=s1.fld[i];} +#define Y(fld) {s.fld; s.fld -= s1.fld;} +#define Z(fld) {s.nchstats.fld; s.nchstats.fld -= s1.nchstats.fld;} #define PUTRATE(fld, l, c, w) \ do { \ Y(fld); \ @@ -302,7 +328,6 @@ showkre(void) static int failcnt = 0, first_run = 0; if (state == TIME) { - dkswap(); if (!first_run) { first_run = 1; return; @@ -315,14 +340,8 @@ showkre(void) } if (etime < 5.0) { /* < 5 ticks - ignore this trash */ if (failcnt++ >= MAXFAIL) { - clear(); - mvprintw(2, 10, "The alternate system clock has died!"); - mvprintw(3, 10, "Reverting to ``pigs'' display."); - move(CMDLINE, 0); - refresh(); + error("The alternate system clock has died!"); failcnt = 0; - sleep(5); - command("pigs"); } return; } @@ -342,8 +361,6 @@ showkre(void) } t = intcnt = s.intrcnt[i]; s.intrcnt[i] -= s1.intrcnt[i]; - if (state == TIME) - s1.intrcnt[i] = intcnt; intcnt = (u_int64_t)((float)s.intrcnt[i]/etime + 0.5); inttotal += intcnt; putuint64(intcnt, intrloc[i], INTSCOL, 8); @@ -353,8 +370,6 @@ showkre(void) Z(ncs_long); Z(ncs_pass2); Z(ncs_2passes); s.nchcount = nchtotal.ncs_goodhits + nchtotal.ncs_badhits + nchtotal.ncs_miss + nchtotal.ncs_long; - if (state == TIME) - s1.nchcount = s.nchcount; psiz = 0; f2 = 0.0; @@ -453,31 +468,29 @@ showkre(void) } int -cmdkre(char *cmd, char *args) +vm_keyboard_callback(int ch) { - - if (prefix(cmd, "run")) { + switch(ch) { + case 'r': copyinfo(&s2, &s1); state = RUN; - return (1); - } - if (prefix(cmd, "boot")) { + break; + case 'b': state = BOOT; copyinfo(&z, &s1); - return (1); - } - if (prefix(cmd, "time")) { + break; + case 't': state = TIME; - return (1); - } - if (prefix(cmd, "zero")) { + break; + case 'z': if (state == RUN) getinfo(&s1); - return (1); + break; } - return (dkcmd(cmd, args)); + return (keyboard_callback(ch)); } + static float cputime(int indx) { @@ -603,7 +616,7 @@ getinfo(struct Info *s) static void allocinfo(struct Info *s) { - + memset(s, 0, sizeof(*s)); s->intrcnt = (u_quad_t *) calloc(nintr, sizeof(u_quad_t)); if (s->intrcnt == NULL) errx(2, "out of memory"); @@ -639,3 +652,33 @@ dinfo(int dn, int c) putint((int)(words/etime + 0.5), DISKROW + 3, c, 5); putfloat(atime/etime, DISKROW + 4, c, 5, 1, 1); } + + + +int +select_vm(void) +{ + num_disp = 0; + return (0); +} + +int +read_vm(void) +{ + if (state == TIME) + copyinfo(&s3, &s1); + fetchkre(); + if (state == TIME) + dkswap(); + num_disp = 0; + return 0; +} + + +void +print_vm(void) +{ + copyinfo(&s3, &s); + labelkre(); + showkre(); +} |