Print this page
patch relling-feedback
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/rpcsvc/rstat_proc.c
+++ new/usr/src/cmd/rpcsvc/rstat_proc.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 -#pragma ident "%Z%%M% %I% %E% SMI"
27 -
28 26 /*
29 27 * rstat service: built with rstat.x
30 28 */
31 29
32 30 #include <stdio.h>
33 31 #include <stdlib.h>
34 32 #include <stdarg.h>
35 33 #include <string.h>
36 34 #include <signal.h>
37 35 #include <utmpx.h>
38 36 #include <nlist.h>
39 37 #include <fcntl.h>
40 38 #include <syslog.h>
41 39 #include <kstat.h>
42 40
43 41 #include <rpc/rpc.h>
44 42
45 43 #include <sys/socket.h>
46 44 #include <sys/cpuvar.h>
47 45 #include <sys/sysinfo.h>
48 46 #include <sys/systm.h>
49 47 #include <errno.h>
50 48 #include <sys/stropts.h>
51 49 #include <sys/tihdr.h>
52 50 #include <sys/sysmacros.h>
53 51
54 52 #include <net/if.h>
55 53 #include <inet/mib2.h>
56 54
57 55 #include "rstat.h"
58 56 #include "rstat_v2.h"
59 57
60 58 typedef struct {
61 59 kstat_t sys;
62 60 kstat_t vm;
63 61 } _cpu_stats_t;
64 62
65 63 /*
66 64 * system and cpu stats
67 65 */
68 66 static kstat_ctl_t *kc; /* libkstat cookie */
69 67 static int ncpus;
70 68 static _cpu_stats_t *cpu_stats_list = NULL;
71 69 static kstat_t *system_misc_ksp;
72 70 static kstat_named_t *boot_time_knp;
73 71 static kstat_named_t *avenrun_1min_knp, *avenrun_5min_knp, *avenrun_15min_knp;
74 72 static int hz;
75 73 static struct timeval btm; /* boottime */
76 74
77 75 /*
78 76 * network interface stats
79 77 */
80 78
81 79 typedef struct mib_item_s {
82 80 struct mib_item_s *next_item;
83 81 long group;
84 82 long mib_id;
85 83 long length;
86 84 char *valp;
87 85 } mib_item_t;
88 86
89 87 mib_item_t *netstat_item;
90 88
91 89 /*
92 90 * disk stats
93 91 */
94 92
95 93 struct diskinfo {
96 94 struct diskinfo *next;
97 95 kstat_t *ks;
98 96 kstat_io_t kios;
99 97 };
100 98
101 99 #define NULLDISK (struct diskinfo *)0
102 100 static struct diskinfo zerodisk = { NULL, NULL };
103 101 static struct diskinfo *firstdisk = NULLDISK;
104 102 static struct diskinfo *lastdisk = NULLDISK;
105 103 static struct diskinfo *snip = NULLDISK;
106 104 static int ndisks;
107 105
108 106 /*
109 107 * net stats
110 108 */
111 109
112 110 struct netinfo {
113 111 struct netinfo *next;
114 112 kstat_t *ks;
115 113 kstat_named_t *ipackets;
116 114 kstat_named_t *opackets;
117 115 kstat_named_t *ierrors;
118 116 kstat_named_t *oerrors;
119 117 kstat_named_t *collisions;
120 118 };
121 119
122 120 #define NULLNET (struct netinfo *)0
123 121 static struct netinfo zeronet = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
124 122 static struct netinfo *firstnet = NULLNET;
125 123 static struct netinfo *lastnet = NULLNET;
126 124 static struct netinfo *netsnip = NULLNET;
127 125 static int nnets;
128 126
129 127 /*
130 128 * Define EXIT_WHEN_IDLE if you are able to have this program invoked
131 129 * automatically on demand (as from inetd). When defined, the service
132 130 * will terminated after being idle for 120 seconds.
133 131 */
134 132
135 133 #define EXIT_WHEN_IDLE 1
136 134
137 135 int sincelastreq = 0; /* number of alarms since last request */
138 136 #ifdef EXIT_WHEN_IDLE
139 137 #define CLOSEDOWN 120 /* how long to wait before exiting */
140 138 #endif /* def EXIT_WHEN_IDLE */
141 139
142 140 statstime stats_s3;
143 141 statsvar stats_s4;
144 142 /* V2 support for backwards compatibility to pre-5.0 systems */
145 143 statsswtch stats_s2;
146 144
147 145 static int stat_is_init = 0;
148 146
149 147 static void fail(int, char *, ...);
150 148 static void safe_zalloc(void **, int, int);
151 149 static kid_t safe_kstat_read(kstat_ctl_t *, kstat_t *, void *);
152 150 static kstat_t *safe_kstat_lookup(kstat_ctl_t *, char *, int, char *);
153 151 static void *safe_kstat_data_lookup(kstat_t *, char *);
154 152 static void system_stat_init(void);
155 153 static int system_stat_load(void);
156 154 static void init_disks(void);
157 155 static int diskinfo_load(void);
158 156 static void init_net(void);
159 157 static int netinfo_load(void);
160 158
161 159 static void updatestat(int);
162 160
163 161 static mib_item_t *mibget(int sd);
164 162 static int mibopen(void);
165 163 static char *octetstr(char *buf, Octet_t *op, int code);
166 164
167 165 static void kstat_copy(kstat_t *, kstat_t *, int);
168 166
169 167 static char *cmdname = "rpc.rstatd";
170 168
171 169 #define CPU_STAT(ksp, name) (((kstat_named_t *)safe_kstat_data_lookup( \
172 170 (ksp), (name)))->value.ui64)
173 171 static _cpu_stats_t cpu_stats_all = { 0 };
174 172
175 173 static void
176 174 stat_init(void)
177 175 {
178 176 struct utmpx *utmpx, utmpx_id;
179 177
180 178 stat_is_init = 1;
181 179
182 180 if ((kc = kstat_open()) == NULL)
183 181 fail(1, "kstat_open(): can't open /dev/kstat");
184 182
185 183 /*
186 184 * Preallocate minimal set of drive entries.
187 185 */
188 186
189 187 if (stats_s4.dk_xfer.dk_xfer_val == NULL) {
190 188 stats_s4.dk_xfer.dk_xfer_len = RSTAT_DK_NDRIVE;
191 189 stats_s4.dk_xfer.dk_xfer_val =
192 190 (int *)calloc(RSTAT_DK_NDRIVE, sizeof (int));
193 191 }
194 192
195 193 system_stat_init();
196 194 init_disks();
197 195 init_net();
198 196
199 197 /*
200 198 * To get the boot time, use utmpx, which is per-zone, but fall back
201 199 * to the system-wide kstat if utmpx is hosed for any reason.
202 200 */
203 201 utmpx_id.ut_type = BOOT_TIME;
204 202 if ((utmpx = getutxid(&utmpx_id)) != NULL)
205 203 btm = utmpx->ut_tv;
206 204 else {
207 205 btm.tv_sec = boot_time_knp->value.ul;
208 206 btm.tv_usec = 0; /* don't bother with usecs for boot time */
209 207 }
210 208 endutxent();
211 209 stats_s4.boottime.tv_sec =
212 210 stats_s2.boottime.tv_sec =
213 211 stats_s3.boottime.tv_sec = btm.tv_sec;
214 212 stats_s4.boottime.tv_usec =
215 213 stats_s2.boottime.tv_usec =
216 214 stats_s3.boottime.tv_usec = btm.tv_usec;
217 215
218 216 updatestat(0);
219 217 alarm(1);
220 218 signal(SIGALRM, updatestat);
221 219 sleep(2); /* allow for one wake-up */
222 220 }
223 221
224 222 statsvar *
225 223 rstatproc_stats_4_svc(argp, svcrq)
226 224 void *argp;
227 225 struct svc_req *svcrq;
228 226 {
229 227 if (! stat_is_init)
230 228 stat_init();
231 229 #ifdef EXIT_WHEN_IDLE
232 230 sincelastreq = 0;
233 231 #endif
234 232 return (&stats_s4);
235 233 }
236 234
237 235 statstime *
238 236 rstatproc_stats_3_svc(argp, svcrq)
239 237 void *argp;
240 238 struct svc_req *svcrq;
241 239 {
242 240 if (! stat_is_init)
243 241 stat_init();
244 242 #ifdef EXIT_WHEN_IDLE
245 243 sincelastreq = 0;
246 244 #endif
247 245 return (&stats_s3);
248 246 }
249 247
250 248 statsswtch *
251 249 rstatproc_stats_2_svc(argp, svcrq)
252 250 void *argp;
253 251 struct svc_req *svcrq;
254 252 {
255 253 if (! stat_is_init)
256 254 stat_init();
257 255 #ifdef EXIT_WHEN_IDLE
258 256 sincelastreq = 0;
259 257 #endif
260 258 return (&stats_s2);
261 259 }
262 260
263 261
264 262 uint_t *
265 263 rstatproc_havedisk_4_svc(argp, svcrq)
266 264 void *argp;
267 265 struct svc_req *svcrq;
268 266 {
269 267 return (rstatproc_havedisk_3_svc(argp, svcrq));
270 268 }
271 269
272 270 uint_t *
273 271 rstatproc_havedisk_3_svc(argp, svcrq)
274 272 void *argp;
275 273 struct svc_req *svcrq;
276 274 {
277 275 static uint_t have;
278 276
279 277 if (! stat_is_init)
280 278 stat_init();
281 279 #ifdef EXIT_WHEN_IDLE
282 280 sincelastreq = 0;
283 281 #endif
284 282 have = (ndisks != 0);
285 283 return (&have);
286 284 }
287 285
288 286 uint_t *
289 287 rstatproc_havedisk_2_svc(argp, svcrq)
290 288 void *argp;
291 289 struct svc_req *svcrq;
292 290 {
293 291 return (rstatproc_havedisk_3_svc(argp, svcrq));
294 292 }
295 293
296 294 void
297 295 updatestat(int ignored)
298 296 {
299 297 extern int _rpcpmstart; /* Started by a port monitor ? */
300 298 extern int _rpcsvcdirty; /* Still serving ? */
301 299
302 300 #ifdef DEBUG
303 301 fprintf(stderr, "entering updatestat\n");
304 302 #endif
305 303 #ifdef EXIT_WHEN_IDLE
306 304 if (_rpcpmstart && sincelastreq >= CLOSEDOWN && !_rpcsvcdirty) {
307 305 #ifdef DEBUG
308 306 fprintf(stderr, "about to closedown\n");
309 307 #endif
310 308 exit(0);
311 309 }
312 310 sincelastreq++;
313 311 #endif /* def EXIT_WHEN_IDLE */
314 312
315 313 (void) alarm(0);
316 314 #ifdef DEBUG
317 315 fprintf(stderr, "boottime: %d %d\n", stats_s3.boottime.tv_sec,
318 316 stats_s3.boottime.tv_usec);
319 317 #endif
320 318 while (system_stat_load() || diskinfo_load() || netinfo_load()) {
321 319 (void) kstat_chain_update(kc);
322 320 system_stat_init();
323 321 init_disks();
324 322 init_net();
325 323 }
326 324 stats_s4.cp_time.cp_time_len = CPU_STATES;
327 325 if (stats_s4.cp_time.cp_time_val == NULL)
328 326 stats_s4.cp_time.cp_time_val =
329 327 malloc(stats_s4.cp_time.cp_time_len * sizeof (int));
330 328 stats_s2.cp_time[RSTAT_CPU_USER] =
331 329 stats_s3.cp_time[RSTAT_CPU_USER] =
332 330 stats_s4.cp_time.cp_time_val[RSTAT_CPU_USER] =
333 331 CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_user");
334 332 stats_s2.cp_time[RSTAT_CPU_NICE] =
335 333 stats_s3.cp_time[RSTAT_CPU_NICE] =
336 334 stats_s4.cp_time.cp_time_val[RSTAT_CPU_NICE] =
337 335 CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_wait");
338 336 stats_s2.cp_time[RSTAT_CPU_SYS] =
339 337 stats_s3.cp_time[RSTAT_CPU_SYS] =
340 338 stats_s4.cp_time.cp_time_val[RSTAT_CPU_SYS] =
341 339 CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_kernel");
342 340 stats_s2.cp_time[RSTAT_CPU_IDLE] =
343 341 stats_s3.cp_time[RSTAT_CPU_IDLE] =
344 342 stats_s4.cp_time.cp_time_val[RSTAT_CPU_IDLE] =
345 343 CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_idle");
346 344
347 345 #ifdef DEBUG
348 346 fprintf(stderr, "cpu: %d %d %d %d\n",
349 347 CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_user"),
350 348 CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_wait"),
351 349 CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_kernel"),
352 350 CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_idle"));
353 351 fprintf(stderr, "cp_time: %d %d %d %d\n",
354 352 stats_s3.cp_time[RSTAT_CPU_USER],
355 353 stats_s3.cp_time[RSTAT_CPU_NICE],
356 354 stats_s3.cp_time[RSTAT_CPU_SYS],
357 355 stats_s3.cp_time[RSTAT_CPU_IDLE]);
358 356 #endif
359 357
360 358 /* current time */
361 359 gettimeofday((struct timeval *)&stats_s3.curtime, NULL);
↓ open down ↓ |
324 lines elided |
↑ open up ↑ |
362 360 stats_s4.curtime = stats_s3.curtime;
363 361
364 362 stats_s2.v_pgpgin =
365 363 stats_s3.v_pgpgin =
366 364 stats_s4.v_pgpgin = CPU_STAT(&cpu_stats_all.vm, "pgpgin");
367 365 stats_s2.v_pgpgout =
368 366 stats_s3.v_pgpgout =
369 367 stats_s4.v_pgpgout = CPU_STAT(&cpu_stats_all.vm, "pgpgout");
370 368 stats_s2.v_pswpin =
371 369 stats_s3.v_pswpin =
372 - stats_s4.v_pswpin = CPU_STAT(&cpu_stats_all.vm, "pgswapin");
370 + stats_s4.v_pswpin = 0;
373 371 stats_s2.v_pswpout =
374 372 stats_s3.v_pswpout =
375 - stats_s4.v_pswpout = CPU_STAT(&cpu_stats_all.vm, "pgswapout");
373 + stats_s4.v_pswpout = 0;
376 374 stats_s3.v_intr = CPU_STAT(&cpu_stats_all.sys, "intr");
377 375 stats_s3.v_intr -= hz*(stats_s3.curtime.tv_sec - btm.tv_sec) +
378 376 hz*(stats_s3.curtime.tv_usec - btm.tv_usec)/1000000;
379 377 stats_s2.v_intr =
380 378 stats_s4.v_intr = stats_s3.v_intr;
381 379 /* swtch not in V1 */
382 380 stats_s2.v_swtch =
383 381 stats_s3.v_swtch =
384 382 stats_s4.v_swtch = CPU_STAT(&cpu_stats_all.sys, "pswitch");
385 383
386 384 #ifdef DEBUG
387 385 fprintf(stderr,
388 386 "pgin: %d pgout: %d swpin: %d swpout: %d intr: %d swtch: %d\n",
389 387 stats_s3.v_pgpgin,
390 388 stats_s3.v_pgpgout,
391 389 stats_s3.v_pswpin,
392 390 stats_s3.v_pswpout,
393 391 stats_s3.v_intr,
394 392 stats_s3.v_swtch);
395 393 #endif
396 394 /*
397 395 * V2 and V3 of rstat are limited to RSTAT_DK_NDRIVE drives
398 396 */
399 397 memcpy(stats_s3.dk_xfer, stats_s4.dk_xfer.dk_xfer_val,
400 398 RSTAT_DK_NDRIVE * sizeof (int));
401 399 memcpy(stats_s2.dk_xfer, stats_s4.dk_xfer.dk_xfer_val,
402 400 RSTAT_DK_NDRIVE * sizeof (int));
403 401 #ifdef DEBUG
404 402 fprintf(stderr, "dk_xfer: %d %d %d %d\n",
405 403 stats_s4.dk_xfer.dk_xfer_val[0],
406 404 stats_s4.dk_xfer.dk_xfer_val[1],
407 405 stats_s4.dk_xfer.dk_xfer_val[2],
408 406 stats_s4.dk_xfer.dk_xfer_val[3]);
409 407 #endif
410 408
411 409 stats_s2.if_ipackets =
412 410 stats_s3.if_ipackets = stats_s4.if_ipackets;
413 411 /* no s2 opackets */
414 412 stats_s3.if_opackets = stats_s4.if_opackets;
415 413 stats_s2.if_ierrors =
416 414 stats_s3.if_ierrors = stats_s4.if_ierrors;
417 415 stats_s2.if_oerrors =
418 416 stats_s3.if_oerrors = stats_s4.if_oerrors;
419 417 stats_s2.if_collisions =
420 418 stats_s3.if_collisions = stats_s4.if_collisions;
421 419
422 420 stats_s2.avenrun[0] =
423 421 stats_s3.avenrun[0] =
424 422 stats_s4.avenrun[0] = avenrun_1min_knp->value.ul;
425 423 stats_s2.avenrun[1] =
426 424 stats_s3.avenrun[1] =
427 425 stats_s4.avenrun[1] = avenrun_5min_knp->value.ul;
428 426 stats_s2.avenrun[2] =
429 427 stats_s3.avenrun[2] =
430 428 stats_s4.avenrun[2] = avenrun_15min_knp->value.ul;
431 429 #ifdef DEBUG
432 430 fprintf(stderr, "avenrun: %d %d %d\n", stats_s3.avenrun[0],
433 431 stats_s3.avenrun[1], stats_s3.avenrun[2]);
434 432 #endif
435 433 signal(SIGALRM, updatestat);
436 434 alarm(1);
437 435 }
438 436
439 437 /* --------------------------------- MIBGET -------------------------------- */
440 438
441 439 static mib_item_t *
442 440 mibget(int sd)
443 441 {
444 442 int flags;
445 443 int j, getcode;
446 444 struct strbuf ctlbuf, databuf;
447 445 char buf[512];
448 446 struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf;
449 447 struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf;
450 448 struct T_error_ack *tea = (struct T_error_ack *)buf;
451 449 struct opthdr *req;
452 450 mib_item_t *first_item = NULL;
453 451 mib_item_t *last_item = NULL;
454 452 mib_item_t *temp;
455 453
456 454 tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
457 455 tor->OPT_offset = sizeof (struct T_optmgmt_req);
458 456 tor->OPT_length = sizeof (struct opthdr);
459 457 tor->MGMT_flags = T_CURRENT;
460 458 req = (struct opthdr *)&tor[1];
461 459 req->level = MIB2_IP; /* any MIB2_xxx value ok here */
462 460 req->name = 0;
463 461 req->len = 0;
464 462
465 463 ctlbuf.buf = buf;
466 464 ctlbuf.len = tor->OPT_length + tor->OPT_offset;
467 465 flags = 0;
468 466 if (putmsg(sd, &ctlbuf, NULL, flags) == -1) {
469 467 perror("mibget: putmsg(ctl) failed");
470 468 goto error_exit;
471 469 }
472 470 /*
473 471 * each reply consists of a ctl part for one fixed structure
474 472 * or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK,
475 473 * containing an opthdr structure. level/name identify the entry,
476 474 * len is the size of the data part of the message.
477 475 */
478 476 req = (struct opthdr *)&toa[1];
479 477 ctlbuf.maxlen = sizeof (buf);
480 478 /*CSTYLED*/
481 479 for (j = 1; ; j++) {
482 480 flags = 0;
483 481 getcode = getmsg(sd, &ctlbuf, NULL, &flags);
484 482 if (getcode == -1) {
485 483 #ifdef DEBUG_MIB
486 484 perror("mibget getmsg(ctl) failed");
487 485 fprintf(stderr, "# level name len\n");
488 486 i = 0;
489 487 for (last_item = first_item; last_item;
490 488 last_item = last_item->next_item)
491 489 fprintf(stderr, "%d %4d %5d %d\n", ++i,
492 490 last_item->group,
493 491 last_item->mib_id,
494 492 last_item->length);
495 493 #endif /* DEBUG_MIB */
496 494 goto error_exit;
497 495 }
498 496 if (getcode == 0 &&
499 497 (ctlbuf.len >= sizeof (struct T_optmgmt_ack)) &&
500 498 (toa->PRIM_type == T_OPTMGMT_ACK) &&
501 499 (toa->MGMT_flags == T_SUCCESS) &&
502 500 req->len == 0) {
503 501 #ifdef DEBUG_MIB
504 502 fprintf(stderr,
505 503 "mibget getmsg() %d returned EOD (level %d, name %d)\n",
506 504 j, req->level, req->name);
507 505 #endif /* DEBUG_MIB */
508 506 return (first_item); /* this is EOD msg */
509 507 }
510 508
511 509 if (ctlbuf.len >= sizeof (struct T_error_ack) &&
512 510 (tea->PRIM_type == T_ERROR_ACK)) {
513 511 #ifdef DEBUG_MIB
514 512 fprintf(stderr,
515 513 "mibget %d gives T_ERROR_ACK: TLI_error = 0x%x, UNIX_error = 0x%x\n",
516 514 j, getcode, tea->TLI_error, tea->UNIX_error);
517 515 #endif /* DEBUG_MIB */
518 516 errno = (tea->TLI_error == TSYSERR)
519 517 ? tea->UNIX_error : EPROTO;
520 518 goto error_exit;
521 519 }
522 520
523 521 if (getcode != MOREDATA ||
524 522 (ctlbuf.len < sizeof (struct T_optmgmt_ack)) ||
525 523 (toa->PRIM_type != T_OPTMGMT_ACK) ||
526 524 (toa->MGMT_flags != T_SUCCESS)) {
527 525 #ifdef DEBUG_MIB
528 526 fprintf(stderr,
529 527 "mibget getmsg(ctl) %d returned %d, ctlbuf.len = %d, PRIM_type = %d\n",
530 528 j, getcode, ctlbuf.len, toa->PRIM_type);
531 529 if (toa->PRIM_type == T_OPTMGMT_ACK)
532 530 fprintf(stderr,
533 531 "T_OPTMGMT_ACK: MGMT_flags = 0x%x, req->len = %d\n",
534 532 toa->MGMT_flags, req->len);
535 533 #endif /* DEBUG_MIB */
536 534 errno = ENOMSG;
537 535 goto error_exit;
538 536 }
539 537
540 538 temp = malloc(sizeof (mib_item_t));
541 539 if (!temp) {
542 540 perror("mibget malloc failed");
543 541 goto error_exit;
544 542 }
545 543 if (last_item)
546 544 last_item->next_item = temp;
547 545 else
548 546 first_item = temp;
549 547 last_item = temp;
550 548 last_item->next_item = NULL;
551 549 last_item->group = req->level;
552 550 last_item->mib_id = req->name;
553 551 last_item->length = req->len;
554 552 last_item->valp = malloc(req->len);
555 553 #ifdef DEBUG_MIB
556 554 fprintf(stderr,
557 555 "msg %d: group = %4d mib_id = %5d length = %d\n",
558 556 j, last_item->group, last_item->mib_id,
559 557 last_item->length);
560 558 #endif /* DEBUG_MIB */
561 559 databuf.maxlen = last_item->length;
562 560 databuf.buf = last_item->valp;
563 561 databuf.len = 0;
564 562 flags = 0;
565 563 getcode = getmsg(sd, NULL, &databuf, &flags);
566 564 if (getcode == -1) {
567 565 perror("mibget getmsg(data) failed");
568 566 goto error_exit;
569 567 } else if (getcode != 0) {
570 568 fprintf(stderr,
571 569 "mibget getmsg(data) returned %d, databuf.maxlen = %d, databuf.len = %d\n",
572 570 getcode, databuf.maxlen, databuf.len);
573 571 goto error_exit;
574 572 }
575 573 }
576 574
577 575 error_exit:
578 576 while (first_item) {
579 577 last_item = first_item;
580 578 first_item = first_item->next_item;
581 579 if (last_item->valp) {
582 580 free(last_item->valp);
583 581 }
584 582 free(last_item);
585 583 }
586 584 return (first_item);
587 585 }
588 586
589 587 static int
590 588 mibopen(void)
591 589 {
592 590 int sd;
593 591
594 592 /* gives us ip w/ arp on top */
595 593 sd = open("/dev/arp", O_RDWR);
596 594 if (sd == -1) {
597 595 perror("arp open");
598 596 close(sd);
599 597 return (-1);
600 598 }
601 599 if (ioctl(sd, I_PUSH, "tcp") == -1) {
602 600 perror("tcp I_PUSH");
603 601 close(sd);
604 602 return (-1);
605 603 }
606 604 if (ioctl(sd, I_PUSH, "udp") == -1) {
607 605 perror("udp I_PUSH");
608 606 close(sd);
609 607 return (-1);
610 608 }
611 609 return (sd);
612 610 }
613 611
614 612 static char *
615 613 octetstr(char *buf, Octet_t *op, int code)
616 614 {
617 615 int i;
618 616 char *cp;
619 617
620 618 cp = buf;
621 619 if (op)
622 620 for (i = 0; i < op->o_length; i++)
623 621 switch (code) {
624 622 case 'd':
625 623 sprintf(cp, "%d.", 0xff & op->o_bytes[i]);
626 624 cp = strchr(cp, '\0');
627 625 break;
628 626 case 'a':
629 627 *cp++ = op->o_bytes[i];
630 628 break;
631 629 case 'h':
632 630 default:
633 631 sprintf(cp, "%02x:", 0xff & op->o_bytes[i]);
634 632 cp += 3;
635 633 break;
636 634 }
637 635 if (code != 'a' && cp != buf)
638 636 cp--;
639 637 *cp = '\0';
640 638 return (buf);
641 639 }
642 640
643 641 static void
644 642 fail(int do_perror, char *message, ...)
645 643 {
646 644 va_list args;
647 645
648 646 va_start(args, message);
649 647 fprintf(stderr, "%s: ", cmdname);
650 648 vfprintf(stderr, message, args);
651 649 va_end(args);
652 650 if (do_perror)
653 651 fprintf(stderr, ": %s", strerror(errno));
654 652 fprintf(stderr, "\n");
655 653 exit(2);
656 654 }
657 655
658 656 static void
659 657 safe_zalloc(void **ptr, int size, int free_first)
660 658 {
661 659 if (free_first && *ptr != NULL)
662 660 free(*ptr);
663 661 if ((*ptr = malloc(size)) == NULL)
664 662 fail(1, "malloc failed");
665 663 memset(*ptr, 0, size);
666 664 }
667 665
668 666 kid_t
669 667 safe_kstat_read(kstat_ctl_t *kctl, kstat_t *ksp, void *data)
670 668 {
671 669 kid_t kstat_chain_id = kstat_read(kctl, ksp, data);
672 670
673 671 if (kstat_chain_id == -1)
674 672 fail(1, "kstat_read(%x, '%s') failed", kctl, ksp->ks_name);
675 673 return (kstat_chain_id);
676 674 }
677 675
678 676 kstat_t *
679 677 safe_kstat_lookup(kstat_ctl_t *kctl, char *ks_module, int ks_instance,
680 678 char *ks_name)
681 679 {
682 680 kstat_t *ksp = kstat_lookup(kctl, ks_module, ks_instance, ks_name);
683 681
684 682 if (ksp == NULL)
685 683 fail(0, "kstat_lookup('%s', %d, '%s') failed",
686 684 ks_module == NULL ? "" : ks_module,
687 685 ks_instance,
688 686 ks_name == NULL ? "" : ks_name);
689 687 return (ksp);
690 688 }
691 689
692 690 void *
693 691 safe_kstat_data_lookup(kstat_t *ksp, char *name)
694 692 {
695 693 void *fp = kstat_data_lookup(ksp, name);
696 694
697 695 if (fp == NULL) {
698 696 fail(0, "kstat_data_lookup('%s', '%s') failed",
699 697 ksp->ks_name, name);
700 698 }
701 699 return (fp);
702 700 }
703 701
704 702 /*
705 703 * Get various KIDs for subsequent system_stat_load operations.
706 704 */
707 705
708 706 static void
709 707 system_stat_init(void)
710 708 {
711 709 kstat_t *ksp;
712 710 int i, nvmks;
713 711
714 712 /*
715 713 * Global statistics
716 714 */
717 715
718 716 system_misc_ksp = safe_kstat_lookup(kc, "unix", 0, "system_misc");
719 717
720 718 safe_kstat_read(kc, system_misc_ksp, NULL);
721 719 boot_time_knp = safe_kstat_data_lookup(system_misc_ksp, "boot_time");
722 720 avenrun_1min_knp = safe_kstat_data_lookup(system_misc_ksp,
723 721 "avenrun_1min");
724 722 avenrun_5min_knp = safe_kstat_data_lookup(system_misc_ksp,
725 723 "avenrun_5min");
726 724 avenrun_15min_knp = safe_kstat_data_lookup(system_misc_ksp,
727 725 "avenrun_15min");
728 726
729 727 /*
730 728 * Per-CPU statistics
731 729 */
732 730
733 731 ncpus = 0;
734 732 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next)
735 733 if (strcmp(ksp->ks_module, "cpu") == 0 &&
736 734 strcmp(ksp->ks_name, "sys") == 0)
737 735 ncpus++;
738 736
739 737 safe_zalloc((void **)&cpu_stats_list, ncpus * sizeof (*cpu_stats_list),
740 738 1);
741 739
742 740 ncpus = 0;
743 741 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next)
744 742 if (strcmp(ksp->ks_module, "cpu") == 0 &&
745 743 strcmp(ksp->ks_name, "sys") == 0 &&
746 744 kstat_read(kc, ksp, NULL) != -1) {
747 745 kstat_copy(ksp, &cpu_stats_list[ncpus].sys,
748 746 1);
749 747 if ((ksp = kstat_lookup(kc, "cpu", ksp->ks_instance,
750 748 "vm")) != NULL && kstat_read(kc, ksp, NULL) != -1)
751 749 kstat_copy(ksp, &cpu_stats_list[ncpus].vm, 1);
752 750 else
753 751 fail(0, "couldn't find per-CPU VM statistics");
754 752 ncpus++;
755 753 }
756 754
757 755 if (ncpus == 0)
758 756 fail(0, "couldn't find per-CPU statistics");
759 757 }
760 758
761 759 /*
762 760 * load statistics, summing across CPUs where needed
763 761 */
764 762
765 763 static int
766 764 system_stat_load(void)
767 765 {
768 766 int i, j;
769 767 _cpu_stats_t cs;
770 768 ulong_t *np, *tp;
771 769
772 770 /*
773 771 * Global statistics
774 772 */
775 773
776 774 safe_kstat_read(kc, system_misc_ksp, NULL);
777 775
778 776 /*
779 777 * Per-CPU statistics.
780 778 */
781 779
782 780 for (i = 0; i < ncpus; i++) {
783 781 if (kstat_read(kc, &cpu_stats_list[i].sys, NULL) == -1 ||
784 782 kstat_read(kc, &cpu_stats_list[i].vm, NULL) == -1)
785 783 return (1);
786 784 if (i == 0) {
787 785 kstat_copy(&cpu_stats_list[0].sys, &cpu_stats_all.sys,
788 786 1);
789 787 kstat_copy(&cpu_stats_list[0].vm, &cpu_stats_all.vm, 1);
790 788 } else {
791 789 kstat_named_t *nkp;
792 790 kstat_named_t *tkp;
793 791
794 792 /*
795 793 * Other CPUs' statistics are accumulated in
796 794 * cpu_stats_all, initialized at the first iteration of
797 795 * the loop.
798 796 */
799 797 nkp = (kstat_named_t *)cpu_stats_all.sys.ks_data;
800 798 tkp = (kstat_named_t *)cpu_stats_list[i].sys.ks_data;
801 799 for (j = 0; j < cpu_stats_list[i].sys.ks_ndata; j++)
802 800 (nkp++)->value.ui64 += (tkp++)->value.ui64;
803 801 nkp = (kstat_named_t *)cpu_stats_all.vm.ks_data;
804 802 tkp = (kstat_named_t *)cpu_stats_list[i].vm.ks_data;
805 803 for (j = 0; j < cpu_stats_list[i].vm.ks_ndata; j++)
806 804 (nkp++)->value.ui64 += (tkp++)->value.ui64;
807 805 }
808 806 }
809 807 return (0);
810 808 }
811 809
812 810 static int
813 811 kscmp(kstat_t *ks1, kstat_t *ks2)
814 812 {
815 813 int cmp;
816 814
817 815 cmp = strcmp(ks1->ks_module, ks2->ks_module);
818 816 if (cmp != 0)
819 817 return (cmp);
820 818 cmp = ks1->ks_instance - ks2->ks_instance;
821 819 if (cmp != 0)
822 820 return (cmp);
823 821 return (strcmp(ks1->ks_name, ks2->ks_name));
824 822 }
825 823
826 824 static void
827 825 init_disks(void)
828 826 {
829 827 struct diskinfo *disk, *prevdisk, *comp;
830 828 kstat_t *ksp;
831 829
832 830 ndisks = 0;
833 831 disk = &zerodisk;
834 832
835 833 /*
836 834 * Patch the snip in the diskinfo list (see below)
837 835 */
838 836 if (snip)
839 837 lastdisk->next = snip;
840 838
841 839 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
842 840
843 841 if (ksp->ks_type != KSTAT_TYPE_IO ||
844 842 strcmp(ksp->ks_class, "disk") != 0)
845 843 continue;
846 844 prevdisk = disk;
847 845 if (disk->next)
848 846 disk = disk->next;
849 847 else {
850 848 safe_zalloc((void **)&disk->next,
851 849 sizeof (struct diskinfo), 0);
852 850 disk = disk->next;
853 851 disk->next = NULLDISK;
854 852 }
855 853 disk->ks = ksp;
856 854 memset((void *)&disk->kios, 0, sizeof (kstat_io_t));
857 855 disk->kios.wlastupdate = disk->ks->ks_crtime;
858 856 disk->kios.rlastupdate = disk->ks->ks_crtime;
859 857
860 858 /*
861 859 * Insertion sort on (ks_module, ks_instance, ks_name)
862 860 */
863 861 comp = &zerodisk;
864 862 while (kscmp(disk->ks, comp->next->ks) > 0)
865 863 comp = comp->next;
866 864 if (prevdisk != comp) {
867 865 prevdisk->next = disk->next;
868 866 disk->next = comp->next;
869 867 comp->next = disk;
870 868 disk = prevdisk;
871 869 }
872 870 ndisks++;
873 871 }
874 872 /*
875 873 * Put a snip in the linked list of diskinfos. The idea:
876 874 * If there was a state change such that now there are fewer
877 875 * disks, we snip the list and retain the tail, rather than
878 876 * freeing it. At the next state change, we clip the tail back on.
879 877 * This prevents a lot of malloc/free activity, and it's simpler.
880 878 */
881 879 lastdisk = disk;
882 880 snip = disk->next;
883 881 disk->next = NULLDISK;
884 882
885 883 firstdisk = zerodisk.next;
886 884
887 885 if (ndisks > stats_s4.dk_xfer.dk_xfer_len) {
888 886 stats_s4.dk_xfer.dk_xfer_len = ndisks;
889 887 safe_zalloc((void **)&stats_s4.dk_xfer.dk_xfer_val,
890 888 ndisks * sizeof (int), 1);
891 889 }
892 890 }
893 891
894 892 static int
895 893 diskinfo_load(void)
896 894 {
897 895 struct diskinfo *disk;
898 896 int i;
899 897
900 898 for (disk = firstdisk, i = 0; disk; disk = disk->next, i++) {
901 899 if (kstat_read(kc, disk->ks, (void *)&disk->kios) == -1)
902 900 return (1);
903 901 stats_s4.dk_xfer.dk_xfer_val[i] = disk->kios.reads +
904 902 disk->kios.writes;
905 903 }
906 904 return (0);
907 905 }
908 906
909 907 static void
910 908 init_net(void)
911 909 {
912 910 static int sd;
913 911 mib_item_t *item;
914 912 mib2_ipAddrEntry_t *ap;
915 913 char namebuf[KSTAT_STRLEN];
916 914 struct netinfo *net, *prevnet, *comp;
917 915 kstat_t *ksp;
918 916
919 917 if (sd) {
920 918 close(sd);
921 919 }
922 920 while (netstat_item) {
923 921 item = netstat_item;
924 922 netstat_item = netstat_item->next_item;
925 923 if (item->valp) {
926 924 free(item->valp);
927 925 }
928 926 free(item);
929 927 }
930 928 sd = mibopen();
931 929 if (sd == -1) {
932 930 #ifdef DEBUG
933 931 fprintf(stderr, "mibopen() failed\n");
934 932 #endif
935 933 sd = 0;
936 934 } else {
937 935 if ((netstat_item = mibget(sd)) == NULL) {
938 936 #ifdef DEBUG
939 937 fprintf(stderr, "mibget() failed\n");
940 938 #endif
941 939 close(sd);
942 940 sd = 0;
943 941 }
944 942 }
945 943 #ifdef DEBUG
946 944 fprintf(stderr, "mibget returned item: %x\n", netstat_item);
947 945 #endif
948 946
949 947 nnets = 0;
950 948 net = &zeronet;
951 949
952 950 if (netsnip)
953 951 lastnet->next = netsnip;
954 952
955 953 for (item = netstat_item; item; item = item->next_item) {
956 954 #ifdef DEBUG_MIB
957 955 fprintf(stderr, "\n--- Item %x ---\n", item);
958 956 fprintf(stderr,
959 957 "Group = %d, mib_id = %d, length = %d, valp = 0x%x\n",
960 958 item->group, item->mib_id, item->length,
961 959 item->valp);
962 960 #endif
963 961 if (item->group != MIB2_IP || item->mib_id != MIB2_IP_20)
964 962 continue;
965 963 ap = (mib2_ipAddrEntry_t *)item->valp;
966 964 for (; (char *)ap < item->valp + item->length; ap++) {
967 965
968 966 octetstr(namebuf, &ap->ipAdEntIfIndex, 'a');
969 967 #ifdef DEBUG
970 968 fprintf(stderr, "%s ", namebuf);
971 969 #endif
972 970 if (strlen(namebuf) == 0)
973 971 continue;
974 972 /*
975 973 * We found a device of interest.
976 974 * Now, let's see if there's a kstat for it.
977 975 * First we try to query the "link" kstats in case
978 976 * the link is renamed. If that fails, fallback
979 977 * to legacy ktats for those non-GLDv3 links.
980 978 */
981 979 if (((ksp = kstat_lookup(kc, "link", 0, namebuf))
982 980 == NULL) && ((ksp = kstat_lookup(kc, NULL, -1,
983 981 namebuf)) == NULL)) {
984 982 continue;
985 983 }
986 984 if (ksp->ks_type != KSTAT_TYPE_NAMED)
987 985 continue;
988 986 if (kstat_read(kc, ksp, NULL) == -1)
989 987 continue;
990 988 prevnet = net;
991 989 if (net->next)
992 990 net = net->next;
993 991 else {
994 992 safe_zalloc((void **)&net->next,
995 993 sizeof (struct netinfo), 0);
996 994 net = net->next;
997 995 net->next = NULLNET;
998 996 }
999 997 net->ks = ksp;
1000 998 net->ipackets = kstat_data_lookup(net->ks,
1001 999 "ipackets");
1002 1000 net->opackets = kstat_data_lookup(net->ks,
1003 1001 "opackets");
1004 1002 net->ierrors = kstat_data_lookup(net->ks,
1005 1003 "ierrors");
1006 1004 net->oerrors = kstat_data_lookup(net->ks,
1007 1005 "oerrors");
1008 1006 net->collisions = kstat_data_lookup(net->ks,
1009 1007 "collisions");
1010 1008 /*
1011 1009 * Insertion sort on the name
1012 1010 */
1013 1011 comp = &zeronet;
1014 1012 while (strcmp(net->ks->ks_name,
1015 1013 comp->next->ks->ks_name) > 0)
1016 1014 comp = comp->next;
1017 1015 if (prevnet != comp) {
1018 1016 prevnet->next = net->next;
1019 1017 net->next = comp->next;
1020 1018 comp->next = net;
1021 1019 net = prevnet;
1022 1020 }
1023 1021 nnets++;
1024 1022 }
1025 1023 #ifdef DEBUG
1026 1024 fprintf(stderr, "\n");
1027 1025 #endif
1028 1026 }
1029 1027 /*
1030 1028 * Put a snip in the linked list of netinfos. The idea:
1031 1029 * If there was a state change such that now there are fewer
1032 1030 * nets, we snip the list and retain the tail, rather than
1033 1031 * freeing it. At the next state change, we clip the tail back on.
1034 1032 * This prevents a lot of malloc/free activity, and it's simpler.
1035 1033 */
1036 1034 lastnet = net;
1037 1035 netsnip = net->next;
1038 1036 net->next = NULLNET;
1039 1037
1040 1038 firstnet = zeronet.next;
1041 1039 }
1042 1040
1043 1041 static int
1044 1042 netinfo_load(void)
1045 1043 {
1046 1044 struct netinfo *net;
1047 1045
1048 1046 if (netstat_item == NULL) {
1049 1047 #ifdef DEBUG
1050 1048 fprintf(stderr, "No net stats\n");
1051 1049 #endif
1052 1050 return (0);
1053 1051 }
1054 1052
1055 1053 stats_s4.if_ipackets =
1056 1054 stats_s4.if_opackets =
1057 1055 stats_s4.if_ierrors =
1058 1056 stats_s4.if_oerrors =
1059 1057 stats_s4.if_collisions = 0;
1060 1058
1061 1059 for (net = firstnet; net; net = net->next) {
1062 1060 if (kstat_read(kc, net->ks, NULL) == -1)
1063 1061 return (1);
1064 1062 if (net->ipackets)
1065 1063 stats_s4.if_ipackets += net->ipackets->value.ul;
1066 1064 if (net->opackets)
1067 1065 stats_s4.if_opackets += net->opackets->value.ul;
1068 1066 if (net->ierrors)
1069 1067 stats_s4.if_ierrors += net->ierrors->value.ul;
1070 1068 if (net->oerrors)
1071 1069 stats_s4.if_oerrors += net->oerrors->value.ul;
1072 1070 if (net->collisions)
1073 1071 stats_s4.if_collisions += net->collisions->value.ul;
1074 1072 }
1075 1073 #ifdef DEBUG
1076 1074 fprintf(stderr,
1077 1075 "ipackets: %d opackets: %d ierrors: %d oerrors: %d colls: %d\n",
1078 1076 stats_s4.if_ipackets,
1079 1077 stats_s4.if_opackets,
1080 1078 stats_s4.if_ierrors,
1081 1079 stats_s4.if_oerrors,
1082 1080 stats_s4.if_collisions);
1083 1081 #endif
1084 1082 return (0);
1085 1083 }
1086 1084
1087 1085 static void
1088 1086 kstat_copy(kstat_t *src, kstat_t *dst, int fr)
1089 1087 {
1090 1088 if (fr)
1091 1089 free(dst->ks_data);
1092 1090 *dst = *src;
1093 1091 if (src->ks_data != NULL) {
1094 1092 safe_zalloc(&dst->ks_data, src->ks_data_size, 0);
1095 1093 (void) memcpy(dst->ks_data, src->ks_data, src->ks_data_size);
1096 1094 } else {
1097 1095 dst->ks_data = NULL;
1098 1096 dst->ks_data_size = 0;
1099 1097 }
1100 1098 }
↓ open down ↓ |
715 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX