1dbed73cbSSangeeta Misra /*
2dbed73cbSSangeeta Misra * CDDL HEADER START
3dbed73cbSSangeeta Misra *
4dbed73cbSSangeeta Misra * The contents of this file are subject to the terms of the
5dbed73cbSSangeeta Misra * Common Development and Distribution License (the "License").
6dbed73cbSSangeeta Misra * You may not use this file except in compliance with the License.
7dbed73cbSSangeeta Misra *
8dbed73cbSSangeeta Misra * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9dbed73cbSSangeeta Misra * or http://www.opensolaris.org/os/licensing.
10dbed73cbSSangeeta Misra * See the License for the specific language governing permissions
11dbed73cbSSangeeta Misra * and limitations under the License.
12dbed73cbSSangeeta Misra *
13dbed73cbSSangeeta Misra * When distributing Covered Code, include this CDDL HEADER in each
14dbed73cbSSangeeta Misra * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15dbed73cbSSangeeta Misra * If applicable, add the following below this CDDL HEADER, with the
16dbed73cbSSangeeta Misra * fields enclosed by brackets "[]" replaced with your own identifying
17dbed73cbSSangeeta Misra * information: Portions Copyright [yyyy] [name of copyright owner]
18dbed73cbSSangeeta Misra *
19dbed73cbSSangeeta Misra * CDDL HEADER END
20dbed73cbSSangeeta Misra */
21dbed73cbSSangeeta Misra
22dbed73cbSSangeeta Misra /*
23dbed73cbSSangeeta Misra * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24dbed73cbSSangeeta Misra * Use is subject to license terms.
25*33f5ff17SMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved.
26dbed73cbSSangeeta Misra */
27dbed73cbSSangeeta Misra
28dbed73cbSSangeeta Misra #include <stdio.h>
29dbed73cbSSangeeta Misra #include <unistd.h>
30dbed73cbSSangeeta Misra #include <stdlib.h>
31dbed73cbSSangeeta Misra #include <strings.h>
32dbed73cbSSangeeta Misra #include <sys/types.h>
33dbed73cbSSangeeta Misra #include <sys/socket.h>
34dbed73cbSSangeeta Misra #include <sys/sysmacros.h>
35dbed73cbSSangeeta Misra #include <sys/note.h>
36dbed73cbSSangeeta Misra #include <fcntl.h>
37dbed73cbSSangeeta Misra #include <errno.h>
38dbed73cbSSangeeta Misra #include <assert.h>
39dbed73cbSSangeeta Misra #include <libgen.h>
40dbed73cbSSangeeta Misra #include <kstat.h>
41dbed73cbSSangeeta Misra #include <ofmt.h>
42dbed73cbSSangeeta Misra #include <libilb.h>
43dbed73cbSSangeeta Misra #include "ilbadm.h"
44dbed73cbSSangeeta Misra
45dbed73cbSSangeeta Misra #define ILBST_TIMESTAMP_HEADER 0x01 /* a timestamp w. every header */
46dbed73cbSSangeeta Misra #define ILBST_DELTA_INTERVAL 0x02 /* delta over specified interval */
47dbed73cbSSangeeta Misra #define ILBST_ABS_NUMBERS 0x04 /* print absolute numbers, no d's */
48dbed73cbSSangeeta Misra #define ILBST_ITEMIZE 0x08 /* itemize */
49dbed73cbSSangeeta Misra #define ILBST_VERBOSE 0x10 /* verbose error info */
50dbed73cbSSangeeta Misra
51dbed73cbSSangeeta Misra #define ILBST_OLD_VALUES 0x20 /* for internal processing */
52dbed73cbSSangeeta Misra #define ILBST_RULES_CHANGED 0x40
53dbed73cbSSangeeta Misra
54dbed73cbSSangeeta Misra typedef struct {
55dbed73cbSSangeeta Misra char is_name[KSTAT_STRLEN];
56dbed73cbSSangeeta Misra uint64_t is_value;
57dbed73cbSSangeeta Misra } ilbst_stat_t;
58dbed73cbSSangeeta Misra
59dbed73cbSSangeeta Misra static ilbst_stat_t rulestats[] = {
60dbed73cbSSangeeta Misra {"num_servers", 0},
61dbed73cbSSangeeta Misra {"bytes_not_processed", 0},
62dbed73cbSSangeeta Misra {"pkt_not_processed", 0},
63dbed73cbSSangeeta Misra {"bytes_dropped", 0},
64dbed73cbSSangeeta Misra {"pkt_dropped", 0},
65dbed73cbSSangeeta Misra {"nomem_bytes_dropped", 0},
66dbed73cbSSangeeta Misra {"nomem_pkt_dropped", 0},
67dbed73cbSSangeeta Misra {"noport_bytes_dropped", 0},
68dbed73cbSSangeeta Misra {"noport_pkt_dropped", 0},
69dbed73cbSSangeeta Misra {"icmp_echo_processed", 0},
70dbed73cbSSangeeta Misra {"icmp_dropped", 0},
71dbed73cbSSangeeta Misra {"icmp_too_big_processed", 0},
72dbed73cbSSangeeta Misra {"icmp_too_big_dropped", 0}
73dbed73cbSSangeeta Misra };
74dbed73cbSSangeeta Misra
75dbed73cbSSangeeta Misra /* indices into array above, to avoid searching */
76dbed73cbSSangeeta Misra #define RLSTA_NUM_SRV 0
77dbed73cbSSangeeta Misra #define RLSTA_BYTES_U 1
78dbed73cbSSangeeta Misra #define RLSTA_PKT_U 2
79dbed73cbSSangeeta Misra #define RLSTA_BYTES_D 3
80dbed73cbSSangeeta Misra #define RLSTA_PKT_D 4
81dbed73cbSSangeeta Misra #define RLSTA_NOMEMBYTES_D 5
82dbed73cbSSangeeta Misra #define RLSTA_NOMEMPKT_D 6
83dbed73cbSSangeeta Misra #define RLSTA_NOPORTBYTES_D 7
84dbed73cbSSangeeta Misra #define RLSTA_NOPORTPKT_D 8
85dbed73cbSSangeeta Misra #define RLSTA_ICMP_P 9
86dbed73cbSSangeeta Misra #define RLSTA_ICMP_D 10
87dbed73cbSSangeeta Misra #define RLSTA_ICMP2BIG_P 11
88dbed73cbSSangeeta Misra #define RLSTA_ICMP2BIG_D 12
89dbed73cbSSangeeta Misra
90dbed73cbSSangeeta Misra static ilbst_stat_t servstats[] = {
91dbed73cbSSangeeta Misra {"bytes_processed", 0},
92dbed73cbSSangeeta Misra {"pkt_processed", 0}
93dbed73cbSSangeeta Misra };
94dbed73cbSSangeeta Misra /* indices into array above, to avoid searching */
95dbed73cbSSangeeta Misra #define SRVST_BYTES_P 0
96dbed73cbSSangeeta Misra #define SRVST_PKT_P 1
97dbed73cbSSangeeta Misra
98dbed73cbSSangeeta Misra /* values used for of_* commands as id */
99dbed73cbSSangeeta Misra #define ILBST_PKT_P 0
100dbed73cbSSangeeta Misra #define ILBST_BYTES_P 1
101dbed73cbSSangeeta Misra #define ILBST_PKT_U 2
102dbed73cbSSangeeta Misra #define ILBST_BYTES_U 3
103dbed73cbSSangeeta Misra #define ILBST_PKT_D 4
104dbed73cbSSangeeta Misra #define ILBST_BYTES_D 5
105dbed73cbSSangeeta Misra #define ILBST_ICMP_P 6
106dbed73cbSSangeeta Misra #define ILBST_ICMP_D 7
107dbed73cbSSangeeta Misra #define ILBST_ICMP2BIG_P 8
108dbed73cbSSangeeta Misra #define ILBST_ICMP2BIG_D 9
109dbed73cbSSangeeta Misra #define ILBST_NOMEMP_D 10
110dbed73cbSSangeeta Misra #define ILBST_NOPORTP_D 11
111dbed73cbSSangeeta Misra #define ILBST_NOMEMB_D 12
112dbed73cbSSangeeta Misra #define ILBST_NOPORTB_D 13
113dbed73cbSSangeeta Misra
114dbed73cbSSangeeta Misra #define ILBST_ITEMIZE_SNAME 97
115dbed73cbSSangeeta Misra #define ILBST_ITEMIZE_RNAME 98
116dbed73cbSSangeeta Misra #define ILBST_TIMESTAMP 99
117dbed73cbSSangeeta Misra
118dbed73cbSSangeeta Misra /* approx field widths */
119dbed73cbSSangeeta Misra #define ILBST_PKTCTR_W 8
120dbed73cbSSangeeta Misra #define ILBST_BYTECTR_W 10
121dbed73cbSSangeeta Misra #define ILBST_TIME_W 15
122dbed73cbSSangeeta Misra
123dbed73cbSSangeeta Misra static boolean_t of_rule_stats(ofmt_arg_t *, char *, uint_t);
124dbed73cbSSangeeta Misra static boolean_t of_server_stats(ofmt_arg_t *, char *, uint_t);
125dbed73cbSSangeeta Misra static boolean_t of_itemize_stats(ofmt_arg_t *, char *, uint_t);
126dbed73cbSSangeeta Misra static boolean_t of_timestamp(ofmt_arg_t *, char *, uint_t);
127dbed73cbSSangeeta Misra
128dbed73cbSSangeeta Misra static ofmt_field_t stat_itemize_fields[] = {
129dbed73cbSSangeeta Misra {"RULENAME", ILB_NAMESZ, ILBST_ITEMIZE_RNAME, of_itemize_stats},
130dbed73cbSSangeeta Misra {"SERVERNAME", ILB_NAMESZ, ILBST_ITEMIZE_SNAME, of_itemize_stats},
131dbed73cbSSangeeta Misra {"PKT_P", ILBST_PKTCTR_W, ILBST_PKT_P, of_itemize_stats},
132dbed73cbSSangeeta Misra {"BYTES_P", ILBST_BYTECTR_W, ILBST_BYTES_P, of_itemize_stats},
133dbed73cbSSangeeta Misra {"TIME", ILBST_TIME_W, ILBST_TIMESTAMP, of_timestamp},
134dbed73cbSSangeeta Misra {NULL, 0, 0, NULL}
135dbed73cbSSangeeta Misra };
136dbed73cbSSangeeta Misra static ofmt_field_t stat_stdfields[] = {
137dbed73cbSSangeeta Misra {"PKT_P", ILBST_PKTCTR_W, ILBST_PKT_P, of_server_stats},
138dbed73cbSSangeeta Misra {"BYTES_P", ILBST_BYTECTR_W, ILBST_BYTES_P, of_server_stats},
139dbed73cbSSangeeta Misra {"PKT_U", ILBST_PKTCTR_W, ILBST_PKT_U, of_rule_stats},
140dbed73cbSSangeeta Misra {"BYTES_U", ILBST_BYTECTR_W, ILBST_BYTES_U, of_rule_stats},
141dbed73cbSSangeeta Misra {"PKT_D", ILBST_PKTCTR_W, ILBST_PKT_D, of_rule_stats},
142dbed73cbSSangeeta Misra {"BYTES_D", ILBST_BYTECTR_W, ILBST_BYTES_D, of_rule_stats},
143dbed73cbSSangeeta Misra {"ICMP_P", ILBST_PKTCTR_W, ILBST_ICMP_P, of_rule_stats},
144dbed73cbSSangeeta Misra {"ICMP_D", ILBST_PKTCTR_W, ILBST_ICMP_D, of_rule_stats},
145dbed73cbSSangeeta Misra {"ICMP2BIG_P", 11, ILBST_ICMP2BIG_P, of_rule_stats},
146dbed73cbSSangeeta Misra {"ICMP2BIG_D", 11, ILBST_ICMP2BIG_D, of_rule_stats},
147dbed73cbSSangeeta Misra {"NOMEMP_D", ILBST_PKTCTR_W, ILBST_NOMEMP_D, of_rule_stats},
148dbed73cbSSangeeta Misra {"NOPORTP_D", ILBST_PKTCTR_W, ILBST_NOPORTP_D, of_rule_stats},
149dbed73cbSSangeeta Misra {"NOMEMB_D", ILBST_PKTCTR_W, ILBST_NOMEMB_D, of_rule_stats},
150dbed73cbSSangeeta Misra {"NOPORTB_D", ILBST_PKTCTR_W, ILBST_NOPORTB_D, of_rule_stats},
151dbed73cbSSangeeta Misra {"TIME", ILBST_TIME_W, ILBST_TIMESTAMP, of_timestamp},
152dbed73cbSSangeeta Misra {NULL, 0, 0, NULL}
153dbed73cbSSangeeta Misra };
154dbed73cbSSangeeta Misra
155dbed73cbSSangeeta Misra static char stat_stdhdrs[] = "PKT_P,BYTES_P,PKT_U,BYTES_U,PKT_D,BYTES_D";
156dbed73cbSSangeeta Misra static char stat_stdv_hdrs[] = "PKT_P,BYTES_P,PKT_U,BYTES_U,PKT_D,BYTES_D,"
157dbed73cbSSangeeta Misra "ICMP_P,ICMP_D,ICMP2BIG_P,ICMP2BIG_D,NOMEMP_D,NOPORTP_D";
158dbed73cbSSangeeta Misra static char stat_itemize_rule_hdrs[] = "SERVERNAME,PKT_P,BYTES_P";
159dbed73cbSSangeeta Misra static char stat_itemize_server_hdrs[] = "RULENAME,PKT_P,BYTES_P";
160dbed73cbSSangeeta Misra
161dbed73cbSSangeeta Misra #define RSTAT_SZ (sizeof (rulestats)/sizeof (rulestats[0]))
162dbed73cbSSangeeta Misra #define SSTAT_SZ (sizeof (servstats)/sizeof (servstats[0]))
163dbed73cbSSangeeta Misra
164dbed73cbSSangeeta Misra typedef struct {
165dbed73cbSSangeeta Misra char isd_servername[KSTAT_STRLEN]; /* serverID */
166dbed73cbSSangeeta Misra ilbst_stat_t isd_serverstats[SSTAT_SZ];
167dbed73cbSSangeeta Misra hrtime_t isd_crtime; /* save for comparison purpose */
168dbed73cbSSangeeta Misra } ilbst_srv_desc_t;
169dbed73cbSSangeeta Misra
170dbed73cbSSangeeta Misra /*
171dbed73cbSSangeeta Misra * this data structure stores statistics for a rule - both an old set
172dbed73cbSSangeeta Misra * and a current/new set. we use pointers to the actual stores and switch
173dbed73cbSSangeeta Misra * the pointers for every round. old_is_old in ilbst_arg_t indicates
174dbed73cbSSangeeta Misra * which pointer points to the "old" data struct (ie, if true, _o pointer
175dbed73cbSSangeeta Misra * points to old)
176dbed73cbSSangeeta Misra */
177dbed73cbSSangeeta Misra typedef struct {
178dbed73cbSSangeeta Misra char ird_rulename[KSTAT_STRLEN];
179dbed73cbSSangeeta Misra int ird_num_servers;
180dbed73cbSSangeeta Misra int ird_num_servers_o;
181dbed73cbSSangeeta Misra int ird_srv_ind;
182dbed73cbSSangeeta Misra hrtime_t ird_crtime; /* save for comparison */
183dbed73cbSSangeeta Misra hrtime_t ird_crtime_o; /* save for comparison */
184dbed73cbSSangeeta Misra ilbst_srv_desc_t *ird_srvlist;
185dbed73cbSSangeeta Misra ilbst_srv_desc_t *ird_srvlist_o;
186dbed73cbSSangeeta Misra ilbst_stat_t ird_rstats[RSTAT_SZ];
187dbed73cbSSangeeta Misra ilbst_stat_t ird_rstats_o[RSTAT_SZ];
188dbed73cbSSangeeta Misra ilbst_stat_t *ird_rulestats;
189dbed73cbSSangeeta Misra ilbst_stat_t *ird_rulestats_o;
190dbed73cbSSangeeta Misra } ilbst_rule_desc_t;
191dbed73cbSSangeeta Misra
192dbed73cbSSangeeta Misra /*
193dbed73cbSSangeeta Misra * overall "container" for information pertaining to statistics, and
194dbed73cbSSangeeta Misra * how to display them.
195dbed73cbSSangeeta Misra */
196dbed73cbSSangeeta Misra typedef struct {
197dbed73cbSSangeeta Misra int ilbst_flags;
198dbed73cbSSangeeta Misra /* fields representing user input */
199dbed73cbSSangeeta Misra char *ilbst_rulename; /* optional */
200dbed73cbSSangeeta Misra char *ilbst_server; /* optional */
201dbed73cbSSangeeta Misra int ilbst_interval;
202dbed73cbSSangeeta Misra int ilbst_count;
203dbed73cbSSangeeta Misra /* "internal" fields for data and data presentation */
204dbed73cbSSangeeta Misra ofmt_handle_t ilbst_oh;
205dbed73cbSSangeeta Misra boolean_t ilbst_old_is_old;
206dbed73cbSSangeeta Misra ilbst_rule_desc_t *ilbst_rlist;
207dbed73cbSSangeeta Misra int ilbst_rcount; /* current list count */
208dbed73cbSSangeeta Misra int ilbst_rcount_prev; /* prev (different) count */
209dbed73cbSSangeeta Misra int ilbst_rlist_sz; /* number of alloc'ed rules */
210dbed73cbSSangeeta Misra int ilbst_rule_index; /* for itemizes display */
211dbed73cbSSangeeta Misra } ilbst_arg_t;
212dbed73cbSSangeeta Misra
213dbed73cbSSangeeta Misra /* ARGSUSED */
214dbed73cbSSangeeta Misra static boolean_t
of_timestamp(ofmt_arg_t * of_arg,char * buf,uint_t bufsize)215dbed73cbSSangeeta Misra of_timestamp(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
216dbed73cbSSangeeta Misra {
217dbed73cbSSangeeta Misra time_t now;
218dbed73cbSSangeeta Misra struct tm *now_tm;
219dbed73cbSSangeeta Misra
220dbed73cbSSangeeta Misra now = time(NULL);
221dbed73cbSSangeeta Misra now_tm = localtime(&now);
222dbed73cbSSangeeta Misra
223dbed73cbSSangeeta Misra (void) strftime(buf, bufsize, "%F:%H.%M.%S", now_tm);
224dbed73cbSSangeeta Misra return (B_TRUE);
225dbed73cbSSangeeta Misra }
226dbed73cbSSangeeta Misra
227dbed73cbSSangeeta Misra static boolean_t
i_sum_per_rule_processed(ilbst_rule_desc_t * rp,uint64_t * resp,int index,int flags)228dbed73cbSSangeeta Misra i_sum_per_rule_processed(ilbst_rule_desc_t *rp, uint64_t *resp, int index,
229dbed73cbSSangeeta Misra int flags)
230dbed73cbSSangeeta Misra {
231dbed73cbSSangeeta Misra int i, num_servers;
232dbed73cbSSangeeta Misra ilbst_srv_desc_t *srv, *o_srv, *n_srv;
233dbed73cbSSangeeta Misra uint64_t res = 0;
234dbed73cbSSangeeta Misra boolean_t valid = B_TRUE;
235dbed73cbSSangeeta Misra boolean_t old = flags & ILBST_OLD_VALUES;
236dbed73cbSSangeeta Misra boolean_t check_valid;
237dbed73cbSSangeeta Misra
238dbed73cbSSangeeta Misra /* if we do abs. numbers, we never look at the _o fields */
239dbed73cbSSangeeta Misra assert((old && (flags & ILBST_ABS_NUMBERS)) == B_FALSE);
240dbed73cbSSangeeta Misra
241dbed73cbSSangeeta Misra /* we only check for validity under certain conditions */
242dbed73cbSSangeeta Misra check_valid = !(old || (flags & ILBST_ABS_NUMBERS));
243dbed73cbSSangeeta Misra
244dbed73cbSSangeeta Misra if (check_valid && rp->ird_num_servers != rp->ird_num_servers_o)
245dbed73cbSSangeeta Misra valid = B_FALSE;
246dbed73cbSSangeeta Misra
247dbed73cbSSangeeta Misra num_servers = old ? rp->ird_num_servers_o : rp->ird_num_servers;
248dbed73cbSSangeeta Misra
249dbed73cbSSangeeta Misra for (i = 0; i < num_servers; i++) {
250dbed73cbSSangeeta Misra n_srv = &rp->ird_srvlist[i];
251dbed73cbSSangeeta Misra o_srv = &rp->ird_srvlist_o[i];
252dbed73cbSSangeeta Misra
253dbed73cbSSangeeta Misra if (old)
254dbed73cbSSangeeta Misra srv = o_srv;
255dbed73cbSSangeeta Misra else
256dbed73cbSSangeeta Misra srv = n_srv;
257dbed73cbSSangeeta Misra
258dbed73cbSSangeeta Misra res += srv->isd_serverstats[index].is_value;
259dbed73cbSSangeeta Misra /*
260dbed73cbSSangeeta Misra * if creation times don't match, comparison is wrong; if
261dbed73cbSSangeeta Misra * if we already know something is invalid, we don't
262dbed73cbSSangeeta Misra * need to compare again.
263dbed73cbSSangeeta Misra */
264dbed73cbSSangeeta Misra if (check_valid && valid == B_TRUE &&
265dbed73cbSSangeeta Misra o_srv->isd_crtime != n_srv->isd_crtime) {
266dbed73cbSSangeeta Misra valid = B_FALSE;
267dbed73cbSSangeeta Misra break;
268dbed73cbSSangeeta Misra }
269dbed73cbSSangeeta Misra }
270dbed73cbSSangeeta Misra /*
271dbed73cbSSangeeta Misra * save the result even though it may be imprecise - let the
272dbed73cbSSangeeta Misra * caller decide what to do
273dbed73cbSSangeeta Misra */
274dbed73cbSSangeeta Misra *resp = res;
275dbed73cbSSangeeta Misra
276dbed73cbSSangeeta Misra return (valid);
277dbed73cbSSangeeta Misra }
278dbed73cbSSangeeta Misra
279dbed73cbSSangeeta Misra typedef boolean_t (*sumfunc_t)(ilbst_rule_desc_t *, uint64_t *, int);
280dbed73cbSSangeeta Misra
281dbed73cbSSangeeta Misra static boolean_t
i_sum_per_rule_pkt_p(ilbst_rule_desc_t * rp,uint64_t * resp,int flags)282dbed73cbSSangeeta Misra i_sum_per_rule_pkt_p(ilbst_rule_desc_t *rp, uint64_t *resp, int flags)
283dbed73cbSSangeeta Misra {
284dbed73cbSSangeeta Misra return (i_sum_per_rule_processed(rp, resp, SRVST_PKT_P, flags));
285dbed73cbSSangeeta Misra }
286dbed73cbSSangeeta Misra
287dbed73cbSSangeeta Misra static boolean_t
i_sum_per_rule_bytes_p(ilbst_rule_desc_t * rp,uint64_t * resp,int flags)288dbed73cbSSangeeta Misra i_sum_per_rule_bytes_p(ilbst_rule_desc_t *rp, uint64_t *resp, int flags)
289dbed73cbSSangeeta Misra {
290dbed73cbSSangeeta Misra return (i_sum_per_rule_processed(rp, resp, SRVST_BYTES_P, flags));
291dbed73cbSSangeeta Misra }
292dbed73cbSSangeeta Misra
293dbed73cbSSangeeta Misra static boolean_t
of_server_stats(ofmt_arg_t * of_arg,char * buf,uint_t bufsize)294dbed73cbSSangeeta Misra of_server_stats(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
295dbed73cbSSangeeta Misra {
296dbed73cbSSangeeta Misra ilbst_arg_t *sta = (ilbst_arg_t *)of_arg->ofmt_cbarg;
297dbed73cbSSangeeta Misra uint64_t count = 0, val;
298dbed73cbSSangeeta Misra int i;
299dbed73cbSSangeeta Misra boolean_t valid = B_TRUE;
300dbed73cbSSangeeta Misra sumfunc_t sumfunc;
301dbed73cbSSangeeta Misra
302dbed73cbSSangeeta Misra switch (of_arg->ofmt_id) {
303dbed73cbSSangeeta Misra case ILBST_PKT_P: sumfunc = i_sum_per_rule_pkt_p;
304dbed73cbSSangeeta Misra break;
305dbed73cbSSangeeta Misra case ILBST_BYTES_P: sumfunc = i_sum_per_rule_bytes_p;
306dbed73cbSSangeeta Misra break;
307dbed73cbSSangeeta Misra }
308dbed73cbSSangeeta Misra
309dbed73cbSSangeeta Misra for (i = 0; i < sta->ilbst_rcount; i++) {
310dbed73cbSSangeeta Misra valid = sumfunc(&sta->ilbst_rlist[i], &val, sta->ilbst_flags);
311dbed73cbSSangeeta Misra if (!valid)
312dbed73cbSSangeeta Misra return (valid);
313dbed73cbSSangeeta Misra count += val;
314dbed73cbSSangeeta Misra }
315dbed73cbSSangeeta Misra
316dbed73cbSSangeeta Misra if ((sta->ilbst_flags & ILBST_ABS_NUMBERS) != 0)
317dbed73cbSSangeeta Misra goto out;
318dbed73cbSSangeeta Misra
319dbed73cbSSangeeta Misra for (i = 0; i < sta->ilbst_rcount; i++) {
320dbed73cbSSangeeta Misra (void) sumfunc(&sta->ilbst_rlist[i], &val,
321dbed73cbSSangeeta Misra sta->ilbst_flags | ILBST_OLD_VALUES);
322dbed73cbSSangeeta Misra count -= val;
323dbed73cbSSangeeta Misra }
324dbed73cbSSangeeta Misra
325dbed73cbSSangeeta Misra out:
326dbed73cbSSangeeta Misra /*
327dbed73cbSSangeeta Misra * normally, we print "change per second", which we calculate
328dbed73cbSSangeeta Misra * here. otherwise, we print "change over interval"
329dbed73cbSSangeeta Misra */
330dbed73cbSSangeeta Misra if ((sta->ilbst_flags & (ILBST_DELTA_INTERVAL|ILBST_ABS_NUMBERS)) == 0)
331dbed73cbSSangeeta Misra count /= sta->ilbst_interval;
332dbed73cbSSangeeta Misra
333dbed73cbSSangeeta Misra (void) snprintf(buf, bufsize, "%llu", count);
334dbed73cbSSangeeta Misra return (B_TRUE);
335dbed73cbSSangeeta Misra }
336dbed73cbSSangeeta Misra
337dbed73cbSSangeeta Misra /*
338dbed73cbSSangeeta Misra * this function is called when user wants itemized stats of every
339dbed73cbSSangeeta Misra * server for a named rule, or vice vera.
340dbed73cbSSangeeta Misra * i_do_print sets sta->rule_index and the proper ird_srv_ind so
341dbed73cbSSangeeta Misra * we don't have to differentiate between these two cases here.
342dbed73cbSSangeeta Misra */
343dbed73cbSSangeeta Misra static boolean_t
of_itemize_stats(ofmt_arg_t * of_arg,char * buf,uint_t bufsize)344dbed73cbSSangeeta Misra of_itemize_stats(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
345dbed73cbSSangeeta Misra {
346dbed73cbSSangeeta Misra ilbst_arg_t *sta = (ilbst_arg_t *)of_arg->ofmt_cbarg;
347dbed73cbSSangeeta Misra int stat_ind;
348dbed73cbSSangeeta Misra uint64_t count;
349dbed73cbSSangeeta Misra int rule_index = sta->ilbst_rule_index;
350dbed73cbSSangeeta Misra int srv_ind = sta->ilbst_rlist[rule_index].ird_srv_ind;
351dbed73cbSSangeeta Misra boolean_t ret = B_TRUE;
352dbed73cbSSangeeta Misra ilbst_srv_desc_t *srv, *osrv;
353dbed73cbSSangeeta Misra
354dbed73cbSSangeeta Misra srv = &sta->ilbst_rlist[rule_index].ird_srvlist[srv_ind];
355dbed73cbSSangeeta Misra
356dbed73cbSSangeeta Misra switch (of_arg->ofmt_id) {
357dbed73cbSSangeeta Misra case ILBST_PKT_P: stat_ind = SRVST_PKT_P;
358dbed73cbSSangeeta Misra break;
359dbed73cbSSangeeta Misra case ILBST_BYTES_P: stat_ind = SRVST_BYTES_P;
360dbed73cbSSangeeta Misra break;
361dbed73cbSSangeeta Misra case ILBST_ITEMIZE_RNAME:
362dbed73cbSSangeeta Misra (void) snprintf(buf, bufsize, "%s",
363dbed73cbSSangeeta Misra sta->ilbst_rlist[rule_index].ird_rulename);
364dbed73cbSSangeeta Misra return (B_TRUE);
365dbed73cbSSangeeta Misra case ILBST_ITEMIZE_SNAME:
366dbed73cbSSangeeta Misra (void) snprintf(buf, bufsize, "%s", srv->isd_servername);
367dbed73cbSSangeeta Misra return (B_TRUE);
368dbed73cbSSangeeta Misra }
369dbed73cbSSangeeta Misra
370dbed73cbSSangeeta Misra count = srv->isd_serverstats[stat_ind].is_value;
371dbed73cbSSangeeta Misra
372dbed73cbSSangeeta Misra if ((sta->ilbst_flags & ILBST_ABS_NUMBERS) != 0)
373dbed73cbSSangeeta Misra goto out;
374dbed73cbSSangeeta Misra
375dbed73cbSSangeeta Misra osrv = &sta->ilbst_rlist[rule_index].ird_srvlist_o[srv_ind];
376dbed73cbSSangeeta Misra if (srv->isd_crtime != osrv->isd_crtime)
377dbed73cbSSangeeta Misra ret = B_FALSE;
378dbed73cbSSangeeta Misra
379dbed73cbSSangeeta Misra count -= osrv->isd_serverstats[stat_ind].is_value;
380dbed73cbSSangeeta Misra out:
381dbed73cbSSangeeta Misra /*
382dbed73cbSSangeeta Misra * normally, we print "change per second", which we calculate
383dbed73cbSSangeeta Misra * here. otherwise, we print "change over interval" or absolute
384dbed73cbSSangeeta Misra * values.
385dbed73cbSSangeeta Misra */
386dbed73cbSSangeeta Misra if ((sta->ilbst_flags & (ILBST_DELTA_INTERVAL|ILBST_ABS_NUMBERS)) == 0)
387dbed73cbSSangeeta Misra count /= sta->ilbst_interval;
388dbed73cbSSangeeta Misra
389dbed73cbSSangeeta Misra (void) snprintf(buf, bufsize, "%llu", count);
390dbed73cbSSangeeta Misra return (ret);
391dbed73cbSSangeeta Misra
392dbed73cbSSangeeta Misra }
393dbed73cbSSangeeta Misra
394dbed73cbSSangeeta Misra static boolean_t
of_rule_stats(ofmt_arg_t * of_arg,char * buf,uint_t bufsize)395dbed73cbSSangeeta Misra of_rule_stats(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
396dbed73cbSSangeeta Misra {
397dbed73cbSSangeeta Misra ilbst_arg_t *sta = (ilbst_arg_t *)of_arg->ofmt_cbarg;
398dbed73cbSSangeeta Misra int i, ind;
399dbed73cbSSangeeta Misra uint64_t count = 0;
400dbed73cbSSangeeta Misra
401dbed73cbSSangeeta Misra switch (of_arg->ofmt_id) {
402dbed73cbSSangeeta Misra case ILBST_PKT_U: ind = RLSTA_PKT_U;
403dbed73cbSSangeeta Misra break;
404dbed73cbSSangeeta Misra case ILBST_BYTES_U: ind = RLSTA_BYTES_U;
405dbed73cbSSangeeta Misra break;
406dbed73cbSSangeeta Misra case ILBST_PKT_D: ind = RLSTA_PKT_D;
407dbed73cbSSangeeta Misra break;
408dbed73cbSSangeeta Misra case ILBST_BYTES_D: ind = RLSTA_BYTES_D;
409dbed73cbSSangeeta Misra break;
410dbed73cbSSangeeta Misra case ILBST_ICMP_P: ind = RLSTA_ICMP_P;
411dbed73cbSSangeeta Misra break;
412dbed73cbSSangeeta Misra case ILBST_ICMP_D: ind = RLSTA_ICMP_D;
413dbed73cbSSangeeta Misra break;
414dbed73cbSSangeeta Misra case ILBST_ICMP2BIG_P: ind = RLSTA_ICMP2BIG_P;
415dbed73cbSSangeeta Misra break;
416dbed73cbSSangeeta Misra case ILBST_ICMP2BIG_D: ind = RLSTA_ICMP2BIG_D;
417dbed73cbSSangeeta Misra break;
418dbed73cbSSangeeta Misra case ILBST_NOMEMP_D: ind = RLSTA_NOMEMPKT_D;
419dbed73cbSSangeeta Misra break;
420dbed73cbSSangeeta Misra case ILBST_NOPORTP_D: ind = RLSTA_NOPORTPKT_D;
421dbed73cbSSangeeta Misra break;
422dbed73cbSSangeeta Misra case ILBST_NOMEMB_D: ind = RLSTA_NOMEMBYTES_D;
423dbed73cbSSangeeta Misra break;
424dbed73cbSSangeeta Misra case ILBST_NOPORTB_D: ind = RLSTA_NOPORTBYTES_D;
425dbed73cbSSangeeta Misra break;
426dbed73cbSSangeeta Misra }
427dbed73cbSSangeeta Misra
428dbed73cbSSangeeta Misra for (i = 0; i < sta->ilbst_rcount; i++)
429dbed73cbSSangeeta Misra count += sta->ilbst_rlist[i].ird_rulestats[ind].is_value;
430dbed73cbSSangeeta Misra
431dbed73cbSSangeeta Misra if ((sta->ilbst_flags & ILBST_ABS_NUMBERS) != 0)
432dbed73cbSSangeeta Misra goto out;
433dbed73cbSSangeeta Misra
434dbed73cbSSangeeta Misra /*
435dbed73cbSSangeeta Misra * the purist approach: if we can't say 100% that what we
436dbed73cbSSangeeta Misra * calculate is correct, don't.
437dbed73cbSSangeeta Misra */
438dbed73cbSSangeeta Misra if (sta->ilbst_flags & ILBST_RULES_CHANGED)
439dbed73cbSSangeeta Misra return (B_FALSE);
440dbed73cbSSangeeta Misra
441dbed73cbSSangeeta Misra for (i = 0; i < sta->ilbst_rcount; i++) {
442dbed73cbSSangeeta Misra if (sta->ilbst_rlist[i].ird_crtime_o != 0 &&
443dbed73cbSSangeeta Misra sta->ilbst_rlist[i].ird_crtime !=
444dbed73cbSSangeeta Misra sta->ilbst_rlist[i].ird_crtime_o)
445dbed73cbSSangeeta Misra return (B_FALSE);
446dbed73cbSSangeeta Misra
447dbed73cbSSangeeta Misra count -= sta->ilbst_rlist[i].ird_rulestats_o[ind].is_value;
448dbed73cbSSangeeta Misra }
449dbed73cbSSangeeta Misra out:
450dbed73cbSSangeeta Misra /*
451dbed73cbSSangeeta Misra * normally, we print "change per second", which we calculate
452dbed73cbSSangeeta Misra * here. otherwise, we print "change over interval"
453dbed73cbSSangeeta Misra */
454dbed73cbSSangeeta Misra if ((sta->ilbst_flags & (ILBST_DELTA_INTERVAL|ILBST_ABS_NUMBERS)) == 0)
455dbed73cbSSangeeta Misra count /= sta->ilbst_interval;
456dbed73cbSSangeeta Misra
457dbed73cbSSangeeta Misra (void) snprintf(buf, bufsize, "%llu", count);
458dbed73cbSSangeeta Misra return (B_TRUE);
459dbed73cbSSangeeta Misra }
460dbed73cbSSangeeta Misra
461dbed73cbSSangeeta Misra /*
462dbed73cbSSangeeta Misra * Get the number of kstat instances. Note that when rules are being
463dbed73cbSSangeeta Misra * drained the number of kstats instances may be different than the
464dbed73cbSSangeeta Misra * kstat counter num_rules (ilb:0:global:num_rules").
465dbed73cbSSangeeta Misra *
466dbed73cbSSangeeta Misra * Also there can be multiple instances of a rule in the following
467dbed73cbSSangeeta Misra * scenario:
468dbed73cbSSangeeta Misra *
469dbed73cbSSangeeta Misra * A rule named rule A has been deleted but remains in kstats because
470dbed73cbSSangeeta Misra * its undergoing connection draining. During this time, the user adds
471dbed73cbSSangeeta Misra * a new rule with the same name(rule A). In this case, there would
472dbed73cbSSangeeta Misra * be two kstats instances for rule A. Currently ilbadm's aggregate
473dbed73cbSSangeeta Misra * results will include data from both instances of rule A. In,
474dbed73cbSSangeeta Misra * future we should have ilbadm stats only consider the latest instance
475dbed73cbSSangeeta Misra * of the rule (ie only consider the the instance that corresponds
476dbed73cbSSangeeta Misra * to the rule that was just added).
477dbed73cbSSangeeta Misra *
478dbed73cbSSangeeta Misra */
479dbed73cbSSangeeta Misra static int
i_get_num_kinstances(kstat_ctl_t * kctl)480dbed73cbSSangeeta Misra i_get_num_kinstances(kstat_ctl_t *kctl)
481dbed73cbSSangeeta Misra {
482dbed73cbSSangeeta Misra kstat_t *kp;
483dbed73cbSSangeeta Misra int num_instances = 0; /* nothing found, 0 rules */
484dbed73cbSSangeeta Misra
485dbed73cbSSangeeta Misra for (kp = kctl->kc_chain; kp != NULL; kp = kp->ks_next) {
486dbed73cbSSangeeta Misra if (strncmp("rulestat", kp->ks_class, 8) == 0 &&
487dbed73cbSSangeeta Misra strncmp("ilb", kp->ks_module, 3) == 0) {
488dbed73cbSSangeeta Misra num_instances++;
489dbed73cbSSangeeta Misra }
490dbed73cbSSangeeta Misra }
491dbed73cbSSangeeta Misra
492dbed73cbSSangeeta Misra return (num_instances);
493dbed73cbSSangeeta Misra }
494dbed73cbSSangeeta Misra
495dbed73cbSSangeeta Misra
496dbed73cbSSangeeta Misra /*
497dbed73cbSSangeeta Misra * since server stat's classname is made up of <rulename>-sstat,
498dbed73cbSSangeeta Misra * we walk the rule list to construct the comparison
499dbed73cbSSangeeta Misra * Return: pointer to rule whose name matches the class
500dbed73cbSSangeeta Misra * NULL if no match
501dbed73cbSSangeeta Misra */
502dbed73cbSSangeeta Misra static ilbst_rule_desc_t *
match_2_rnames(char * class,ilbst_rule_desc_t * rlist,int rcount)503dbed73cbSSangeeta Misra match_2_rnames(char *class, ilbst_rule_desc_t *rlist, int rcount)
504dbed73cbSSangeeta Misra {
505dbed73cbSSangeeta Misra int i;
506dbed73cbSSangeeta Misra char classname[KSTAT_STRLEN];
507dbed73cbSSangeeta Misra
508dbed73cbSSangeeta Misra for (i = 0; i < rcount; i++) {
509dbed73cbSSangeeta Misra (void) snprintf(classname, sizeof (classname), "%s-sstat",
510dbed73cbSSangeeta Misra rlist[i].ird_rulename);
511dbed73cbSSangeeta Misra if (strncmp(classname, class, sizeof (classname)) == 0)
512dbed73cbSSangeeta Misra return (&rlist[i]);
513dbed73cbSSangeeta Misra }
514dbed73cbSSangeeta Misra return (NULL);
515dbed73cbSSangeeta Misra }
516dbed73cbSSangeeta Misra
517dbed73cbSSangeeta Misra static int
i_stat_index(kstat_named_t * knp,ilbst_stat_t * stats,int count)518dbed73cbSSangeeta Misra i_stat_index(kstat_named_t *knp, ilbst_stat_t *stats, int count)
519dbed73cbSSangeeta Misra {
520dbed73cbSSangeeta Misra int i;
521dbed73cbSSangeeta Misra
522dbed73cbSSangeeta Misra for (i = 0; i < count; i++) {
523dbed73cbSSangeeta Misra if (strcasecmp(stats[i].is_name, knp->name) == 0)
524dbed73cbSSangeeta Misra return (i);
525dbed73cbSSangeeta Misra }
526dbed73cbSSangeeta Misra
527dbed73cbSSangeeta Misra return (-1);
528dbed73cbSSangeeta Misra }
529dbed73cbSSangeeta Misra
530dbed73cbSSangeeta Misra static void
i_copy_sstats(ilbst_srv_desc_t * sp,kstat_t * kp)531dbed73cbSSangeeta Misra i_copy_sstats(ilbst_srv_desc_t *sp, kstat_t *kp)
532dbed73cbSSangeeta Misra {
533dbed73cbSSangeeta Misra kstat_named_t *knp;
534dbed73cbSSangeeta Misra int i, ind;
535dbed73cbSSangeeta Misra
536dbed73cbSSangeeta Misra knp = KSTAT_NAMED_PTR(kp);
537dbed73cbSSangeeta Misra for (i = 0; i < kp->ks_ndata; i++, knp++) {
538dbed73cbSSangeeta Misra ind = i_stat_index(knp, servstats, SSTAT_SZ);
539dbed73cbSSangeeta Misra if (ind == -1)
540dbed73cbSSangeeta Misra continue;
541dbed73cbSSangeeta Misra (void) strlcpy(sp->isd_serverstats[ind].is_name, knp->name,
542dbed73cbSSangeeta Misra sizeof (sp->isd_serverstats[ind].is_name));
543dbed73cbSSangeeta Misra sp->isd_serverstats[ind].is_value = knp->value.ui64;
544dbed73cbSSangeeta Misra sp->isd_crtime = kp->ks_crtime;
545dbed73cbSSangeeta Misra }
546dbed73cbSSangeeta Misra }
547dbed73cbSSangeeta Misra
548dbed73cbSSangeeta Misra
549dbed73cbSSangeeta Misra static ilbadm_status_t
i_get_server_descs(ilbst_arg_t * sta,kstat_ctl_t * kctl)550dbed73cbSSangeeta Misra i_get_server_descs(ilbst_arg_t *sta, kstat_ctl_t *kctl)
551dbed73cbSSangeeta Misra {
552dbed73cbSSangeeta Misra ilbadm_status_t rc = ILBADM_OK;
553dbed73cbSSangeeta Misra kstat_t *kp;
554dbed73cbSSangeeta Misra int i = -1;
555dbed73cbSSangeeta Misra ilbst_rule_desc_t *rp;
556dbed73cbSSangeeta Misra ilbst_rule_desc_t *rlist = sta->ilbst_rlist;
557dbed73cbSSangeeta Misra int rcount = sta->ilbst_rcount;
558dbed73cbSSangeeta Misra
559dbed73cbSSangeeta Misra /*
560dbed73cbSSangeeta Misra * find all "server" kstats, or the one specified in
561dbed73cbSSangeeta Misra * sta->server
562dbed73cbSSangeeta Misra */
563dbed73cbSSangeeta Misra for (kp = kctl->kc_chain; kp != NULL; kp = kp->ks_next) {
564dbed73cbSSangeeta Misra if (strncmp("ilb", kp->ks_module, 3) != 0)
565dbed73cbSSangeeta Misra continue;
566dbed73cbSSangeeta Misra if (sta->ilbst_server != NULL &&
567dbed73cbSSangeeta Misra strcasecmp(sta->ilbst_server, kp->ks_name) != 0)
568dbed73cbSSangeeta Misra continue;
569dbed73cbSSangeeta Misra rp = match_2_rnames(kp->ks_class, rlist, rcount);
570dbed73cbSSangeeta Misra if (rp == NULL)
571dbed73cbSSangeeta Misra continue;
572dbed73cbSSangeeta Misra
573dbed73cbSSangeeta Misra (void) kstat_read(kctl, kp, NULL);
574dbed73cbSSangeeta Misra i = rp->ird_srv_ind++;
575dbed73cbSSangeeta Misra
576dbed73cbSSangeeta Misra rc = ILBADM_OK;
577dbed73cbSSangeeta Misra /*
578dbed73cbSSangeeta Misra * This means that a server is added after we check last
579dbed73cbSSangeeta Misra * time... Just make the array bigger.
580dbed73cbSSangeeta Misra */
581dbed73cbSSangeeta Misra if (i+1 > rp->ird_num_servers) {
582dbed73cbSSangeeta Misra ilbst_srv_desc_t *srvlist;
583dbed73cbSSangeeta Misra
584dbed73cbSSangeeta Misra if ((srvlist = realloc(rp->ird_srvlist, (i+1) *
585dbed73cbSSangeeta Misra sizeof (*srvlist))) == NULL) {
586dbed73cbSSangeeta Misra rc = ILBADM_ENOMEM;
587dbed73cbSSangeeta Misra break;
588dbed73cbSSangeeta Misra }
589dbed73cbSSangeeta Misra rp->ird_srvlist = srvlist;
590dbed73cbSSangeeta Misra rp->ird_num_servers = i;
591dbed73cbSSangeeta Misra }
592dbed73cbSSangeeta Misra
593dbed73cbSSangeeta Misra (void) strlcpy(rp->ird_srvlist[i].isd_servername, kp->ks_name,
594dbed73cbSSangeeta Misra sizeof (rp->ird_srvlist[i].isd_servername));
595dbed73cbSSangeeta Misra i_copy_sstats(&rp->ird_srvlist[i], kp);
596dbed73cbSSangeeta Misra }
597dbed73cbSSangeeta Misra
598dbed73cbSSangeeta Misra for (i = 0; i < rcount; i++)
599dbed73cbSSangeeta Misra rlist[i].ird_srv_ind = 0;
600dbed73cbSSangeeta Misra
601dbed73cbSSangeeta Misra if (sta->ilbst_server != NULL && i == -1)
602dbed73cbSSangeeta Misra rc = ILBADM_ENOSERVER;
603dbed73cbSSangeeta Misra return (rc);
604dbed73cbSSangeeta Misra }
605dbed73cbSSangeeta Misra
606dbed73cbSSangeeta Misra static void
i_copy_rstats(ilbst_rule_desc_t * rp,kstat_t * kp)607dbed73cbSSangeeta Misra i_copy_rstats(ilbst_rule_desc_t *rp, kstat_t *kp)
608dbed73cbSSangeeta Misra {
609dbed73cbSSangeeta Misra kstat_named_t *knp;
610dbed73cbSSangeeta Misra int i, ind;
611dbed73cbSSangeeta Misra
612dbed73cbSSangeeta Misra knp = KSTAT_NAMED_PTR(kp);
613dbed73cbSSangeeta Misra for (i = 0; i < kp->ks_ndata; i++, knp++) {
614dbed73cbSSangeeta Misra ind = i_stat_index(knp, rulestats, RSTAT_SZ);
615dbed73cbSSangeeta Misra if (ind == -1)
616dbed73cbSSangeeta Misra continue;
617dbed73cbSSangeeta Misra
618dbed73cbSSangeeta Misra (void) strlcpy(rp->ird_rulestats[ind].is_name, knp->name,
619dbed73cbSSangeeta Misra sizeof (rp->ird_rulestats[ind].is_name));
620dbed73cbSSangeeta Misra rp->ird_rulestats[ind].is_value = knp->value.ui64;
621dbed73cbSSangeeta Misra }
622dbed73cbSSangeeta Misra }
623dbed73cbSSangeeta Misra
624dbed73cbSSangeeta Misra static void
i_set_rlstats_ptr(ilbst_rule_desc_t * rp,boolean_t old_is_old)625dbed73cbSSangeeta Misra i_set_rlstats_ptr(ilbst_rule_desc_t *rp, boolean_t old_is_old)
626dbed73cbSSangeeta Misra {
627dbed73cbSSangeeta Misra if (old_is_old) {
628dbed73cbSSangeeta Misra rp->ird_rulestats = rp->ird_rstats;
629dbed73cbSSangeeta Misra rp->ird_rulestats_o = rp->ird_rstats_o;
630dbed73cbSSangeeta Misra } else {
631dbed73cbSSangeeta Misra rp->ird_rulestats = rp->ird_rstats_o;
632dbed73cbSSangeeta Misra rp->ird_rulestats_o = rp->ird_rstats;
633dbed73cbSSangeeta Misra }
634dbed73cbSSangeeta Misra }
635dbed73cbSSangeeta Misra /*
636dbed73cbSSangeeta Misra * this function walks the array of rules and switches pointer to old
637dbed73cbSSangeeta Misra * and new stats as well as serverlists.
638dbed73cbSSangeeta Misra */
639dbed73cbSSangeeta Misra static void
i_swap_rl_pointers(ilbst_arg_t * sta,int rcount)640dbed73cbSSangeeta Misra i_swap_rl_pointers(ilbst_arg_t *sta, int rcount)
641dbed73cbSSangeeta Misra {
642dbed73cbSSangeeta Misra int i, tmp_num;
643dbed73cbSSangeeta Misra ilbst_rule_desc_t *rlist = sta->ilbst_rlist;
644dbed73cbSSangeeta Misra ilbst_srv_desc_t *tmp_srv;
645dbed73cbSSangeeta Misra
646dbed73cbSSangeeta Misra for (i = 0; i < rcount; i++) {
647dbed73cbSSangeeta Misra /* swap srvlist pointers */
648dbed73cbSSangeeta Misra tmp_srv = rlist[i].ird_srvlist;
649dbed73cbSSangeeta Misra rlist[i].ird_srvlist = rlist[i].ird_srvlist_o;
650dbed73cbSSangeeta Misra rlist[i].ird_srvlist_o = tmp_srv;
651dbed73cbSSangeeta Misra
652dbed73cbSSangeeta Misra /*
653dbed73cbSSangeeta Misra * swap server counts - we need the old one to
654dbed73cbSSangeeta Misra * save reallocation calls
655dbed73cbSSangeeta Misra */
656dbed73cbSSangeeta Misra tmp_num = rlist[i].ird_num_servers_o;
657dbed73cbSSangeeta Misra rlist[i].ird_num_servers_o = rlist[i].ird_num_servers;
658dbed73cbSSangeeta Misra rlist[i].ird_num_servers = tmp_num;
659dbed73cbSSangeeta Misra
660dbed73cbSSangeeta Misra /* preserve creation time */
661dbed73cbSSangeeta Misra rlist[i].ird_crtime_o = rlist[i].ird_crtime;
662dbed73cbSSangeeta Misra
663dbed73cbSSangeeta Misra i_set_rlstats_ptr(&rlist[i], sta->ilbst_old_is_old);
664dbed73cbSSangeeta Misra rlist[i].ird_srv_ind = 0;
665dbed73cbSSangeeta Misra }
666dbed73cbSSangeeta Misra }
667dbed73cbSSangeeta Misra
668dbed73cbSSangeeta Misra static void
i_init_rulelist(ilbst_arg_t * sta,int rcount)669dbed73cbSSangeeta Misra i_init_rulelist(ilbst_arg_t *sta, int rcount)
670dbed73cbSSangeeta Misra {
671dbed73cbSSangeeta Misra int i;
672dbed73cbSSangeeta Misra ilbst_rule_desc_t *rlist = sta->ilbst_rlist;
673dbed73cbSSangeeta Misra
674dbed73cbSSangeeta Misra for (i = 0; i < rcount; i++) {
675dbed73cbSSangeeta Misra rlist[i].ird_rulestats = rlist[i].ird_rstats;
676dbed73cbSSangeeta Misra rlist[i].ird_rulestats_o = rlist[i].ird_rstats_o;
677dbed73cbSSangeeta Misra rlist[i].ird_srv_ind = 0;
678dbed73cbSSangeeta Misra }
679dbed73cbSSangeeta Misra }
680dbed73cbSSangeeta Misra
681dbed73cbSSangeeta Misra
682dbed73cbSSangeeta Misra /*
683dbed73cbSSangeeta Misra * this function searches for kstats describing individual rules and
684dbed73cbSSangeeta Misra * saves name, # of servers, and the kstat_t * describing them (this is
685dbed73cbSSangeeta Misra * for sta->rulename == NULL);
686dbed73cbSSangeeta Misra * if sta->rulename != NULL, it names the rule we're looking for
687dbed73cbSSangeeta Misra * and this function will fill in the other data (like the all_rules case)
688dbed73cbSSangeeta Misra * Returns: ILBADM_ENORULE named rule not found
689dbed73cbSSangeeta Misra * ILBADM_ENOMEM no mem. available
690dbed73cbSSangeeta Misra */
691dbed73cbSSangeeta Misra static ilbadm_status_t
i_get_rule_descs(ilbst_arg_t * sta,kstat_ctl_t * kctl)692dbed73cbSSangeeta Misra i_get_rule_descs(ilbst_arg_t *sta, kstat_ctl_t *kctl)
693dbed73cbSSangeeta Misra {
694dbed73cbSSangeeta Misra ilbadm_status_t rc = ILBADM_OK;
695dbed73cbSSangeeta Misra kstat_t *kp;
696dbed73cbSSangeeta Misra kstat_named_t *knp;
697dbed73cbSSangeeta Misra int i;
698dbed73cbSSangeeta Misra int num_servers;
699dbed73cbSSangeeta Misra ilbst_rule_desc_t *rlist = sta->ilbst_rlist;
700dbed73cbSSangeeta Misra int rcount = sta->ilbst_rcount;
701dbed73cbSSangeeta Misra
702dbed73cbSSangeeta Misra /*
703dbed73cbSSangeeta Misra * find all "rule" kstats, or the one specified in
704dbed73cbSSangeeta Misra * sta->ilbst_rulename.
705dbed73cbSSangeeta Misra */
706dbed73cbSSangeeta Misra for (i = 0, kp = kctl->kc_chain; i < rcount && kp != NULL;
707dbed73cbSSangeeta Misra kp = kp->ks_next) {
708dbed73cbSSangeeta Misra if (strncmp("rulestat", kp->ks_class, 8) != 0 ||
709dbed73cbSSangeeta Misra strncmp("ilb", kp->ks_module, 3) != 0)
710dbed73cbSSangeeta Misra continue;
711dbed73cbSSangeeta Misra
712dbed73cbSSangeeta Misra (void) kstat_read(kctl, kp, NULL);
713dbed73cbSSangeeta Misra
714dbed73cbSSangeeta Misra knp = kstat_data_lookup(kp, "num_servers");
715dbed73cbSSangeeta Misra if (knp == NULL) {
716dbed73cbSSangeeta Misra ilbadm_err(gettext("kstat_data_lookup() failed: %s"),
717dbed73cbSSangeeta Misra strerror(errno));
718dbed73cbSSangeeta Misra rc = ILBADM_LIBERR;
719dbed73cbSSangeeta Misra break;
720dbed73cbSSangeeta Misra }
721dbed73cbSSangeeta Misra if (sta->ilbst_rulename != NULL) {
722dbed73cbSSangeeta Misra if (strcasecmp(kp->ks_name, sta->ilbst_rulename)
723dbed73cbSSangeeta Misra != 0)
724dbed73cbSSangeeta Misra continue;
725dbed73cbSSangeeta Misra }
726dbed73cbSSangeeta Misra (void) strlcpy(rlist[i].ird_rulename, kp->ks_name,
727dbed73cbSSangeeta Misra sizeof (rlist[i].ird_rulename));
728dbed73cbSSangeeta Misra
729dbed73cbSSangeeta Misra /* only alloc the space we need, set counter here ... */
730dbed73cbSSangeeta Misra if (sta->ilbst_server != NULL)
731dbed73cbSSangeeta Misra num_servers = 1;
732dbed73cbSSangeeta Misra else
733dbed73cbSSangeeta Misra num_servers = (int)knp->value.ui64;
734dbed73cbSSangeeta Misra
735dbed73cbSSangeeta Misra /* ... furthermore, only reallocate if necessary */
736dbed73cbSSangeeta Misra if (num_servers != rlist[i].ird_num_servers) {
737dbed73cbSSangeeta Misra ilbst_srv_desc_t *srvlist;
738dbed73cbSSangeeta Misra
739dbed73cbSSangeeta Misra rlist[i].ird_num_servers = num_servers;
740dbed73cbSSangeeta Misra
741dbed73cbSSangeeta Misra if (rlist[i].ird_srvlist == NULL)
742dbed73cbSSangeeta Misra srvlist = calloc(num_servers,
743dbed73cbSSangeeta Misra sizeof (*srvlist));
744dbed73cbSSangeeta Misra else
745dbed73cbSSangeeta Misra srvlist = realloc(rlist[i].ird_srvlist,
746dbed73cbSSangeeta Misra sizeof (*srvlist) * num_servers);
747dbed73cbSSangeeta Misra if (srvlist == NULL) {
748dbed73cbSSangeeta Misra rc = ILBADM_ENOMEM;
749dbed73cbSSangeeta Misra break;
750dbed73cbSSangeeta Misra }
751dbed73cbSSangeeta Misra rlist[i].ird_srvlist = srvlist;
752dbed73cbSSangeeta Misra }
753dbed73cbSSangeeta Misra rlist[i].ird_srv_ind = 0;
754dbed73cbSSangeeta Misra rlist[i].ird_crtime = kp->ks_crtime;
755dbed73cbSSangeeta Misra
756dbed73cbSSangeeta Misra i_copy_rstats(&rlist[i], kp);
757dbed73cbSSangeeta Misra i++;
758dbed73cbSSangeeta Misra
759dbed73cbSSangeeta Misra /* if we know we're done, return */
760dbed73cbSSangeeta Misra if (sta->ilbst_rulename != NULL || i == rcount) {
761dbed73cbSSangeeta Misra rc = ILBADM_OK;
762dbed73cbSSangeeta Misra break;
763dbed73cbSSangeeta Misra }
764dbed73cbSSangeeta Misra }
765dbed73cbSSangeeta Misra
766dbed73cbSSangeeta Misra if (sta->ilbst_rulename != NULL && i == 0)
767dbed73cbSSangeeta Misra rc = ILBADM_ENORULE;
768dbed73cbSSangeeta Misra return (rc);
769dbed73cbSSangeeta Misra }
770dbed73cbSSangeeta Misra
771dbed73cbSSangeeta Misra static void
i_do_print(ilbst_arg_t * sta)772dbed73cbSSangeeta Misra i_do_print(ilbst_arg_t *sta)
773dbed73cbSSangeeta Misra {
774dbed73cbSSangeeta Misra int i;
775dbed73cbSSangeeta Misra
776dbed73cbSSangeeta Misra /* non-itemized display can go right ahead */
777dbed73cbSSangeeta Misra if ((sta->ilbst_flags & ILBST_ITEMIZE) == 0) {
778dbed73cbSSangeeta Misra ofmt_print(sta->ilbst_oh, sta);
779dbed73cbSSangeeta Misra return;
780dbed73cbSSangeeta Misra }
781dbed73cbSSangeeta Misra
782dbed73cbSSangeeta Misra /*
783dbed73cbSSangeeta Misra * rulename is given, list a line per server
784dbed73cbSSangeeta Misra * here's how we do it:
785dbed73cbSSangeeta Misra * the _ITEMIZE flag indicates to the print function (called
786dbed73cbSSangeeta Misra * from ofmt_print()) to look at server [ird_srv_ind] only.
787dbed73cbSSangeeta Misra */
788dbed73cbSSangeeta Misra if (sta->ilbst_rulename != NULL) {
789dbed73cbSSangeeta Misra sta->ilbst_rule_index = 0;
790dbed73cbSSangeeta Misra for (i = 0; i < sta->ilbst_rlist->ird_num_servers; i++) {
791dbed73cbSSangeeta Misra sta->ilbst_rlist->ird_srv_ind = i;
792dbed73cbSSangeeta Misra ofmt_print(sta->ilbst_oh, sta);
793dbed73cbSSangeeta Misra }
794dbed73cbSSangeeta Misra sta->ilbst_rlist->ird_srv_ind = 0;
795dbed73cbSSangeeta Misra return;
796dbed73cbSSangeeta Misra }
797dbed73cbSSangeeta Misra
798dbed73cbSSangeeta Misra /* list one line for every rule for a given server */
799dbed73cbSSangeeta Misra for (i = 0; i < sta->ilbst_rcount; i++) {
800dbed73cbSSangeeta Misra /*
801dbed73cbSSangeeta Misra * if a rule doesn't contain a given server, there's no
802dbed73cbSSangeeta Misra * need to print it. Luckily, we can check that
803dbed73cbSSangeeta Misra * fairly easily
804dbed73cbSSangeeta Misra */
805dbed73cbSSangeeta Misra if (sta->ilbst_rlist[i].ird_srvlist[0].isd_servername[0] ==
806dbed73cbSSangeeta Misra '\0')
807dbed73cbSSangeeta Misra continue;
808dbed73cbSSangeeta Misra
809dbed73cbSSangeeta Misra sta->ilbst_rule_index = i;
810dbed73cbSSangeeta Misra sta->ilbst_rlist[i].ird_srv_ind = 0;
811dbed73cbSSangeeta Misra ofmt_print(sta->ilbst_oh, sta);
812dbed73cbSSangeeta Misra }
813dbed73cbSSangeeta Misra sta->ilbst_rule_index = 0;
814dbed73cbSSangeeta Misra }
815dbed73cbSSangeeta Misra
816dbed73cbSSangeeta Misra static ilbadm_status_t
i_do_show_stats(ilbst_arg_t * sta)817dbed73cbSSangeeta Misra i_do_show_stats(ilbst_arg_t *sta)
818dbed73cbSSangeeta Misra {
819dbed73cbSSangeeta Misra kstat_ctl_t *kctl;
820dbed73cbSSangeeta Misra kid_t nkid;
821dbed73cbSSangeeta Misra int rcount = 1, i;
822dbed73cbSSangeeta Misra ilbadm_status_t rc = ILBADM_OK;
823dbed73cbSSangeeta Misra ilbst_rule_desc_t *rlist, *rp;
824dbed73cbSSangeeta Misra boolean_t pseudo_abs = B_FALSE; /* for first pass */
825dbed73cbSSangeeta Misra
826dbed73cbSSangeeta Misra if ((kctl = kstat_open()) == NULL) {
827dbed73cbSSangeeta Misra ilbadm_err(gettext("kstat_open() failed: %s"), strerror(errno));
828dbed73cbSSangeeta Misra return (ILBADM_LIBERR);
829dbed73cbSSangeeta Misra }
830dbed73cbSSangeeta Misra
831dbed73cbSSangeeta Misra
832dbed73cbSSangeeta Misra if (sta->ilbst_rulename == NULL)
833dbed73cbSSangeeta Misra rcount = i_get_num_kinstances(kctl);
834dbed73cbSSangeeta Misra
835dbed73cbSSangeeta Misra rlist = calloc(sizeof (*rlist), rcount);
836dbed73cbSSangeeta Misra if (rlist == NULL) {
837dbed73cbSSangeeta Misra rc = ILBADM_ENOMEM;
838dbed73cbSSangeeta Misra goto out;
839dbed73cbSSangeeta Misra }
840dbed73cbSSangeeta Misra
841dbed73cbSSangeeta Misra sta->ilbst_old_is_old = B_TRUE;
842dbed73cbSSangeeta Misra sta->ilbst_rlist = rlist;
843dbed73cbSSangeeta Misra sta->ilbst_rcount = sta->ilbst_rcount_prev = rcount;
844dbed73cbSSangeeta Misra sta->ilbst_rlist_sz = rcount;
845dbed73cbSSangeeta Misra
846dbed73cbSSangeeta Misra /*
847dbed73cbSSangeeta Misra * in the first pass, we always print absolute numbers. We
848dbed73cbSSangeeta Misra * need to remember whether we wanted abs. numbers for
849dbed73cbSSangeeta Misra * other samples as well
850dbed73cbSSangeeta Misra */
851dbed73cbSSangeeta Misra if ((sta->ilbst_flags & ILBST_ABS_NUMBERS) == 0) {
852dbed73cbSSangeeta Misra sta->ilbst_flags |= ILBST_ABS_NUMBERS;
853dbed73cbSSangeeta Misra pseudo_abs = B_TRUE;
854dbed73cbSSangeeta Misra }
855dbed73cbSSangeeta Misra
856dbed73cbSSangeeta Misra i_init_rulelist(sta, rcount);
857dbed73cbSSangeeta Misra do {
858dbed73cbSSangeeta Misra rc = i_get_rule_descs(sta, kctl);
859dbed73cbSSangeeta Misra if (rc != ILBADM_OK)
860dbed73cbSSangeeta Misra goto out;
861dbed73cbSSangeeta Misra
862dbed73cbSSangeeta Misra rc = i_get_server_descs(sta, kctl);
863dbed73cbSSangeeta Misra if (rc != ILBADM_OK)
864dbed73cbSSangeeta Misra goto out;
865dbed73cbSSangeeta Misra
866dbed73cbSSangeeta Misra i_do_print(sta);
867dbed73cbSSangeeta Misra
868dbed73cbSSangeeta Misra if (sta->ilbst_count == -1 || --(sta->ilbst_count) > 0)
869dbed73cbSSangeeta Misra (void) sleep(sta->ilbst_interval);
870dbed73cbSSangeeta Misra else
871dbed73cbSSangeeta Misra break;
872dbed73cbSSangeeta Misra
873dbed73cbSSangeeta Misra nkid = kstat_chain_update(kctl);
874dbed73cbSSangeeta Misra sta->ilbst_flags &= ~ILBST_RULES_CHANGED;
875dbed73cbSSangeeta Misra /*
876dbed73cbSSangeeta Misra * we only need to continue with most of the rest of this if
877dbed73cbSSangeeta Misra * the kstat chain id has changed
878dbed73cbSSangeeta Misra */
879dbed73cbSSangeeta Misra if (nkid == 0)
880dbed73cbSSangeeta Misra goto swap_old_new;
881dbed73cbSSangeeta Misra if (nkid == -1) {
882dbed73cbSSangeeta Misra ilbadm_err(gettext("kstat_chain_update() failed: %s"),
883dbed73cbSSangeeta Misra strerror(errno));
884dbed73cbSSangeeta Misra rc = ILBADM_LIBERR;
885dbed73cbSSangeeta Misra break;
886dbed73cbSSangeeta Misra }
887dbed73cbSSangeeta Misra
888dbed73cbSSangeeta Misra /*
889dbed73cbSSangeeta Misra * find out whether the number of rules has changed.
890dbed73cbSSangeeta Misra * if so, adjust rcount and _o; if number has increased,
891dbed73cbSSangeeta Misra * expand array to hold all rules.
892dbed73cbSSangeeta Misra * we only shrink if rlist_sz is larger than both rcount and
893dbed73cbSSangeeta Misra * rcount_prev;
894dbed73cbSSangeeta Misra */
895dbed73cbSSangeeta Misra if (sta->ilbst_rulename == NULL)
896dbed73cbSSangeeta Misra rcount = i_get_num_kinstances(kctl);
897dbed73cbSSangeeta Misra if (rcount != sta->ilbst_rcount) {
898dbed73cbSSangeeta Misra sta->ilbst_flags |= ILBST_RULES_CHANGED;
899dbed73cbSSangeeta Misra sta->ilbst_rcount_prev = sta->ilbst_rcount;
900dbed73cbSSangeeta Misra sta->ilbst_rcount = rcount;
901dbed73cbSSangeeta Misra
902dbed73cbSSangeeta Misra if (rcount > sta->ilbst_rcount_prev) {
903dbed73cbSSangeeta Misra rlist = realloc(sta->ilbst_rlist,
904dbed73cbSSangeeta Misra sizeof (*sta->ilbst_rlist) * rcount);
905dbed73cbSSangeeta Misra if (rlist == NULL) {
906dbed73cbSSangeeta Misra rc = ILBADM_ENOMEM;
907dbed73cbSSangeeta Misra break;
908dbed73cbSSangeeta Misra }
909dbed73cbSSangeeta Misra sta->ilbst_rlist = rlist;
910dbed73cbSSangeeta Misra /* realloc doesn't zero out memory */
911dbed73cbSSangeeta Misra for (i = sta->ilbst_rcount_prev;
912dbed73cbSSangeeta Misra i < rcount; i++) {
913dbed73cbSSangeeta Misra rp = &sta->ilbst_rlist[i];
914dbed73cbSSangeeta Misra bzero(rp, sizeof (*rp));
915dbed73cbSSangeeta Misra i_set_rlstats_ptr(rp,
916dbed73cbSSangeeta Misra sta->ilbst_old_is_old);
917dbed73cbSSangeeta Misra }
918dbed73cbSSangeeta Misra /*
919dbed73cbSSangeeta Misra * even if rlist_sz was > rcount, it's now
920dbed73cbSSangeeta Misra * shrunk to rcount
921dbed73cbSSangeeta Misra */
922dbed73cbSSangeeta Misra sta->ilbst_rlist_sz = sta->ilbst_rcount;
923dbed73cbSSangeeta Misra }
924dbed73cbSSangeeta Misra }
925dbed73cbSSangeeta Misra
926dbed73cbSSangeeta Misra /*
927dbed73cbSSangeeta Misra * we may need to shrink the allocated slots down to the
928dbed73cbSSangeeta Misra * actually required number - we need to make sure we
929dbed73cbSSangeeta Misra * don't delete old or new stats.
930dbed73cbSSangeeta Misra */
931dbed73cbSSangeeta Misra if (sta->ilbst_rlist_sz > MAX(sta->ilbst_rcount,
932dbed73cbSSangeeta Misra sta->ilbst_rcount_prev)) {
933dbed73cbSSangeeta Misra sta->ilbst_rlist_sz =
934dbed73cbSSangeeta Misra MAX(sta->ilbst_rcount, sta->ilbst_rcount_prev);
935dbed73cbSSangeeta Misra rlist = realloc(sta->ilbst_rlist,
936dbed73cbSSangeeta Misra sizeof (*sta->ilbst_rlist) * sta->ilbst_rlist_sz);
937dbed73cbSSangeeta Misra if (rlist == NULL) {
938dbed73cbSSangeeta Misra rc = ILBADM_ENOMEM;
939dbed73cbSSangeeta Misra break;
940dbed73cbSSangeeta Misra }
941dbed73cbSSangeeta Misra sta->ilbst_rlist = rlist;
942dbed73cbSSangeeta Misra }
943dbed73cbSSangeeta Misra
944dbed73cbSSangeeta Misra /*
945dbed73cbSSangeeta Misra * move pointers around so what used to point to "old"
946dbed73cbSSangeeta Misra * stats now points to new, and vice versa
947dbed73cbSSangeeta Misra * if we're printing absolute numbers, this rigmarole is
948dbed73cbSSangeeta Misra * not necessary.
949dbed73cbSSangeeta Misra */
950dbed73cbSSangeeta Misra swap_old_new:
951dbed73cbSSangeeta Misra if (pseudo_abs)
952dbed73cbSSangeeta Misra sta->ilbst_flags &= ~ILBST_ABS_NUMBERS;
953dbed73cbSSangeeta Misra
954dbed73cbSSangeeta Misra if ((sta->ilbst_flags & ILBST_ABS_NUMBERS) == 0) {
955dbed73cbSSangeeta Misra sta->ilbst_old_is_old = !sta->ilbst_old_is_old;
956dbed73cbSSangeeta Misra i_swap_rl_pointers(sta, rcount);
957dbed73cbSSangeeta Misra }
958dbed73cbSSangeeta Misra _NOTE(CONSTCOND)
959dbed73cbSSangeeta Misra } while (B_TRUE);
960dbed73cbSSangeeta Misra
961dbed73cbSSangeeta Misra out:
962dbed73cbSSangeeta Misra (void) kstat_close(kctl);
963dbed73cbSSangeeta Misra if ((rc != ILBADM_OK) && (rc != ILBADM_LIBERR))
964dbed73cbSSangeeta Misra ilbadm_err(ilbadm_errstr(rc));
965dbed73cbSSangeeta Misra
966dbed73cbSSangeeta Misra if (sta->ilbst_rlist != NULL)
967dbed73cbSSangeeta Misra free(sta->ilbst_rlist);
968dbed73cbSSangeeta Misra
969dbed73cbSSangeeta Misra return (rc);
970dbed73cbSSangeeta Misra }
971dbed73cbSSangeeta Misra
972dbed73cbSSangeeta Misra /*
973dbed73cbSSangeeta Misra * read ilb's kernel statistics and (periodically) display
974dbed73cbSSangeeta Misra * them.
975dbed73cbSSangeeta Misra */
976dbed73cbSSangeeta Misra /* ARGSUSED */
977dbed73cbSSangeeta Misra ilbadm_status_t
ilbadm_show_stats(int argc,char * argv[])978dbed73cbSSangeeta Misra ilbadm_show_stats(int argc, char *argv[])
979dbed73cbSSangeeta Misra {
980dbed73cbSSangeeta Misra ilbadm_status_t rc;
981dbed73cbSSangeeta Misra int c;
982dbed73cbSSangeeta Misra ilbst_arg_t sta;
983dbed73cbSSangeeta Misra int oflags = 0;
984dbed73cbSSangeeta Misra char *fieldnames = stat_stdhdrs;
985dbed73cbSSangeeta Misra ofmt_field_t *fields = stat_stdfields;
986dbed73cbSSangeeta Misra boolean_t r_opt = B_FALSE, s_opt = B_FALSE, i_opt = B_FALSE;
987dbed73cbSSangeeta Misra boolean_t o_opt = B_FALSE, p_opt = B_FALSE, t_opt = B_FALSE;
988dbed73cbSSangeeta Misra boolean_t v_opt = B_FALSE, A_opt = B_FALSE, d_opt = B_FALSE;
989dbed73cbSSangeeta Misra ofmt_status_t oerr;
990dbed73cbSSangeeta Misra ofmt_handle_t oh = NULL;
991dbed73cbSSangeeta Misra
992dbed73cbSSangeeta Misra bzero(&sta, sizeof (sta));
993dbed73cbSSangeeta Misra sta.ilbst_interval = 1;
994dbed73cbSSangeeta Misra sta.ilbst_count = 1;
995dbed73cbSSangeeta Misra
996dbed73cbSSangeeta Misra while ((c = getopt(argc, argv, ":tdAr:s:ivo:p")) != -1) {
997dbed73cbSSangeeta Misra switch ((char)c) {
998dbed73cbSSangeeta Misra case 't': sta.ilbst_flags |= ILBST_TIMESTAMP_HEADER;
999dbed73cbSSangeeta Misra t_opt = B_TRUE;
1000dbed73cbSSangeeta Misra break;
1001dbed73cbSSangeeta Misra case 'd': sta.ilbst_flags |= ILBST_DELTA_INTERVAL;
1002dbed73cbSSangeeta Misra d_opt = B_TRUE;
1003dbed73cbSSangeeta Misra break;
1004dbed73cbSSangeeta Misra case 'A': sta.ilbst_flags |= ILBST_ABS_NUMBERS;
1005dbed73cbSSangeeta Misra A_opt = B_TRUE;
1006dbed73cbSSangeeta Misra break;
1007dbed73cbSSangeeta Misra case 'r': sta.ilbst_rulename = optarg;
1008dbed73cbSSangeeta Misra r_opt = B_TRUE;
1009dbed73cbSSangeeta Misra break;
1010dbed73cbSSangeeta Misra case 's': sta.ilbst_server = optarg;
1011dbed73cbSSangeeta Misra s_opt = B_TRUE;
1012dbed73cbSSangeeta Misra break;
1013dbed73cbSSangeeta Misra case 'i': sta.ilbst_flags |= ILBST_ITEMIZE;
1014dbed73cbSSangeeta Misra i_opt = B_TRUE;
1015dbed73cbSSangeeta Misra break;
1016dbed73cbSSangeeta Misra case 'o': fieldnames = optarg;
1017dbed73cbSSangeeta Misra o_opt = B_TRUE;
1018dbed73cbSSangeeta Misra break;
1019dbed73cbSSangeeta Misra case 'p': oflags |= OFMT_PARSABLE;
1020dbed73cbSSangeeta Misra p_opt = B_TRUE;
1021dbed73cbSSangeeta Misra break;
1022dbed73cbSSangeeta Misra case 'v': sta.ilbst_flags |= ILBST_VERBOSE;
1023dbed73cbSSangeeta Misra v_opt = B_TRUE;
1024dbed73cbSSangeeta Misra fieldnames = stat_stdv_hdrs;
1025dbed73cbSSangeeta Misra break;
1026dbed73cbSSangeeta Misra case ':': ilbadm_err(gettext("missing option-argument"
1027dbed73cbSSangeeta Misra " detected for %c"), (char)optopt);
1028dbed73cbSSangeeta Misra exit(1);
1029dbed73cbSSangeeta Misra /* not reached */
1030dbed73cbSSangeeta Misra break;
1031dbed73cbSSangeeta Misra case '?': /* fallthrough */
1032dbed73cbSSangeeta Misra default:
1033dbed73cbSSangeeta Misra unknown_opt(argv, optind-1);
1034dbed73cbSSangeeta Misra /* not reached */
1035dbed73cbSSangeeta Misra break;
1036dbed73cbSSangeeta Misra }
1037dbed73cbSSangeeta Misra }
1038dbed73cbSSangeeta Misra
1039dbed73cbSSangeeta Misra if (s_opt && r_opt) {
1040dbed73cbSSangeeta Misra ilbadm_err(gettext("options -s and -r are mutually exclusive"));
1041dbed73cbSSangeeta Misra exit(1);
1042dbed73cbSSangeeta Misra }
1043dbed73cbSSangeeta Misra
1044dbed73cbSSangeeta Misra if (i_opt) {
1045dbed73cbSSangeeta Misra if (!(s_opt || r_opt)) {
1046dbed73cbSSangeeta Misra ilbadm_err(gettext("option -i requires"
1047dbed73cbSSangeeta Misra " either -r or -s"));
1048dbed73cbSSangeeta Misra exit(1);
1049dbed73cbSSangeeta Misra }
1050dbed73cbSSangeeta Misra if (v_opt) {
1051dbed73cbSSangeeta Misra ilbadm_err(gettext("option -i and -v are mutually"
1052dbed73cbSSangeeta Misra " exclusive"));
1053dbed73cbSSangeeta Misra exit(1);
1054dbed73cbSSangeeta Misra }
1055dbed73cbSSangeeta Misra /* only use "std" headers if none are specified */
1056dbed73cbSSangeeta Misra if (!o_opt)
1057dbed73cbSSangeeta Misra if (r_opt)
1058dbed73cbSSangeeta Misra fieldnames = stat_itemize_rule_hdrs;
1059dbed73cbSSangeeta Misra else /* must be s_opt */
1060dbed73cbSSangeeta Misra fieldnames = stat_itemize_server_hdrs;
1061dbed73cbSSangeeta Misra fields = stat_itemize_fields;
1062dbed73cbSSangeeta Misra }
1063dbed73cbSSangeeta Misra
1064dbed73cbSSangeeta Misra if (p_opt) {
1065dbed73cbSSangeeta Misra if (!o_opt) {
1066dbed73cbSSangeeta Misra ilbadm_err(gettext("option -p requires -o"));
1067dbed73cbSSangeeta Misra exit(1);
1068dbed73cbSSangeeta Misra }
1069dbed73cbSSangeeta Misra if (v_opt) {
1070dbed73cbSSangeeta Misra ilbadm_err(gettext("option -o and -v are mutually"
1071dbed73cbSSangeeta Misra " exclusive"));
1072dbed73cbSSangeeta Misra exit(1);
1073dbed73cbSSangeeta Misra }
1074dbed73cbSSangeeta Misra if (strcasecmp(fieldnames, "all") == 0) {
1075dbed73cbSSangeeta Misra ilbadm_err(gettext("option -p requires"
1076dbed73cbSSangeeta Misra " explicit field names"));
1077dbed73cbSSangeeta Misra exit(1);
1078dbed73cbSSangeeta Misra }
1079dbed73cbSSangeeta Misra }
1080dbed73cbSSangeeta Misra
1081dbed73cbSSangeeta Misra if (t_opt) {
1082dbed73cbSSangeeta Misra if (v_opt) {
1083dbed73cbSSangeeta Misra fieldnames = "all";
1084dbed73cbSSangeeta Misra } else {
1085dbed73cbSSangeeta Misra int len = strlen(fieldnames) + 6;
1086dbed73cbSSangeeta Misra char *fnames;
1087dbed73cbSSangeeta Misra
1088dbed73cbSSangeeta Misra fnames = malloc(len);
1089dbed73cbSSangeeta Misra if (fnames == NULL) {
1090dbed73cbSSangeeta Misra rc = ILBADM_ENOMEM;
1091dbed73cbSSangeeta Misra return (rc);
1092dbed73cbSSangeeta Misra }
1093dbed73cbSSangeeta Misra (void) snprintf(fnames, len, "%s,TIME", fieldnames);
1094dbed73cbSSangeeta Misra fieldnames = fnames;
1095dbed73cbSSangeeta Misra }
1096dbed73cbSSangeeta Misra }
1097dbed73cbSSangeeta Misra
1098dbed73cbSSangeeta Misra if (A_opt && d_opt) {
1099dbed73cbSSangeeta Misra ilbadm_err(gettext("options -d and -A are mutually exclusive"));
1100dbed73cbSSangeeta Misra exit(1);
1101dbed73cbSSangeeta Misra }
1102dbed73cbSSangeeta Misra
1103dbed73cbSSangeeta Misra /* find and parse interval and count arguments if present */
1104dbed73cbSSangeeta Misra if (optind < argc) {
1105dbed73cbSSangeeta Misra sta.ilbst_interval = atoi(argv[optind]);
1106dbed73cbSSangeeta Misra if (sta.ilbst_interval < 1) {
1107dbed73cbSSangeeta Misra ilbadm_err(gettext("illegal interval spec %s"),
1108dbed73cbSSangeeta Misra argv[optind]);
1109dbed73cbSSangeeta Misra exit(1);
1110dbed73cbSSangeeta Misra }
1111dbed73cbSSangeeta Misra sta.ilbst_count = -1;
1112dbed73cbSSangeeta Misra if (++optind < argc) {
1113dbed73cbSSangeeta Misra sta.ilbst_count = atoi(argv[optind]);
1114dbed73cbSSangeeta Misra if (sta.ilbst_count < 1) {
1115dbed73cbSSangeeta Misra ilbadm_err(gettext("illegal count spec %s"),
1116dbed73cbSSangeeta Misra argv[optind]);
1117dbed73cbSSangeeta Misra exit(1);
1118dbed73cbSSangeeta Misra }
1119dbed73cbSSangeeta Misra }
1120dbed73cbSSangeeta Misra }
1121dbed73cbSSangeeta Misra
1122dbed73cbSSangeeta Misra oerr = ofmt_open(fieldnames, fields, oflags, 80, &oh);
1123dbed73cbSSangeeta Misra if (oerr != OFMT_SUCCESS) {
1124dbed73cbSSangeeta Misra char e[80];
1125dbed73cbSSangeeta Misra
1126dbed73cbSSangeeta Misra ilbadm_err(gettext("ofmt_open failed: %s"),
1127dbed73cbSSangeeta Misra ofmt_strerror(oh, oerr, e, sizeof (e)));
1128dbed73cbSSangeeta Misra return (ILBADM_LIBERR);
1129dbed73cbSSangeeta Misra }
1130dbed73cbSSangeeta Misra
1131dbed73cbSSangeeta Misra sta.ilbst_oh = oh;
1132dbed73cbSSangeeta Misra
1133dbed73cbSSangeeta Misra rc = i_do_show_stats(&sta);
1134dbed73cbSSangeeta Misra
1135dbed73cbSSangeeta Misra ofmt_close(oh);
1136dbed73cbSSangeeta Misra return (rc);
1137dbed73cbSSangeeta Misra }
1138