diff options
author | Can Erkin Acar <canacar@cvs.openbsd.org> | 2008-06-12 22:26:02 +0000 |
---|---|---|
committer | Can Erkin Acar <canacar@cvs.openbsd.org> | 2008-06-12 22:26:02 +0000 |
commit | b9a4c5ecbb7b24c30bc7d0fbafe253b83026f627 (patch) | |
tree | 6cd4b5a419df6b4260809ea551cbfb11d2d82d2c | |
parent | d45105968c2b2c26e15fe4f7d2115e6e5eedf613 (diff) |
New display engine for systat, based on pftop. Adds new views for pf
(status, state, rule, queue). While all displays work, some keyboard
comands are not implemented yet. Other features include better handling
of display resize and scrolling for long views. Committing now to fix
the remaining issues in the tree.
Testing and comments by otto@ and harding@, ok deraadt@
-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(); +} |