]> git.saurik.com Git - apple/system_cmds.git/blame - sar.tproj/sar.c
system_cmds-279.tar.gz
[apple/system_cmds.git] / sar.tproj / sar.c
CommitLineData
c3a08f59
A
1/*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26/*
27 cc -Wall -Wno-long-double -I. -I ../sadc.tproj -O -o sar sar.c
28*/
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
33#include <ctype.h>
34#include <time.h>
35#include <fcntl.h>
36#include <errno.h>
37#include <signal.h>
38#include <mach/mach.h>
39#include <sys/param.h>
40#include <sys/sysctl.h>
41
42#include <sadc.h>
43#include <sar.h>
44
45
46#define IFNET_32_BIT_COUNTERS 1
47
48/* Options used only for launching sadc */
49int t_interval = 5; /* in seconds */
50char * t_intervalp = "5";
51int n_samples = 1; /* number of sample loops */
52char * n_samplesp = "1";
53
54/* Used only for storing the binary output after launching sadc */
55char *outfile = NULL; /* output file */
56int ofd = 0; /* output file descriptor */
57
58/*
59 * When launching sadc, this file descriptor reads sadc's stdout
60 * via pipe.
61 * When not launching sadc, this file descriptor will be either
62 * the input file passed in with the -f flag
63 * or the standard input file /var/log/sa/saXX
64 */
65int ifd = 0; /* input file descriptor */
66char *infile = NULL; /* input file */
67
68
69
70/* Used when we have to luanch sadc */
71pid_t pid;
72int fd[2]; /* read from fd[0], write to fd[1] */
73
74char *optionstring1 = "Adgn:puo:";
75char *optionstring1_usage = "/usr/bin/sar [-Adgpu] [-n { DEV | EDEV | PPP } ] [-o filename] t [n]";
76char *optionstring2 = "Adgn:pue:f:i:s:";
77char *optionstring2_usage = "/usr/bin/sar [-Adgpu] [-n { DEV | EDEV | PPP }] [-e time] [-f filename] [-i sec] [-s time]";
78
79
80/* option flags */
81int aflag = 0;
82int Aflag = 0;
83int bflag = 0;
84int cflag = 0;
85int dflag = 0; /* drive statistics */
86int gflag = 0; /* page-out activity */
87int kflag = 0;
88int mflag = 0;
89
90int nflag = 0; /* network statistics */
91int network_mode = 0;
92char *sadc_mflagp = "-m";
93char *sadc_ppp_modep = "PPP";
94
95int pflag = 0; /* page-in activity */
96int qflag = 0;
97int rflag = 0;
98int uflag = 0; /* cpu utilization - this is the only default */
99int vflag = 0;
100int wflag = 0;
101int yflag = 0;
102int set_default_flag = 1;
103int flag_count = 0;
104
105/*
106 * To get the current time of day in seconds
107 * based on a 24 hour clock, pass in the time_t from time()
108 * the remainder is the current time in seconds
109*/
110#define HOURS_PER_DAY 24
111#define MINS_PER_HOUR 60
112#define SECS_PER_MIN 60
113#define SECS_PER_DAY (SECS_PER_MIN * MINS_PER_HOUR * HOURS_PER_DAY)
114
115/* end time delimiter -- converted from hh:mm:ss to seconds */
116time_t end_time = 0;
117
118int iflag = 0;
119int iseconds = 0; /* interval seconds, default = 0 implies all samples are
120 * printed */
121
122/* start time delimiter -- converted from hh:mm:ss to seconds */
123time_t start_time = 0;
124
125int oflag = 0;
126int fflag = 0;
127
128/* stat records average and previous */
129struct vm_statistics prev_vmstat, avg_vmstat, cur_vmstat;
130host_cpu_load_info_data_t prev_cpuload, avg_cpuload, cur_cpuload;
131struct drivestats_report *dr_head = NULL;
132
133/* internal table of drive path mappings */
134struct drivepath *dp_table = NULL;
135int dp_count = 0;
136
137/* internal table of network interface statistics */
138struct netstats_report *nr_table = NULL;
139int nr_count;
140struct netstats *netstat_readbuf = NULL;
141size_t netstat_readbuf_size = 0;
142
143int avg_counter = 0;
144int avg_interval = 0;
145
146extern int errno;
147
148/* Forward function declarations */
149static void exit_usage();
150static void open_output_file(char *path);
151static void open_input_file(char *path);
152static void read_record_hdr(struct record_hdr *hdr, int writeflag);
153static void read_record_data(char *buf, size_t size, int writeflag);
154static void write_record_hdr(struct record_hdr *hdr);
155static void write_record_data(char *buf, size_t size);
156static long convert_hms(char *string);
157static char *get_hms_string(time_t, char *);
158static int find_restart_header(struct record_hdr *);
159static void print_all_column_headings (time_t timestamp);
160static void print_column_heading (int type, char *timebufptr, int mode);
161static void read_sample_set(int, time_t, struct record_hdr *);
162static void do_main_workloop();
163static int bypass_sample_set(struct record_hdr *, time_t);
164static void skip_data(int);
165static int get_cpu_sample(int flag, struct record_hdr *hdr);
166static void print_cpu_sample(char *timebufptr);
167static int get_vmstat_sample(int flag, struct record_hdr *hdr);
168static void print_vmstat_sample(char *timebufptr);
169
170static int get_drivestats_sample(int flag, struct record_hdr *hdr);
171static void init_drivestats(struct drivestats_report *dr);
172static void print_drivestats_sample(char *timebufptr);
173static int get_drivepath_sample(int flag, struct record_hdr *hdr);
174
175static void set_cur_netstats(struct netstats_report *nr, struct netstats *ns);
176static void init_prev_netstats(struct netstats_report *nr);
177static int get_netstats_sample(int flag, struct record_hdr *hdr);
178static void print_netstats_sample(char *timebufptr);
179
180static void exit_average();
181
182int
183main(argc, argv)
184 int argc;
185 char *argv[];
186{
187
188 char ch;
189
190 time_t curr_time; /* current time in seconds */
191 char timebuf[26];
192 char filenamebuf[20];
193 char *optstring = NULL;
194 int optstringval;
195 int i;
196
197 /*
198 * Detirmine which option string to use
199 */
200
201 optreset=0;
202 optstringval=0;
203
204 while((ch=getopt(argc, argv, "aAbcdgkmn:pqruvwyo:e:f:i:s:")) != EOF) {
205 switch(ch) {
206 case 'o':
207 if (optstringval == 2)
208 exit_usage();
209 optstring=optionstring1;
210 optstringval=1;
211 break;
212 case 'e':
213 case 'f':
214 case 'i':
215 case 's':
216 if (optstringval == 1)
217 exit_usage();
218 optstring=optionstring2;
219 optstringval=2;
220 break;
221 default:
222 /* ignore for now */
223 break;
224 }
225 }
226
227 if (!optstring)
228 {
229 /* still trying to determine which option string to use */
230 if (argc - optind > 0)
231 {
232 optstring=optionstring1; /* we should have a t_second value */
233 optstringval=1;
234 }
235 else
236 {
237 optstring=optionstring2;
238 optstringval=2;
239 }
240 }
241
242 optreset = optind = 1;
243 while ((ch=getopt(argc, argv, optstring)) != EOF) {
244 switch (ch) {
245 case 'a':
246 aflag = 1;
247 set_default_flag = 0;
248 flag_count++;
249 break;
250 case 'A':
251 Aflag = 1;
252 set_default_flag = 0;
253 flag_count++;
254 break;
255 case 'b':
256 bflag = 1;
257 set_default_flag = 0;
258 flag_count++;
259 break;
260 case 'c':
261 cflag = 1;
262 set_default_flag = 0;
263 flag_count++;
264 break;
265 case 'd':
266 dflag = 1;
267 set_default_flag = 0;
268 flag_count++;
269 break;
270 case 'g':
271 gflag = 1;
272 set_default_flag = 0;
273 flag_count++;
274 break;
275 case 'k':
276 kflag = 1;
277 set_default_flag = 0;
278 flag_count++;
279 break;
280 case 'm':
281 mflag = 1;
282 set_default_flag = 0;
283 flag_count++;
284 break;
285 case 'n':
286 nflag= 1;
287 if (!strncmp(optarg, "PPP", 3))
288 network_mode |= NET_PPP_MODE;
289 else if (!strncmp(optarg, "DEV", 3))
290 network_mode |= NET_DEV_MODE;
291 else if (!strncmp(optarg, "EDEV", 4))
292 network_mode |= NET_EDEV_MODE;
293 else
294 exit_usage();
295 set_default_flag = 0;
296 flag_count++;
297 break;
298 case 'p':
299 pflag = 1;
300 set_default_flag = 0;
301 flag_count++;
302 break;
303 case 'q':
304 qflag = 1;
305 set_default_flag = 0;
306 flag_count++;
307 break;
308 case 'r':
309 rflag = 1;
310 set_default_flag = 0;
311 flag_count++;
312 break;
313 case 'u':
314 uflag= 1;
315 set_default_flag = 0;
316 flag_count++;
317 break;
318 case 'v':
319 vflag = 1;
320 set_default_flag = 0;
321 flag_count++;
322 break;
323 case 'w':
324 wflag = 1;
325 set_default_flag = 0;
326 flag_count++;
327 break;
328 case 'y':
329 yflag = 1;
330 set_default_flag = 0;
331 flag_count++;
332 break;
333 case 'o':
334 /* open the output file */
335 oflag = 1;
336 outfile=optarg;
337 (void)open_output_file(outfile);
338 break;
339 case 'e': /* eflag */
340 end_time = convert_hms(optarg);
341 break;
342 case 'f':
343 fflag = 1;
344 infile=optarg;
345 break;
346 case 'i':
347 iflag = 1;
348 iseconds=atoi(optarg);
349 break;
350 case 's':
351 start_time = convert_hms(optarg);
352 break;
353 default:
354 exit_usage();
355 break;
356 }
357 }
358
359 /* setup default uflag option */
360 if (Aflag)
361 {
362 dflag = gflag = pflag = uflag = 1;
363 if (!nflag)
364 {
365 /*
366 * Add network stats to the load
367 * but avoid PPP data by default.
368 */
369 nflag = 1;
370 network_mode = NET_DEV_MODE | NET_EDEV_MODE;;
371 }
372 flag_count = 2; /* triggers column headings */
373 }
374 else if (set_default_flag)
375 {
376 uflag=1;
377 flag_count++;
378 }
379
380 if (nflag)
381 {
382 if (network_mode & NET_PPP_MODE)
383 {
384 if (!(network_mode & NET_DEV_MODE) &&
385 !(network_mode & NET_EDEV_MODE))
386 {
387 /* set defaults */
388 network_mode |= NET_DEV_MODE;
389 network_mode |= NET_EDEV_MODE;
390 flag_count++;
391 }
392 }
393 }
394
395 argc -= optind;
396 argv += optind;
397
398 /* set up signal handlers */
399 signal(SIGINT, exit_average);
400 signal(SIGQUIT, exit_average);
401 signal(SIGHUP, exit_average);
402 signal(SIGTERM, exit_average);
403
404 if (optstringval == 1)
405 {
406 /* expecting a time interval */
407
408 char *p;
409
410 if (argc >= 1)
411 {
412 errno = 0;
413 t_interval = strtol(argv[0], &p, 0);
414 t_intervalp = argv[0];
415 if (errno || (*p != '\0') || t_interval <= 0 )
416 exit_usage();
417 if (argc >= 2)
418 {
419 errno=0;
420 n_samples = strtol(argv[1], &p, 0);
421 n_samplesp = argv[1];
422 if (errno || (*p != '\0') || n_samples <= 0)
423 exit_usage();
424 }
425 }
426 }
427
428 /* where does the input come from */
429 if (fflag)
430 {
431 (void)open_input_file(infile);
432 }
433 else if (optstringval == 2)
434 {
435 /*
436 * Create a filename of the form /var/log/sa/sadd
437 * where "dd" is the date of the month
438 */
439 curr_time = time((time_t *)0); /* returns time in seconds */
440
441 /*
442 timebuf will be a 26-character string of the form:
443 Thu Nov 24 18:22:48 1986\n\0
444 */
445
446 ctime_r(&curr_time, timebuf);
447 strncpy(filenamebuf, "/var/log/sa/sa", 14);
448 strncpy(&filenamebuf[14], &timebuf[8], 2);
449 if (filenamebuf[14] == ' ')
450 filenamebuf[14] = '0';
451 filenamebuf[16]='\0';
452 infile = filenamebuf;
453 (void)open_input_file(infile);
454 }
455 else if (optstringval == 1)
456 {
457 /* launch sadc */
458 if (pipe(fd) == -1)
459 {
460 fprintf(stderr, "sar: pipe(2) failed, errno = (%d)\n",errno);
461 exit(1);
462 }
463
464 if ((pid=fork()) == 0)
465 {
466#if 0
467 int efd;
468#endif
469
470 /* This is the child */
471 /* Close all file descriptors except the one we need */
472
473 for (i=0; i <= KERN_MAXFILESPERPROC; i++) {
474 if ((i != fd[0]) && (i != fd[1]))
475 (void)close(i);
476 }
477#if 0
478 efd = open("/tmp/errlog", O_CREAT|O_APPEND|O_RDWR, 0666);
479 if (dup2(efd,2) == -1) {
480 exit(1);
481 }
482#endif
483 /* Dup the two file descriptors to stdin and stdout */
484 if (dup2(fd[0],0) == -1) {
485 exit(1);
486 }
487 if (dup2(fd[1],1) == -1) {
488 exit(1);
489 }
490 /* Exec the child process */
491 if (network_mode & NET_PPP_MODE)
492 execl("/usr/lib/sa/sadc", "sadc", sadc_mflagp, sadc_ppp_modep, t_intervalp, n_samplesp, NULL);
493 else
494 execl("/usr/lib/sa/sadc", "sadc", t_intervalp, n_samplesp, NULL);
495
496 perror("execlp sadc");
497 exit(2); /* This call of exit(2) should never be reached... */
498 }
499 else
500 { /* This is the parent */
501 if (pid == -1) {
502 fprintf(stderr, "sar: fork(2) failed, errno = (%d)\n",errno);
503 exit(1);
504 }
505 close (fd[1]); /* parent does not write to the pipe */
506 ifd = fd[0]; /* parent will read from the pipe */
507 }
508 }
509 else
510 {
511 /* we're confused about source of input data - bail out */
512 fprintf(stderr, "sar: no input file recognized\n");
513 exit_usage();
514 }
515
516 /* start reading input data and format the output */
517 (void)do_main_workloop();
518 (void)exit_average();
519 exit(0);
520}
521
522static void
523exit_usage()
524{
525 fprintf(stderr, "\n%s\n\n", optionstring1_usage);
526 fprintf(stderr, "%s\n", optionstring2_usage);
527 exit(EXIT_FAILURE);
528}
529
530static void
531open_output_file(char *path)
532{
533 if ((ofd = open(path, O_CREAT|O_APPEND|O_TRUNC|O_WRONLY, 0664)) == -1 )
534 {
535 /* failed to open path */
536 fprintf(stderr, "sar: failed to open output file [%s]\n", path);
537 exit_usage();
538 }
539}
540
541
542static void
543open_input_file(char *path)
544{
545 if ((ifd = open(path, O_RDONLY, 0)) == -1)
546 {
547 /* failed to open path */
548 fprintf(stderr, "sar: failed to open input file [%d][%s]\n", ifd, path);
549 exit_usage();
550 }
551}
552
553static void
554read_record_hdr(hdr, writeflag)
555 struct record_hdr *hdr;
556 int writeflag;
557{
558 errno = 0;
559 int num = 0;
560 int n = 0;
561 size_t size = 0;
562
563 size = sizeof(struct record_hdr);
564
565 while (size)
566 {
567 num = read(ifd, &hdr[n], size);
568 if (num > 0)
569 {
570 n += num;
571 size -= num;
572 }
573 else if (num == 0)
574 exit_average();
575 else
576 {
577 fprintf(stderr, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno, (int)num, (int)size);
578 exit(EXIT_FAILURE);
579 }
580 }
581
582 if (oflag && writeflag)
583 write_record_hdr(hdr);
584
585 return;
586}
587
588static void
589read_record_data(buf, size, writeflag)
590 char * buf;
591 size_t size;
592 int writeflag;
593{
594 errno = 0;
595 size_t num = 0;
596 size_t n = 0;
597
598 while (size)
599 {
600 num = read(ifd, &buf[n], size);
601 if (num > 0)
602 {
603 n += num;
604 size -= num;
605 }
606 else if (num == 0) /* EOF */
607 exit_average();
608 else
609 {
610 fprintf(stderr, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno, (int)num, (int)size);
611 exit(EXIT_FAILURE);
612 }
613 }
614
615 if (oflag && writeflag)
616 write_record_data(buf, n);
617
618 return;
619}
620
621static void
622write_record_hdr(hdr)
623 struct record_hdr *hdr;
624{
625 errno = 0;
626 int num;
627
628 if ((num = write(ofd, hdr, sizeof(struct record_hdr))) == -1)
629 {
630 fprintf(stderr, "sar: write_record_hdr failed, errno=%d\n", errno);
631 exit(EXIT_FAILURE);
632 }
633 return;
634}
635
636static void
637write_record_data(char *buf, size_t nbytes)
638{
639 errno = 0;
640 int num;
641 if ((num = write(ofd, buf, nbytes)) == -1)
642 {
643 fprintf(stderr, "sar: write_record_data failed, errno=%d\n", errno);
644 exit(EXIT_FAILURE);
645 }
646 return;
647}
648
649/*
650 * Convert a string of one of the forms
651 * hh hh:mm hh:mm:ss
652 * into the number of seconds.
653 * exit on error
654*/
655
656static time_t
657convert_hms(string)
658 char *string;
659{
660 int hh = 0; /* hours */
661 int mm = 0; /* minutes */
662 int ss = 0; /* seconds */
663 time_t seconds;
664 time_t timestamp;
665 struct tm *tm;
666 int i;
667
668 if (string == NULL || *string == '\0')
669 goto convert_err;
670
671 for (i=0; string[i] != '\0'; i++)
672 {
673 if ((!isdigit(string[i])) && (string[i] != ':'))
674 {
675 goto convert_err;
676 }
677 }
678
679 if (sscanf(string, "%d:%d:%d", &hh, &mm, &ss) != 3)
680 {
681 if (sscanf(string, "%d:%d", &hh, &mm) != 2)
682 {
683 if (sscanf(string, "%d", &hh) != 1)
684 {
685 goto convert_err;
686 }
687 }
688 }
689
690 if (hh < 0 || hh >= HOURS_PER_DAY ||
691 mm < 0 || mm >= MINS_PER_HOUR ||
692 ss < 0 || ss > SECS_PER_MIN)
693 {
694 goto convert_err;
695 }
696
697 seconds = ((((hh * MINS_PER_HOUR) + mm) * SECS_PER_MIN) + ss);
698 timestamp = time((time_t *)0);
699 tm=localtime(&timestamp);
700 seconds -= tm->tm_gmtoff;
701
702 return(seconds);
703
704 convert_err:
705 fprintf(stderr, "sar: time format usage is hh[:mm[:ss]]\n");
706 exit_usage();
707 return(0);
708}
709
710
711/*
712 * Use ctime_r to convert a time value into
713 * a 26-character string of the form:
714 *
715 * Thu Nov 24 18:22:48 1986\n\0
716 */
717
718static char *
719get_hms_string(tdata, tbuf)
720 time_t tdata;
721 char *tbuf;
722{
723 time_t t;
724 char *p;
725
726 t = tdata;
727 ctime_r(&t, tbuf);
728 p=&tbuf[11];
729 tbuf[19] = 0;
730
731 return(p);
732}
733
734
735/* sample set flags */
736#define INIT_SET 0
737#define PRINT_SET 1
738#define PRINT_AVG 2
739
740static void
741do_main_workloop()
742{
743 struct record_hdr hdr;
744 time_t cur_timestamp = 0; /* seconds - Coordinated Universal Time */
745 time_t next_timestamp = 0; /* seconds - Coordinated Universal Time */
746
747 if (!find_restart_header(&hdr))
748 exit(1);
749
750 cur_timestamp = hdr.rec_timestamp;
751
752 /* convert sflag's start_time from 24 hour clock time to UTC seconds */
753 if (start_time < (cur_timestamp % SECS_PER_DAY))
754 start_time = cur_timestamp;
755 else
756 start_time += cur_timestamp - (cur_timestamp % SECS_PER_DAY);
757
758 /* convert end_time, from 24 hour clock time to UTC seconds */
759 if (end_time != 0)
760 end_time += cur_timestamp - (cur_timestamp % SECS_PER_DAY);
761
762#if 0
763 fprintf(stderr, "start = %ld, end = %ld, cur=%ld, [24hour - %ld]\n",
764 start_time, end_time, cur_timestamp,(cur_timestamp % SECS_PER_DAY));
765#endif
766
767 while (cur_timestamp < start_time)
768 {
769 bypass_sample_set(&hdr, cur_timestamp);
770 cur_timestamp = hdr.rec_timestamp;
771 }
772
773 next_timestamp = cur_timestamp + iseconds;
774 print_all_column_headings(cur_timestamp);
775 read_sample_set(INIT_SET, cur_timestamp, &hdr);
776 cur_timestamp = hdr.rec_timestamp;
777
778 while ((end_time == 0) || (next_timestamp < end_time))
779 {
780 if (cur_timestamp < next_timestamp)
781 {
782 bypass_sample_set (&hdr, cur_timestamp);
783 cur_timestamp = hdr.rec_timestamp;
784 }
785 else
786 {
787 /* need to know the seconds interval when printing averages */
788 if (avg_interval == 0)
789 {
790 if (iseconds)
791 avg_interval = iseconds;
792 else
793 avg_interval = cur_timestamp - next_timestamp;
794 }
795 next_timestamp = cur_timestamp + iseconds;
796 read_sample_set(PRINT_SET, cur_timestamp, &hdr);
797 cur_timestamp = hdr.rec_timestamp;
798 }
799 }
800 exit_average();
801}
802
803
804/*
805 * Find and fill in a restart header. We don't write
806 * the binary data when looking for SAR_RESTART.
807 * Return: 1 on success
808 * 0 on failure
809 */
810static int
811find_restart_header (ret_hdr)
812 struct record_hdr *ret_hdr;
813{
814 struct record_hdr hdr;
815 int bufsize = 0;
816 char *buf = NULL;
817
818 errno = 0;
819
820 restart_loop:
821 read_record_hdr(&hdr, FALSE); /* exits on error */
822
823 if (hdr.rec_type == SAR_RESTART)
824 {
825 *ret_hdr = hdr;
826 if (oflag)
827 write_record_hdr(&hdr); /* writes the RESTART record */
828 if (buf)
829 free(buf);
830 return(1);
831 }
832
833 /*
834 * not the record we want...
835 * read past data and try again
836 */
837 if (hdr.rec_count)
838 {
839 if (fflag)
840 { /* seek past data in the file */
841 if ((lseek(ifd, (hdr.rec_count * hdr.rec_size), SEEK_CUR)) == -1)
842 {
843 /*exit on error */
844 fprintf(stderr, "sar: lseek failed, errno=%d\n", errno);
845 exit(EXIT_FAILURE);
846 }
847
848 }
849 /* compute data size - malloc a new buf if it's not big enough */
850 else
851 {
852 /* have to read from the pipe */
853 if (bufsize < (hdr.rec_count * hdr.rec_size))
854 {
855 if (buf)
856 free(buf);
857 bufsize = hdr.rec_count * hdr.rec_size;
858 if((buf = (char *)malloc(bufsize)) == NULL)
859 {
860 fprintf(stderr, "sar: malloc failed\n");
861 return(0);
862 }
863 }
864 /* exits on error */
865 read_record_data(buf, (hdr.rec_count * hdr.rec_size), FALSE);
866 }
867 }
868 goto restart_loop;
869}
870
871static void
872print_all_column_headings(timestamp)
873 time_t timestamp;
874{
875 char timebuf[26];
876 char *timebufp;
877
878 timebufp = get_hms_string (timestamp, timebuf);
879
880 if (uflag) /* print cpu headers */
881 print_column_heading(SAR_CPU, timebufp, 0);
882
883 if (gflag) /* print page-out activity */
884 print_column_heading(SAR_VMSTAT, timebufp, 0);
885
886 if (pflag ) /* print page-in activity */
887 print_column_heading(SAR_VMSTAT, timebufp, 1);
888
889 if (dflag) /* print drive stats */
890 print_column_heading(SAR_DRIVESTATS, timebufp, 0);
891
892 if (nflag) /* print network stats */
893 {
894 if (network_mode & NET_DEV_MODE)
895 print_column_heading(SAR_NETSTATS, timebufp, NET_DEV_MODE);
896
897 if (network_mode & NET_EDEV_MODE)
898 print_column_heading(SAR_NETSTATS, timebufp, NET_EDEV_MODE);
899 }
900}
901
902
903/*
904 * Find and fill in a timestamp header.
905 * Write the binary data when looking for SAR_TIMESTAMP
906 * Don't do anything with the data, just read past it.
907 * Return: 1 on success
908 * 0 on failure
909 */
910static int
911bypass_sample_set (ret_hdr, timestamp)
912 struct record_hdr *ret_hdr;
913 time_t timestamp;
914{
915 struct record_hdr hdr;
916 int bufsize = 0;
917 char *buf = NULL;
918
919 bypass_loop:
920 read_record_hdr(&hdr, TRUE); /* exits on error */
921
922 if (hdr.rec_type == SAR_TIMESTAMP)
923 {
924 *ret_hdr = hdr;
925 if (buf)
926 free(buf);
927 return(1);
928 }
929
930 /*
931 * not the record we want...
932 * read past data and try again
933 */
934 if (hdr.rec_count)
935 {
936 if (fflag && !oflag)
937 {
938 /*
939 * we're reading from a file and we don't have to write the
940 * binary data so seek past data in the file
941 */
942 errno = 0;
943 if ((lseek(ifd, (hdr.rec_count * hdr.rec_size), SEEK_CUR)) == -1)
944 {
945 /*exit on error */
946 fprintf(stderr, "sar: lseek failed, errno=%d\n", errno);
947 exit(EXIT_FAILURE);
948 }
949 }
950 else
951 {
952 /*
953 * We end up here when reading from pipe.
954 * malloc a new buffer if current is not big enough
955 */
956 if (bufsize < (hdr.rec_count * hdr.rec_size))
957 {
958 if (buf)
959 free(buf);
960 bufsize = hdr.rec_count * hdr.rec_size;
961 if((buf = (char *)malloc(bufsize)) == NULL)
962 {
963 fprintf(stderr, "sar: malloc failed\n");
964 exit(EXIT_FAILURE);
965 }
966 }
967
968 /* exits on error */
969 read_record_data(buf, (hdr.rec_count * hdr.rec_size), TRUE);
970 }
971 } /* end if hdr.rec_count */
972 goto bypass_loop;
973}
974
975
976/*
977 * INIT_SET: This initializes the first sample for each type.
978 * PRINT_SET: This read, compute and print out sample data.
979 */
980static void
981read_sample_set(flag, timestamp, ret_hdr)
982 int flag;
983 time_t timestamp;
984 struct record_hdr *ret_hdr;
985{
986 struct record_hdr hdr;
987 char timebuf[26];
988 char *timebufp;
989 char *indent_string;
990 char *indent_string_wide;
991 char *indent_string_narrow;
992 int sar_cpu = 0;
993 int sar_vmstat=0;
994 int sar_drivestats=0;
995 int sar_drivepath=0;
996 int sar_netstats = 0;
997
998 indent_string_wide = " ";
999 indent_string_narrow = " ";
1000 indent_string = indent_string_narrow;
1001
1002 read_record_hdr(&hdr, TRUE);
1003
1004 while (hdr.rec_type != SAR_TIMESTAMP)
1005 {
1006 switch (hdr.rec_type)
1007 {
1008 case SAR_CPU:
1009 sar_cpu = get_cpu_sample(flag, &hdr);
1010 break;
1011 case SAR_VMSTAT:
1012 sar_vmstat=get_vmstat_sample(flag, &hdr);
1013 break;
1014 case SAR_DRIVEPATH:
1015 sar_drivepath = get_drivepath_sample(flag, &hdr);
1016 if (sar_drivepath < 0)
1017 fprintf(stderr, "sar: drivepath sync code error %d\n", sar_drivepath);
1018 break;
1019 case SAR_DRIVESTATS:
1020 sar_drivestats = get_drivestats_sample(flag, &hdr);
1021 break;
1022 case SAR_NETSTATS:
1023 sar_netstats = get_netstats_sample(flag, &hdr);
1024 break;
1025 default:
1026 break;
1027 }
1028
1029 read_record_hdr(&hdr, TRUE);
1030 }
1031
1032 /* return the timestamp header */
1033 *ret_hdr = hdr;
1034
1035 if (flag == PRINT_SET)
1036 {
1037 avg_counter++;
1038 timebufp = get_hms_string(timestamp, timebuf);
1039
1040 if (uflag && sar_cpu)
1041 print_cpu_sample(timebufp);
1042
1043 if((gflag || pflag) && sar_vmstat)
1044 print_vmstat_sample(timebufp);
1045
1046 if (dflag && sar_drivestats)
1047 print_drivestats_sample(timebufp);
1048
1049 if (nflag && sar_netstats)
1050 print_netstats_sample(timebufp);
1051 }
1052}
1053
1054static void
1055skip_data(bufsize)
1056 int bufsize;
1057{
1058 char *buf = NULL;
1059
1060 if (fflag)
1061 {
1062 /* seek past data in the file */
1063 if ((lseek(ifd, bufsize, SEEK_CUR) == -1))
1064 {
1065 /*exit on error */
1066 fprintf(stderr, "sar: lseek failed, errno=%d\n", errno);
1067 exit(EXIT_FAILURE);
1068 }
1069 }
1070 else
1071 {
1072 /* have to read from the pipe */
1073 if((buf = (char *)malloc(bufsize)) == NULL)
1074 {
1075 fprintf(stderr, "sar: malloc failed\n");
1076 exit(EXIT_FAILURE);
1077 }
1078 /* even though we skip this data, we still write it if necessary */
1079 read_record_data(buf, bufsize, TRUE);
1080 }
1081 if (buf)
1082 free(buf);
1083
1084 return;
1085}
1086
1087static int
1088get_cpu_sample(flag, hdr)
1089 int flag;
1090 struct record_hdr *hdr;
1091{
1092 int datasize;
1093
1094 datasize = hdr->rec_count * hdr->rec_size;
1095
1096 if (datasize != sizeof(host_cpu_load_info_data_t))
1097 {
1098 /* read past the data but don't do anything with it */
1099 skip_data(datasize);
1100 return(0);
1101 }
1102
1103 read_record_data ((char *)&cur_cpuload, (int)sizeof(host_cpu_load_info_data_t), TRUE );
1104
1105 if (flag == INIT_SET)
1106 {
1107 prev_cpuload = cur_cpuload;
1108 bzero(&avg_cpuload, sizeof(avg_cpuload));
1109 }
1110 return(1);
1111}
1112
1113static void
1114print_cpu_sample(timebufptr)
1115 char * timebufptr;
1116{
1117
1118 double time;
1119
1120 time = 0.0;
1121 cur_cpuload.cpu_ticks[CPU_STATE_USER]
1122 -= prev_cpuload.cpu_ticks[CPU_STATE_USER];
1123
1124 prev_cpuload.cpu_ticks[CPU_STATE_USER]
1125 += cur_cpuload.cpu_ticks[CPU_STATE_USER];
1126
1127 time += cur_cpuload.cpu_ticks[CPU_STATE_USER];
1128
1129 cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
1130 -= prev_cpuload.cpu_ticks[CPU_STATE_SYSTEM];
1131
1132 prev_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
1133 += cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM];
1134
1135 time += cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM];
1136
1137 cur_cpuload.cpu_ticks[CPU_STATE_IDLE]
1138 -= prev_cpuload.cpu_ticks[CPU_STATE_IDLE];
1139
1140 prev_cpuload.cpu_ticks[CPU_STATE_IDLE]
1141 += cur_cpuload.cpu_ticks[CPU_STATE_IDLE];
1142
1143 time += cur_cpuload.cpu_ticks[CPU_STATE_IDLE];
1144
1145 avg_cpuload.cpu_ticks[CPU_STATE_USER] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_USER]
1146 / (time ? time : 1));
1147
1148 avg_cpuload.cpu_ticks[CPU_STATE_SYSTEM] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
1149 / (time ? time : 1));
1150
1151 avg_cpuload.cpu_ticks[CPU_STATE_IDLE] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_IDLE]
1152 / (time ? time : 1));
1153
1154 if(flag_count > 1)
1155 print_column_heading(SAR_CPU, timebufptr, 0);
1156
1157 fprintf(stdout, "%s%5.0f ", timebufptr,
1158 rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_USER]
1159 / (time ? time : 1)));
1160
1161 fprintf(stdout, "%4.0f ",
1162 rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
1163 / (time ? time : 1)));
1164
1165 fprintf(stdout, "%4.0f\n",
1166 rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_IDLE]
1167 / (time ? time : 1)));
1168}
1169
1170static int
1171get_vmstat_sample(flag, hdr)
1172 int flag;
1173 struct record_hdr *hdr;
1174{
1175 int datasize;
1176
1177 datasize = hdr->rec_count * hdr->rec_size;
1178
1179 if (datasize != sizeof(struct vm_statistics))
1180 {
1181 /* read past the data but don't do anything with it */
1182 skip_data(datasize);
1183 return(0);
1184 }
1185
1186 read_record_data ((char *)&cur_vmstat, (int)sizeof(struct vm_statistics), TRUE );
1187
1188 if (flag == INIT_SET)
1189 {
1190 prev_vmstat = cur_vmstat;
1191 bzero(&avg_vmstat, sizeof(avg_vmstat));
1192 }
1193 return(1);
1194}
1195
1196
1197static void
1198print_vmstat_sample(char *timebufptr)
1199{
1200
1201 cur_vmstat.faults -= prev_vmstat.faults;
1202 prev_vmstat.faults += cur_vmstat.faults;
1203 avg_vmstat.faults += cur_vmstat.faults;
1204
1205 cur_vmstat.cow_faults -= prev_vmstat.cow_faults;
1206 prev_vmstat.cow_faults += cur_vmstat.cow_faults;
1207 avg_vmstat.cow_faults += cur_vmstat.cow_faults;
1208
1209 cur_vmstat.zero_fill_count -= prev_vmstat.zero_fill_count;
1210 prev_vmstat.zero_fill_count += cur_vmstat.zero_fill_count;
1211 avg_vmstat.zero_fill_count += cur_vmstat.zero_fill_count;
1212
1213 cur_vmstat.reactivations -= prev_vmstat.reactivations;
1214 prev_vmstat.reactivations += cur_vmstat.reactivations;
1215 avg_vmstat.reactivations += cur_vmstat.reactivations;
1216
1217 cur_vmstat.pageins -= prev_vmstat.pageins;
1218 prev_vmstat.pageins += cur_vmstat.pageins;
1219 avg_vmstat.pageins += cur_vmstat.pageins;
1220
1221 cur_vmstat.pageouts -= prev_vmstat.pageouts;
1222 prev_vmstat.pageouts += cur_vmstat.pageouts;
1223 avg_vmstat.pageouts += cur_vmstat.pageouts;
1224
1225
1226 if (gflag)
1227 {
1228 if (flag_count > 1)
1229 print_column_heading(SAR_VMSTAT, timebufptr, 0);
1230 fprintf(stdout, "%s %8.1f \n", timebufptr, (float)((float)cur_vmstat.pageouts/avg_interval));
1231 }
1232
1233 if (pflag)
1234 {
1235 if (flag_count > 1)
1236 print_column_heading(SAR_VMSTAT, timebufptr, 1);
1237 fprintf(stdout, "%s %8.1f %8.1f %8.1f\n", timebufptr,
1238 (float)((float)cur_vmstat.pageins / avg_interval),
1239 (float)((float)cur_vmstat.cow_faults/avg_interval),
1240 (float)((float)cur_vmstat.faults/avg_interval));
1241 }
1242 fflush(stdout);
1243}
1244
1245static int
1246get_drivestats_sample(flag, hdr)
1247 int flag;
1248 struct record_hdr *hdr;
1249{
1250 struct drivestats *databuf;
1251 struct drivestats_report *dr;
1252 size_t datasize;
1253 int datacount;
1254 int index;
1255 int i;
1256
1257 datasize = hdr->rec_count * hdr->rec_size;
1258 datacount = hdr->rec_count;
1259
1260 if (hdr->rec_size != sizeof(struct drivestats))
1261 {
1262 /* something isn't right... read past the data but don't analyze it */
1263 skip_data(datasize);
1264 return(0);
1265 }
1266
1267 /* malloc read buffer */
1268 if ((databuf = (struct drivestats *)malloc(datasize)) == NULL)
1269 {
1270 fprintf(stderr, "sar: malloc failed\n");
1271 exit (EXIT_FAILURE);
1272 }
1273
1274 bzero(databuf, datasize);
1275
1276 read_record_data ((char *)databuf, datasize, TRUE );
1277
1278 /* clear all global current fields */
1279 for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
1280 {
1281 dr->present = 0;
1282 dr->cur_Reads = 0;
1283 dr->cur_BytesRead = 0;
1284 dr->cur_Writes = 0;
1285 dr->cur_BytesWritten = 0;
1286 dr->cur_LatentReadTime = 0;
1287 dr->cur_LatentWriteTime = 0;
1288 dr->cur_ReadErrors = 0;
1289 dr->cur_WriteErrors = 0;
1290 dr->cur_ReadRetries = 0;
1291 dr->cur_WriteRetries = 0;
1292 dr->cur_TotalReadTime = 0;
1293 dr->cur_TotalWriteTime=0;
1294 }
1295
1296 /* By this point, we have read in a complete set of diskstats from the sadc
1297 * data collector.
1298 * The order of the drives in not guaranteed.
1299 * The global report structure is a linked list, but may need initialization
1300 * We need to traverse this list and transfer the current
1301 * read data. If a disk entry isn't found, then we need to allocate one
1302 * initilize it.
1303 */
1304 for (i=0; i< datacount; i++)
1305 {
1306 struct drivestats_report *dr_last = NULL;
1307
1308 index = databuf[i].drivepath_id; /* use this as index into dp_table */
1309
1310 /* find disk entry or allocate new one*/
1311 for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
1312 {
1313 dr_last = dr;
1314 if(index == dr->drivepath_id)
1315 break;
1316 }
1317
1318 if (dr == NULL)
1319 {
1320 /* allocate new entry */
1321 if((dr = (struct drivestats_report *)malloc(sizeof(struct drivestats_report))) == NULL)
1322 {
1323 fprintf(stderr, "sar: malloc error\n");
1324 exit(EXIT_FAILURE);
1325 }
1326 bzero((char *)dr, sizeof(struct drivestats_report));
1327 dr->blocksize = databuf[i].blocksize;
1328 dr->drivepath_id = index;
1329 dr->next = NULL;
1330 dr->avg_count = 0;
1331
1332 /* get the BSDName which should be in the table by now */
1333 if ((index < dp_count) && (dp_table[index].state != DPSTATE_UNINITIALIZED))
1334 strncpy(dr->name, dp_table[index].BSDName, MAXDRIVENAME+1);
1335 else
1336 strcpy(dr->name, "disk??");
1337
1338 if (dr_head == NULL)
1339 {
1340 dr_head = dr;
1341 dr_head->next = NULL;
1342 }
1343 else
1344 {
1345 dr_last->next = (char *)dr;
1346 }
1347 } /* end if dr == NULL */
1348
1349 dr->present = TRUE;
1350 dr->cur_Reads = databuf[i].Reads;
1351 dr->cur_BytesRead = databuf[i].BytesRead;
1352 dr->cur_Writes = databuf[i].Writes;
1353 dr->cur_BytesWritten = databuf[i].BytesWritten;
1354 dr->cur_LatentReadTime = databuf[i].LatentReadTime;
1355 dr->cur_LatentWriteTime = databuf[i].LatentWriteTime;
1356 dr->cur_ReadErrors = databuf[i].ReadErrors;
1357 dr->cur_WriteErrors = databuf[i].WriteErrors;
1358 dr->cur_ReadRetries = databuf[i].ReadRetries;
1359 dr->cur_WriteRetries = databuf[i].WriteRetries;
1360 dr->cur_TotalReadTime = databuf[i].TotalReadTime;
1361 dr->cur_TotalWriteTime=databuf[i].TotalWriteTime;
1362 } /* end for loop */
1363
1364 /* Reinitialize the prev and avg fields when
1365 * This is a new disk
1366 * This is a changed disk - name change implies disk swapping
1367 * This disk is not present in this sample
1368 */
1369 for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
1370 {
1371 if (dr->drivepath_id >= dp_count)
1372 {
1373 /* something is amiss */
1374 continue;
1375 }
1376 else
1377 {
1378 index = dr->drivepath_id; /* use this as index into dp_table */
1379 }
1380
1381 if ((flag == INIT_SET) ||
1382 (dp_table[index].state == DPSTATE_NEW) ||
1383 (dp_table[index].state == DPSTATE_CHANGED) ||
1384 (!dr->present))
1385 {
1386 /*
1387 * prev will be set to cur
1388 * activate the state in dp_table
1389 */
1390 if (dr->present)
1391 dp_table[index].state = DPSTATE_ACTIVE;
1392
1393 init_drivestats(dr);
1394 }
1395 }
1396 return(1);
1397}
1398
1399static void
1400init_drivestats(struct drivestats_report *dr)
1401{
1402 dr->avg_count = 0;
1403 dr->prev_Reads = dr->cur_Reads;
1404 dr->avg_Reads = 0;
1405 dr->prev_BytesRead = dr->cur_BytesRead;
1406 dr->avg_BytesRead = 0;
1407 dr->prev_Writes = dr->cur_Writes;
1408 dr->avg_Writes = 0;
1409 dr->prev_BytesWritten = dr->cur_BytesWritten;
1410 dr->avg_BytesWritten = 0;
1411 dr->prev_LatentReadTime = dr->cur_LatentReadTime;
1412 dr->avg_LatentReadTime = 0;
1413 dr->prev_LatentWriteTime = dr->cur_LatentWriteTime ;
1414 dr->avg_LatentWriteTime = 0;
1415 dr->prev_ReadErrors = dr->cur_ReadErrors ;
1416 dr->avg_ReadErrors = 0;
1417 dr->prev_WriteErrors = dr->cur_WriteErrors ;
1418 dr->avg_WriteErrors = 0;
1419 dr->prev_ReadRetries = dr->cur_ReadRetries ;
1420 dr->avg_ReadRetries = 0;
1421 dr->prev_WriteRetries = dr->cur_WriteRetries ;
1422 dr->avg_WriteRetries = 0;
1423 dr->prev_TotalReadTime = dr->cur_TotalReadTime ;
1424 dr->avg_TotalReadTime = 0;
1425 dr->prev_TotalWriteTime = dr->cur_TotalWriteTime ;
1426 dr->avg_TotalWriteTime = 0;
1427}
1428
1429
1430static void
1431print_drivestats_sample(char *timebufptr)
1432{
1433 struct drivestats_report *dr;
1434 long double transfers_per_second;
1435 long double kb_per_transfer, mb_per_second;
1436 u_int64_t interval_bytes, interval_transfers, interval_blocks;
1437 u_int64_t interval_time;
1438 long double blocks_per_second, ms_per_transaction;
1439
1440 if (flag_count > 1)
1441 print_column_heading(SAR_DRIVESTATS, timebufptr, 0);
1442
1443 for (dr=dr_head; dr; dr=(struct drivestats_report *)dr->next)
1444 {
1445 if(!dr->present)
1446 continue;
1447
1448 /*
1449 * This sanity check is for drives that get removed and then
1450 * returned during the sampling sleep interval. If anything
1451 * looks out of sync, reinit and skip this entry. There is
1452 * no way to guard against this entirely.
1453 */
1454 if ((dr->cur_Reads < dr->prev_Reads) ||
1455 (dr->cur_BytesRead < dr->prev_BytesRead) ||
1456 (dr->cur_Writes < dr->prev_Writes) ||
1457 (dr->cur_BytesWritten < dr->prev_BytesWritten))
1458 {
1459 init_drivestats(dr);
1460 continue;
1461 }
1462
1463 dr->avg_count++;
1464
1465 dr->cur_Reads -= dr->prev_Reads;
1466 dr->prev_Reads += dr->cur_Reads;
1467 dr->avg_Reads += dr->cur_Reads;
1468
1469 dr->cur_BytesRead -= dr->prev_BytesRead;
1470 dr->prev_BytesRead += dr->cur_BytesRead;
1471 dr->avg_BytesRead += dr->cur_BytesRead;
1472
1473 dr->cur_Writes -= dr->prev_Writes ;
1474 dr->prev_Writes += dr->cur_Writes ;
1475 dr->avg_Writes += dr->cur_Writes ;
1476
1477 dr->cur_BytesWritten -= dr->prev_BytesWritten ;
1478 dr->prev_BytesWritten += dr->cur_BytesWritten ;
1479 dr->avg_BytesWritten += dr->cur_BytesWritten ;
1480
1481 dr->cur_LatentReadTime -= dr->prev_LatentReadTime ;
1482 dr->prev_LatentReadTime += dr->cur_LatentReadTime ;
1483 dr->avg_LatentReadTime += dr->cur_LatentReadTime ;
1484
1485 dr->cur_LatentWriteTime -= dr->prev_LatentWriteTime ;
1486 dr->prev_LatentWriteTime += dr->cur_LatentWriteTime ;
1487 dr->avg_LatentWriteTime += dr->cur_LatentWriteTime ;
1488
1489 dr->cur_ReadErrors -= dr->prev_ReadErrors ;
1490 dr->prev_ReadErrors += dr->cur_ReadErrors ;
1491 dr->avg_ReadErrors += dr->cur_ReadErrors ;
1492
1493 dr->cur_WriteErrors -= dr->prev_WriteErrors ;
1494 dr->prev_WriteErrors += dr->cur_WriteErrors ;
1495 dr->avg_WriteErrors += dr->cur_WriteErrors ;
1496
1497 dr->cur_ReadRetries -= dr->prev_ReadRetries ;
1498 dr->prev_ReadRetries += dr->cur_ReadRetries ;
1499 dr->avg_ReadRetries += dr->cur_ReadRetries ;
1500
1501 dr->cur_WriteRetries -= dr->prev_WriteRetries ;
1502 dr->prev_WriteRetries += dr->cur_WriteRetries;
1503 dr->avg_WriteRetries += dr->cur_WriteRetries;
1504
1505 dr->cur_TotalReadTime -= dr->prev_TotalReadTime ;
1506 dr->prev_TotalReadTime += dr->cur_TotalReadTime ;
1507 dr->avg_TotalReadTime += dr->cur_TotalReadTime ;
1508
1509 dr->cur_TotalWriteTime -= dr->prev_TotalWriteTime ;
1510 dr->prev_TotalWriteTime += dr->cur_TotalWriteTime ;
1511 dr->avg_TotalWriteTime += dr->cur_TotalWriteTime ;
1512
1513 /* I/O volume */
1514 interval_bytes = dr->cur_BytesRead + dr->cur_BytesWritten;
1515
1516 /* I/O counts */
1517 interval_transfers = dr->cur_Reads + dr->cur_Writes;
1518
1519 /* I/O time */
1520 interval_time = dr->cur_LatentReadTime + dr->cur_LatentWriteTime;
1521
1522 interval_blocks = interval_bytes / dr->blocksize;
1523 blocks_per_second = interval_blocks / avg_interval;
1524 transfers_per_second = interval_transfers / avg_interval;
1525 mb_per_second = (interval_bytes / avg_interval) / (1024 *1024);
1526
1527 kb_per_transfer = (interval_transfers > 0) ?
1528 ((long double)interval_bytes / interval_transfers)
1529 / 1024 : 0;
1530
1531 /* times are in nanoseconds, convert to milliseconds */
1532 ms_per_transaction = (interval_transfers > 0) ?
1533 ((long double)interval_time / interval_transfers)
1534 / 1000 : 0;
1535
1536 /* print device name */
1537 fprintf(stdout, "%s %-10s", timebufptr, dr->name);
1538
1539 /* print transfers per second */
1540 fprintf(stdout, "%4.0Lf ", transfers_per_second);
1541
1542 /* print blocks per second - in device blocksize */
1543 fprintf(stdout, "%4.0Lf\n", blocks_per_second);
1544 }
1545}
1546
1547/*
1548 * Print averages before exiting.
1549 */
1550static void
1551exit_average()
1552{
1553 int i;
1554
1555 if (avg_counter <= 0 )
1556 exit(0);
1557
1558 if (oflag)
1559 {
1560 if (ofd)
1561 close (ofd);
1562 ofd = 0;
1563 }
1564
1565 if (uflag) /* print cpu averages */
1566 {
1567 if(flag_count > 1)
1568 print_column_heading(SAR_CPU, 0, 0);
1569
1570 fprintf(stdout, "Average: %5d ",
1571 (int)avg_cpuload.cpu_ticks[CPU_STATE_USER]
1572 / (avg_counter ? avg_counter : 1));
1573
1574 fprintf(stdout, "%4d ",
1575 (int)avg_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
1576 / (avg_counter ? avg_counter : 1));
1577
1578 fprintf(stdout, "%4d \n",
1579 (int)avg_cpuload.cpu_ticks[CPU_STATE_IDLE]
1580 / (avg_counter ? avg_counter : 1));
1581
1582 fflush(stdout);
1583 }
1584
1585
1586 if (gflag) /* print page-out averages */
1587 {
1588 if (flag_count > 1)
1589 print_column_heading(SAR_VMSTAT, 0, 0);
1590
1591 fprintf(stdout, "Average: %8.1f\n",
1592 (float)((avg_vmstat.pageouts / (avg_counter ? avg_counter : 1)) / avg_interval));
1593 fflush(stdout);
1594 }
1595
1596 if (pflag) /* print page-in averages */
1597 {
1598 if (flag_count > 1)
1599 print_column_heading(SAR_VMSTAT, 0, 1);
1600
1601 fprintf(stdout, "Average: %8.1f %8.1f %8.1f\n",
1602 (float)(((float)avg_vmstat.pageins / (avg_counter ? avg_counter : 1)) / avg_interval),
1603 (float)(((float)avg_vmstat.cow_faults / (avg_counter ? avg_counter : 1)) / avg_interval),
1604 (float)(((float)avg_vmstat.faults / (avg_counter ? avg_counter : 1)) / avg_interval));
1605 fflush(stdout);
1606 }
1607
1608 if (dflag) /* print drivestats averages */
1609 {
1610 struct drivestats_report *dr;
1611 long double transfers_per_second;
1612 long double kb_per_transfer, mb_per_second;
1613 u_int64_t total_bytes, total_transfers, total_blocks;
1614 u_int64_t total_time;
1615 long double blocks_per_second, ms_per_transaction;
1616 int msdig;
1617
1618 if (flag_count > 1)
1619 print_column_heading(SAR_DRIVESTATS, 0, 0);
1620
1621 for (dr=dr_head; dr; dr=(struct drivestats_report *)dr->next)
1622 {
1623 /* don't bother to print out averages for disks that were removed */
1624 if (!dr->present)
1625 continue;
1626
1627 fprintf(stdout, " %s %s\n",
1628 dp_table[dr->drivepath_id].BSDName, dp_table[dr->drivepath_id].ioreg_path);
1629
1630 /* I/O volume */
1631 total_bytes = dr->avg_BytesRead + dr->avg_BytesWritten;
1632
1633 /* I/O counts */
1634 total_transfers = dr->avg_Reads + dr->avg_Writes;
1635
1636 /* I/O time */
1637 total_time = dr->avg_LatentReadTime + dr->avg_LatentWriteTime;
1638
1639 total_blocks = total_bytes / dr->blocksize;
1640 blocks_per_second = total_blocks / avg_interval;
1641 transfers_per_second = total_transfers / avg_interval;
1642 mb_per_second = (total_bytes / avg_interval) / (1024 *1024);
1643
1644 kb_per_transfer = (total_transfers > 0) ?
1645 ((long double)total_bytes / total_transfers)
1646 / 1024 : 0;
1647
1648 /* times are in nanoseconds, convert to milliseconds */
1649 ms_per_transaction = (total_transfers > 0) ?
1650 ((long double)total_time / total_transfers)
1651 / 1000 : 0;
1652 msdig = (ms_per_transaction < 100.0) ? 1 : 0;
1653 fprintf(stdout, "Average: %-10s %4.0Lf %4.0Lf\n",
1654 dr->name,
1655 (transfers_per_second / dr->avg_count),
1656 (blocks_per_second / dr->avg_count));
1657
1658 fflush(stdout);
1659 }
1660 } /* end if dflag */
1661
1662 if (nflag)
1663 {
1664 int avg_count;
1665
1666 if (network_mode & NET_DEV_MODE)
1667 {
1668 if (flag_count > 1)
1669 print_column_heading(SAR_NETSTATS, 0, NET_DEV_MODE);
1670 for (i = 0; i < nr_count; i++)
1671 {
1672 if (!nr_table[i].valid)
1673 continue;
1674
1675 if(nr_table[i].avg_count == 0)
1676 avg_count = 1;
1677 else
1678 avg_count = nr_table[i].avg_count;
1679
1680 fprintf(stdout, "Average: %-8.8s", nr_table[i].tname_unit);
1681
1682 fprintf (stdout, "%8llu ",
1683 ((nr_table[i].avg_ipackets / avg_count) / avg_interval));
1684
1685 fprintf (stdout, "%10llu ",
1686 ((nr_table[i].avg_ibytes / avg_count) / avg_interval));
1687
1688 fprintf (stdout, "%8llu ",
1689 ((nr_table[i].avg_opackets / avg_count) / avg_interval));
1690
1691 fprintf (stdout, "%10llu\n",
1692 ((nr_table[i].avg_obytes / avg_count) / avg_interval));
1693
1694 fflush(stdout);
1695 }
1696 }
1697
1698 if (network_mode & NET_EDEV_MODE)
1699 {
1700
1701 if(flag_count > 1)
1702 print_column_heading(SAR_NETSTATS, 0, NET_EDEV_MODE);
1703
1704 for (i = 0; i < nr_count; i++)
1705 {
1706 if (!nr_table[i].valid)
1707 continue;
1708
1709 if(nr_table[i].avg_count == 0)
1710 avg_count = 1;
1711 else
1712 avg_count = nr_table[i].avg_count;
1713
1714 fprintf(stdout, "Average: %-8.8s ", nr_table[i].tname_unit);
1715
1716 fprintf (stdout, "%7llu ",
1717 ((nr_table[i].avg_ierrors / avg_count) / avg_interval));
1718
1719 fprintf (stdout, "%7llu ",
1720 ((nr_table[i].avg_oerrors / avg_count) / avg_interval));
1721
1722 fprintf (stdout, "%5llu ",
1723 ((nr_table[i].avg_collisions / avg_count) / avg_interval));
1724
1725 fprintf (stdout, " %5llu\n",
1726 ((nr_table[i].avg_drops / avg_count) / avg_interval));
1727
1728 fflush(stdout);
1729 }
1730 }
1731
1732 } /* end if nflag */
1733 exit(0);
1734}
1735
1736
1737/*
1738 * Return < 0 failure, debugging purposes only
1739 * Return = 0 data skipped
1740 * Return > 0 success
1741 */
1742
1743static int
1744get_drivepath_sample(flag, hdr)
1745 int flag;
1746 struct record_hdr *hdr;
1747{
1748 size_t datasize;
1749 struct drivepath dp;
1750 struct drivestats_report *dr;
1751 int i, n;
1752
1753 datasize = hdr->rec_count * hdr->rec_size;
1754
1755 if (datasize != sizeof(struct drivepath))
1756 {
1757 /* read past the data but don't do anything with it */
1758 skip_data(datasize);
1759 return(0);
1760 }
1761
1762 read_record_data ((char *)&dp, (int)sizeof(struct drivepath), TRUE );
1763
1764 /*
1765 * If state is new -- put a new entry in the dp_table.
1766 * If state is changed -- traverse the drivestats_report table
1767 * and copy new name.
1768 */
1769 if (dp.state == DPSTATE_NEW)
1770 {
1771
1772 if (dp_table == NULL)
1773 {
1774 if (dp.drivepath_id != 0)
1775 return(-1);
1776 /* First setup of internal drivepath table */
1777 dp_table = (struct drivepath *)malloc(sizeof(struct drivepath));
1778 if (dp_table == NULL)
1779 return(-2);
1780 dp_count = 1;
1781 }
1782
1783 if (dflag)
1784 fprintf(stdout, "New Disk: [%s] %s\n", dp.BSDName, dp.ioreg_path);
1785
1786 /* traverse table and find next uninitialized entry */
1787 for (i = 0; i< dp_count; i++)
1788 {
1789 if (dp_table[i].state == DPSTATE_UNINITIALIZED)
1790 {
1791 if (dp.drivepath_id != i)
1792 {
1793 /* the table is out of sync - this should not happen */
1794 return (-3);
1795 }
1796 dp_table[i] = dp;
1797 return(1);
1798 }
1799 }
1800 /*
1801 * If we get here, we've run out of table entries.
1802 * Double the size of the table, then assign the next entry.
1803 */
1804 if (dp.drivepath_id != i)
1805 {
1806 /* the table is out of sync - this should not happen */
1807 return (-4);
1808 }
1809 n = dp_count * 2;
1810 dp_table = (struct drivepath *)realloc(dp_table, n * sizeof(struct drivepath));
1811 bzero(&dp_table[dp_count], dp_count * sizeof(struct drivepath));
1812 dp_table[dp_count] = dp;
1813 dp_count = n;
1814 return(1);
1815
1816 }
1817 else if (dp.state == DPSTATE_CHANGED)
1818 {
1819
1820 /* Update the name in the table */
1821 if ((dp.drivepath_id < dp_count) && (dp_table[dp.drivepath_id].state != DPSTATE_UNINITIALIZED))
1822 {
1823 if (strcmp(dp_table[dp.drivepath_id].ioreg_path, dp.ioreg_path) != 0)
1824 {
1825 /* something is amiss */
1826 return (-5);
1827 }
1828 else
1829 {
1830 if (dflag)
1831 {
1832 fprintf(stdout, "Change: [%s] %s\n", dp.BSDName,
1833 dp_table[dp.drivepath_id].ioreg_path);
1834 }
1835 strcpy(dp_table[dp.drivepath_id].BSDName, dp.BSDName);
1836
1837 for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
1838 {
1839 if (dr->drivepath_id == dp.drivepath_id)
1840 strcpy(dr->name, dp.BSDName);
1841 }
1842 return(1);
1843 }
1844 }
1845 else
1846 return(-6);
1847 }
1848 return(-7);
1849}
1850
1851/*
1852 * Bytes and packet counts are used to track
1853 * counter wraps. So, don't enforce the
1854 * NET_DEV_MODE or NET_EDEV_MODE in here.
1855 * Maintain all the stats.
1856 */
1857static void
1858set_cur_netstats(struct netstats_report *nr, struct netstats *ns)
1859{
1860
1861 nr->cur_ipackets = ns->net_ipackets;
1862 nr->cur_ibytes = ns->net_ibytes;
1863 nr->cur_opackets = ns->net_opackets;
1864 nr->cur_obytes = ns->net_obytes;
1865
1866 nr->cur_ierrors = ns->net_ierrors;
1867 nr->cur_oerrors = ns->net_oerrors;
1868 nr->cur_collisions = ns->net_collisions;
1869 nr->cur_drops = ns->net_drops;
1870
1871 nr->cur_imcasts = ns->net_imcasts;
1872 nr->cur_omcasts = ns->net_omcasts;
1873
1874}
1875
1876static void
1877init_prev_netstats(struct netstats_report *nr)
1878{
1879 nr->avg_count = 0;
1880 nr->valid = 1;
1881 nr->present = 1;
1882
1883 nr->prev_ipackets = nr->cur_ipackets;
1884 nr->avg_ipackets = 0;
1885 nr->prev_ibytes = nr->cur_ibytes;
1886 nr->avg_ibytes = 0;
1887 nr->prev_opackets = nr->cur_opackets;
1888 nr->avg_opackets = 0;
1889 nr->prev_obytes = nr->cur_obytes;
1890 nr->avg_obytes = 0;
1891
1892 nr->prev_ierrors = nr->cur_ierrors;
1893 nr->avg_ierrors = 0;
1894 nr->prev_oerrors = nr->cur_oerrors ;
1895 nr->avg_oerrors = 0;
1896 nr->prev_collisions = nr->cur_collisions ;
1897 nr->avg_collisions = 0;
1898 nr->prev_drops = nr->cur_drops ;
1899 nr->avg_drops = 0;
1900
1901 /* track these, but never displayed */
1902 nr->prev_imcasts = nr->cur_imcasts;
1903 nr->avg_imcasts = 0;
1904 nr->prev_omcasts = nr->cur_omcasts;
1905 nr->avg_omcasts = 0;
1906}
1907
1908/*
1909 * Success : 1
1910 * Failure : 0
1911 */
1912static int
1913get_netstats_sample(flag, hdr)
1914 int flag;
1915 struct record_hdr *hdr;
1916{
1917 struct netstats *databuf = NULL;
1918 size_t datasize;
1919 int datacount;
1920 int i, j;
1921
1922 datasize = hdr->rec_count * hdr->rec_size;
1923 datacount = hdr->rec_count;
1924
1925 if (hdr->rec_size != sizeof(struct netstats))
1926 {
1927 /* something isn't right... read past the data but don't analyze it */
1928 skip_data(datasize);
1929 return(0);
1930 }
1931
1932 /* malloc new or bigger read buffer */
1933 if((netstat_readbuf == NULL) || (netstat_readbuf_size < datasize))
1934 {
1935 if (netstat_readbuf)
1936 free (netstat_readbuf);
1937
1938 if ((netstat_readbuf = (struct netstats *)malloc(datasize)) == NULL)
1939 {
1940 fprintf(stderr, "sar: malloc failed\n");
1941 exit (EXIT_FAILURE);
1942 }
1943 netstat_readbuf_size = datasize;
1944 }
1945
1946 bzero(netstat_readbuf, netstat_readbuf_size);
1947 databuf = netstat_readbuf;
1948
1949 read_record_data ((char *)databuf, datasize, TRUE );
1950
1951 if (nr_table == NULL)
1952 {
1953 /* initial internal table setup */
1954 nr_table = (struct netstats_report *)malloc(datacount * sizeof(struct netstats_report));
1955 nr_count = datacount;
1956 bzero(nr_table, (datacount * sizeof(struct netstats_report)));
1957
1958 /* on first init, this is faster than finding our way to NEW_ENTRY */
1959 for (i = 0; i < datacount; i++)
1960 {
1961 if (!(network_mode & NET_PPP_MODE))
1962 {
1963 if (!strncmp(databuf[i].tname_unit, "ppp", 3))
1964 continue; /*
1965 * Skip ppp interfaces.
1966 * ie don't even put them in this internal table.
1967 */
1968 }
1969 strncpy(nr_table[i].tname_unit, databuf[i].tname_unit, MAX_TNAME_UNIT_SIZE);
1970 nr_table[i].tname_unit[MAX_TNAME_UNIT_SIZE] = '\0';
1971 set_cur_netstats(&nr_table[i], &databuf[i]);
1972 init_prev_netstats(&nr_table[i]);
1973 }
1974 return(1);
1975 }
1976
1977 /*
1978 * clear all the present flags.
1979 * As we traverse the current sample set
1980 * and update the internal table, the flag
1981 * is reset.
1982 */
1983 for (i = 0; i < nr_count; i++)
1984 {
1985 nr_table[i].present = 0;
1986 }
1987
1988 /*
1989 * Find and update table entries.
1990 * Init new entries.
1991 */
1992 for (i=0; i<datacount; i++)
1993 {
1994 int found;
1995 char *name;
1996 int nr_index;
1997 int n;
1998
1999 name = databuf[i].tname_unit;
2000 found = 0;
2001
2002 if (!(network_mode & NET_PPP_MODE))
2003 {
2004 if (!strncmp(name, "ppp", 3))
2005 continue; /* skip ppp interfaces */
2006 }
2007
2008 /* Find the matching entry using the interface name */
2009 for (j=0; j < nr_count && !found; j++)
2010 {
2011 if (nr_table[j].valid)
2012 {
2013 if(!strcmp(nr_table[j].tname_unit, name))
2014 {
2015 found = 1;
2016 nr_table[j].present = 1;
2017 set_cur_netstats(&nr_table[j], &databuf[i]);
2018 }
2019 }
2020 } /* end for */
2021
2022 if (!found) /* this is a new entry */
2023 {
2024 /* Find an invalid entry in the table and init it */
2025 for (j=0; j < nr_count; j++)
2026 {
2027 if (!nr_table[j].valid)
2028 {
2029 nr_index = j;
2030 goto NEW_ENTRY;
2031 }
2032 }
2033
2034 /* we ran out of entries... grow the table */
2035 n = nr_count * 2;
2036 nr_table = (struct netstats_report *)realloc(nr_table, n * sizeof(struct netstats_report));
2037 bzero(&nr_table[nr_count], nr_count * sizeof (struct netstats_report));
2038 nr_index = nr_count;
2039 nr_count = n;
2040
2041 NEW_ENTRY:
2042 strncpy(nr_table[nr_index].tname_unit, databuf[i].tname_unit, MAX_TNAME_UNIT_SIZE);
2043 nr_table[nr_index].tname_unit[MAX_TNAME_UNIT_SIZE] = '\0';
2044 set_cur_netstats(&nr_table[nr_index], &databuf[i]);
2045 init_prev_netstats(&nr_table[nr_index]);
2046 }
2047
2048 } /* end for */
2049
2050 /*
2051 * Traverse the internal table. Any valid entry that wasn't
2052 * present in this sample is cleared for reuse.
2053 */
2054 for (i = 0; i < nr_count; i++)
2055 {
2056 if (nr_table[i].valid)
2057 {
2058 if (nr_table[i].present == 0)
2059 bzero(&nr_table[i], sizeof(struct netstats_report));
2060 }
2061 }
2062 return (1);
2063}
2064
2065static void
2066print_netstats_sample(char *timebufptr)
2067{
2068 int i;
2069
2070 for (i=0; i < nr_count; i++)
2071 {
2072 if (!nr_table[i].valid)
2073 continue;
2074
2075 /*
2076 * This is where we attempt to handle counters that
2077 * might wrap ... the kernel netstats are only 32 bits.
2078 *
2079 * Interfaces may go away and then return within the
2080 * sampling period. This can't be detected and it
2081 * may look like a counter wrap. An interface generation
2082 * counter will help... but isn't implemented at this time.
2083 */
2084
2085 /*
2086 * The ppp interfaces are very likely to come and go during
2087 * a sampling period. During the normal life of a ppp interface,
2088 * it's less likely that the packet counter will wrap, so if
2089 * it appears to have done so, is probably because the
2090 * interface unit number has been reused.
2091 * We reinitialize that interface in that case.
2092 */
2093 if (network_mode & NET_PPP_MODE)
2094 {
2095 /*
2096 * ppp interfaces won't even make it into this table
2097 * when NET_PPP_MODE isn't set
2098 */
2099 if (!strncmp(nr_table[i].tname_unit, "ppp", 3))
2100 {
2101 /*
2102 * Both ipackets and opackets have to be less
2103 * than the previous counter to cause us to reinit.
2104 */
2105
2106 if ((nr_table[i].cur_ipackets < nr_table[i].prev_ipackets)
2107 && (nr_table[i].cur_opackets < nr_table[i].prev_opackets))
2108 {
2109 init_prev_netstats(&nr_table[i]);
2110 continue;
2111 }
2112 }
2113 }
2114
2115 nr_table[i].avg_count ++;
2116
2117#ifdef IFNET_32_BIT_COUNTERS
2118 while (nr_table[i].cur_ipackets < nr_table[i].prev_ipackets)
2119 nr_table[i].cur_ipackets += 0x100000000LL;
2120#endif /* IFNET_32_BIT_COUNTERS */
2121 nr_table[i].cur_ipackets -= nr_table[i].prev_ipackets;
2122 nr_table[i].prev_ipackets += nr_table[i].cur_ipackets;
2123 nr_table[i].avg_ipackets += nr_table[i].cur_ipackets;
2124
2125
2126#ifdef IFNET_32_BIT_COUNTERS
2127 while (nr_table[i].cur_ibytes < nr_table[i].prev_ibytes)
2128 nr_table[i].cur_ibytes += 0x100000000LL;
2129#endif /* IFNET_32_BIT_COUNTERS */
2130 nr_table[i].cur_ibytes -= nr_table[i].prev_ibytes;
2131 nr_table[i].prev_ibytes += nr_table[i].cur_ibytes;
2132 nr_table[i].avg_ibytes += nr_table[i].cur_ibytes;
2133
2134
2135#ifdef IFNET_32_BIT_COUNTERS
2136 while (nr_table[i].cur_opackets < nr_table[i].prev_opackets)
2137 nr_table[i].cur_opackets += 0x100000000LL;
2138#endif /* IFNET_32_BIT_COUNTERS */
2139 nr_table[i].cur_opackets -= nr_table[i].prev_opackets;
2140 nr_table[i].prev_opackets += nr_table[i].cur_opackets;
2141 nr_table[i].avg_opackets += nr_table[i].cur_opackets;
2142
2143#ifdef IFNET_32_BIT_COUNTERS
2144 while (nr_table[i].cur_obytes < nr_table[i].prev_obytes)
2145 nr_table[i].cur_obytes += 0x100000000LL;
2146#endif /* IFNET_32_BIT_COUNTERS */
2147 nr_table[i].cur_obytes -= nr_table[i].prev_obytes;
2148 nr_table[i].prev_obytes += nr_table[i].cur_obytes;
2149 nr_table[i].avg_obytes += nr_table[i].cur_obytes;
2150
2151
2152#ifdef IFNET_32_BIT_COUNTERS
2153 while (nr_table[i].cur_ierrors < nr_table[i].prev_ierrors)
2154 nr_table[i].cur_ierrors += 0x100000000LL;
2155#endif /* IFNET_32_BIT_COUNTERS */
2156 nr_table[i].cur_ierrors -= nr_table[i].prev_ierrors;
2157 nr_table[i].prev_ierrors += nr_table[i].cur_ierrors;
2158 nr_table[i].avg_ierrors += nr_table[i].cur_ierrors;
2159
2160#ifdef IFNET_32_BIT_COUNTERS
2161 while (nr_table[i].cur_oerrors < nr_table[i].prev_oerrors)
2162 nr_table[i].cur_oerrors += 0x100000000LL;
2163#endif /* IFNET_32_BIT_COUNTERS */
2164 nr_table[i].cur_oerrors -= nr_table[i].prev_oerrors;
2165 nr_table[i].prev_oerrors += nr_table[i].cur_oerrors;
2166 nr_table[i].avg_oerrors += nr_table[i].cur_oerrors;
2167
2168#ifdef IFNET_32_BIT_COUNTERS
2169 while (nr_table[i].cur_collisions < nr_table[i].prev_collisions)
2170 nr_table[i].cur_collisions += 0x100000000LL;
2171#endif /* IFNET_32_BIT_COUNTERS */
2172 nr_table[i].cur_collisions -= nr_table[i].prev_collisions;
2173 nr_table[i].prev_collisions += nr_table[i].cur_collisions;
2174 nr_table[i].avg_collisions += nr_table[i].cur_collisions;
2175
2176#ifdef IFNET_32_BIT_COUNTERS
2177 while (nr_table[i].cur_drops < nr_table[i].prev_drops)
2178 nr_table[i].cur_drops += 0x100000000LL;
2179#endif /* IFNET_32_BIT_COUNTERS */
2180 nr_table[i].cur_drops -= nr_table[i].prev_drops;
2181 nr_table[i].prev_drops += nr_table[i].cur_drops;
2182 nr_table[i].avg_drops += nr_table[i].cur_drops;
2183
2184
2185#ifdef IFNET_32_BIT_COUNTERS
2186 while (nr_table[i].cur_imcasts < nr_table[i].prev_imcasts)
2187 nr_table[i].cur_imcasts += 0x100000000LL;
2188#endif /* IFNET_32_BIT_COUNTERS */
2189 nr_table[i].cur_imcasts -= nr_table[i].prev_imcasts;
2190 nr_table[i].prev_imcasts += nr_table[i].cur_imcasts;
2191 nr_table[i].avg_imcasts += nr_table[i].cur_imcasts;
2192
2193#ifdef IFNET_32_BIT_COUNTERS
2194 while (nr_table[i].cur_omcasts < nr_table[i].prev_omcasts)
2195 nr_table[i].cur_omcasts += 0x100000000LL;
2196#endif /* IFNET_32_BIT_COUNTERS */
2197 nr_table[i].cur_omcasts -= nr_table[i].prev_omcasts;
2198 nr_table[i].prev_omcasts += nr_table[i].cur_omcasts;
2199 nr_table[i].avg_omcasts += nr_table[i].cur_omcasts;
2200 }
2201
2202
2203 if (!(flag_count > 1))
2204 fprintf(stdout, "\n");
2205
2206 if (network_mode & NET_DEV_MODE)
2207 {
2208 if (flag_count > 1)
2209 print_column_heading(SAR_NETSTATS, timebufptr, NET_DEV_MODE);
2210
2211 for (i=0; i < nr_count; i++)
2212 {
2213 if (!nr_table[i].valid)
2214 continue;
2215
2216 if (!(network_mode & NET_PPP_MODE))
2217 {
2218 if (!strncmp(nr_table[i].tname_unit, "ppp", 3))
2219 {
2220 continue; /* skip any ppp interfaces */
2221 }
2222 }
2223
2224 /* print the interface name */
2225 fprintf(stdout, "%s %-8.8s", timebufptr, nr_table[i].tname_unit);
2226
2227 fprintf (stdout, "%8llu ",
2228 (nr_table[i].cur_ipackets / avg_interval));
2229
2230 fprintf (stdout, "%10llu ",
2231 (nr_table[i].cur_ibytes / avg_interval));
2232
2233 fprintf (stdout, "%8llu ",
2234 (nr_table[i].cur_opackets / avg_interval));
2235
2236 fprintf (stdout, "%10llu\n",
2237 (nr_table[i].cur_obytes / avg_interval));
2238 }
2239 }
2240
2241
2242 if (network_mode & NET_EDEV_MODE)
2243 {
2244 if(flag_count > 1)
2245 {
2246 print_column_heading(SAR_NETSTATS, timebufptr, NET_EDEV_MODE);
2247 }
2248
2249 for (i=0; i < nr_count; i++)
2250 {
2251 if (!nr_table[i].valid)
2252 continue;
2253
2254 if (!(network_mode & NET_PPP_MODE))
2255 {
2256 if (!strncmp(nr_table[i].tname_unit, "ppp", 3))
2257 {
2258 continue; /* skip any ppp interfaces */
2259 }
2260 }
2261
2262 /* print the interface name */
2263 fprintf(stdout, "%s %-8.8s ", timebufptr, nr_table[i].tname_unit);
2264
2265 fprintf (stdout, "%7llu ",
2266 (nr_table[i].cur_ierrors / avg_interval));
2267
2268 fprintf (stdout, "%7llu ",
2269 (nr_table[i].cur_oerrors / avg_interval));
2270
2271 fprintf (stdout, "%5llu ",
2272 (nr_table[i].cur_collisions / avg_interval));
2273
2274 fprintf (stdout, " %5llu\n",
2275 (nr_table[i].cur_drops / avg_interval));
2276 }
2277 fflush(stdout);
2278 }
2279}
2280
2281static void
2282print_column_heading(int type, char *timebufptr, int mode)
2283{
2284 char *p;
2285
2286 p = timebufptr;
2287
2288 if (p == NULL)
2289 p = "Average:";
2290
2291 if (!(flag_count > 1))
2292 fprintf(stdout, "\n");
2293
2294 switch (type)
2295 {
2296 case SAR_CPU:
2297 fprintf (stdout, "\n%s %%usr %%sys %%idle\n", p);
2298 break;
2299
2300 case SAR_VMSTAT:
2301 if (mode == 0) /* gflag */
2302 fprintf(stdout, "\n%s pgout/s\n", p);
2303 else if (mode == 1) /* pflag */
2304 fprintf(stdout, "\n%s pgin/s pflt/s vflt/s\n", p);
2305 break;
2306 case SAR_DRIVESTATS:
2307 fprintf(stdout, "\n%s device r+w/s blks/s\n", p);
2308 break;
2309 case SAR_NETSTATS:
2310 if (mode == NET_DEV_MODE)
2311 {
2312 fprintf(stdout, "\n%s %-8.8s %8.8s %10.10s %8.8s %10.10s\n", p,
2313 " IFACE", "Ipkts/s", "Ibytes/s", "Opkts/s", "Obytes/s");
2314 }
2315 else if (mode == NET_EDEV_MODE)
2316 {
2317 fprintf(stdout, "\n%s %-8.8s %7.7s %7.7s %5s %s\n", p,
2318 " IFACE", "Ierrs/s", "Oerrs/s", "Coll/s", "Drop/s");
2319 }
2320 break;
2321 default:
2322 break;
2323 }
2324}
2325