-/*
- * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
- * Reserved.
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
-*/
-
-/*
- cc -Wall -I. -I ../sadc.tproj -O -o sar sar.c
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <time.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <signal.h>
-#include <mach/mach.h>
-#include <sys/param.h>
-#include <sys/sysctl.h>
-
-#include <sadc.h>
-#include <sar.h>
-
-
-#define IFNET_32_BIT_COUNTERS 1
-
-/* Options used only for launching sadc */
-int t_interval = 5; /* in seconds */
-char * t_intervalp = "5";
-int n_samples = 1; /* number of sample loops */
-char * n_samplesp = "1";
-
-/* Used only for storing the binary output after launching sadc */
-char *outfile = NULL; /* output file */
-int ofd = 0; /* output file descriptor */
-
-/*
- * When launching sadc, this file descriptor reads sadc's stdout
- * via pipe.
- * When not launching sadc, this file descriptor will be either
- * the input file passed in with the -f flag
- * or the standard input file /var/log/sa/saXX
- */
-int ifd = 0; /* input file descriptor */
-char *infile = NULL; /* input file */
-
-
-
-/* Used when we have to luanch sadc */
-pid_t pid;
-int fd[2]; /* read from fd[0], write to fd[1] */
-
-char *optionstring1 = "Adgn:puo:";
-char *optionstring1_usage = "/usr/bin/sar [-Adgpu] [-n { DEV | EDEV | PPP } ] [-o filename] t [n]";
-char *optionstring2 = "Adgn:pue:f:i:s:";
-char *optionstring2_usage = "/usr/bin/sar [-Adgpu] [-n { DEV | EDEV | PPP }] [-e time] [-f filename] [-i sec] [-s time]";
-
-
-/* option flags */
-int aflag = 0;
-int Aflag = 0;
-int bflag = 0;
-int cflag = 0;
-int dflag = 0; /* drive statistics */
-int gflag = 0; /* page-out activity */
-int kflag = 0;
-int mflag = 0;
-
-int nflag = 0; /* network statistics */
-int network_mode = 0;
-char *sadc_mflagp = "-m";
-char *sadc_ppp_modep = "PPP";
-
-int pflag = 0; /* page-in activity */
-int qflag = 0;
-int rflag = 0;
-int uflag = 0; /* cpu utilization - this is the only default */
-int vflag = 0;
-int wflag = 0;
-int yflag = 0;
-int set_default_flag = 1;
-int flag_count = 0;
-
-/*
- * To get the current time of day in seconds
- * based on a 24 hour clock, pass in the time_t from time()
- * the remainder is the current time in seconds
-*/
-#define HOURS_PER_DAY 24
-#define MINS_PER_HOUR 60
-#define SECS_PER_MIN 60
-#define SECS_PER_DAY (SECS_PER_MIN * MINS_PER_HOUR * HOURS_PER_DAY)
-
-/* end time delimiter -- converted from hh:mm:ss to seconds */
-time_t end_time = 0;
-
-int iflag = 0;
-int iseconds = 0; /* interval seconds, default = 0 implies all samples are
- * printed */
-
-/* start time delimiter -- converted from hh:mm:ss to seconds */
-time_t start_time = 0;
-
-int oflag = 0;
-int fflag = 0;
-
-/* stat records average and previous */
-struct vm_statistics prev_vmstat, avg_vmstat, cur_vmstat;
-host_cpu_load_info_data_t prev_cpuload, avg_cpuload, cur_cpuload;
-struct drivestats_report *dr_head = NULL;
-
-/* internal table of drive path mappings */
-struct drivepath *dp_table = NULL;
-int dp_count = 0;
-
-/* internal table of network interface statistics */
-struct netstats_report *nr_table = NULL;
-int nr_count;
-struct netstats *netstat_readbuf = NULL;
-size_t netstat_readbuf_size = 0;
-
-int avg_counter = 0;
-int avg_interval = 0;
-
-extern int errno;
-
-/* Forward function declarations */
-static void exit_usage();
-static void open_output_file(char *path);
-static void open_input_file(char *path);
-static void read_record_hdr(struct record_hdr *hdr, int writeflag);
-static void read_record_data(char *buf, size_t size, int writeflag);
-static void write_record_hdr(struct record_hdr *hdr);
-static void write_record_data(char *buf, size_t size);
-static time_t convert_hms(char *string);
-static char *get_hms_string(time_t, char *);
-static int find_restart_header(struct record_hdr *);
-static void print_all_column_headings (time_t timestamp);
-static void print_column_heading (int type, char *timebufptr, int mode);
-static void read_sample_set(int, time_t, struct record_hdr *);
-static void do_main_workloop();
-static int bypass_sample_set(struct record_hdr *, time_t);
-static void skip_data(int);
-static int get_cpu_sample(int flag, struct record_hdr *hdr);
-static void print_cpu_sample(char *timebufptr);
-static int get_vmstat_sample(int flag, struct record_hdr *hdr);
-static void print_vmstat_sample(char *timebufptr);
-
-static int get_drivestats_sample(int flag, struct record_hdr *hdr);
-static void init_drivestats(struct drivestats_report *dr);
-static void print_drivestats_sample(char *timebufptr);
-static int get_drivepath_sample(int flag, struct record_hdr *hdr);
-
-static void set_cur_netstats(struct netstats_report *nr, struct netstats *ns);
-static void init_prev_netstats(struct netstats_report *nr);
-static int get_netstats_sample(int flag, struct record_hdr *hdr);
-static void print_netstats_sample(char *timebufptr);
-
-static void exit_average();
-
-int
-main(argc, argv)
- int argc;
- char *argv[];
-{
-
- char ch;
-
- time_t curr_time; /* current time in seconds */
- char timebuf[26];
- char filenamebuf[20];
- char *optstring = NULL;
- int optstringval;
- int i;
-
- /*
- * Detirmine which option string to use
- */
-
- optreset=0;
- optstringval=0;
-
- while((ch=getopt(argc, argv, "aAbcdgkmn:pqruvwyo:e:f:i:s:")) != EOF) {
- switch(ch) {
- case 'o':
- if (optstringval == 2)
- exit_usage();
- optstring=optionstring1;
- optstringval=1;
- break;
- case 'e':
- case 'f':
- case 'i':
- case 's':
- if (optstringval == 1)
- exit_usage();
- optstring=optionstring2;
- optstringval=2;
- break;
- default:
- /* ignore for now */
- break;
- }
- }
-
- if (!optstring)
- {
- /* still trying to determine which option string to use */
- if (argc - optind > 0)
- {
- optstring=optionstring1; /* we should have a t_second value */
- optstringval=1;
- }
- else
- {
- optstring=optionstring2;
- optstringval=2;
- }
- }
-
- optreset = optind = 1;
- while ((ch=getopt(argc, argv, optstring)) != EOF) {
- switch (ch) {
- case 'a':
- aflag = 1;
- set_default_flag = 0;
- flag_count++;
- break;
- case 'A':
- Aflag = 1;
- set_default_flag = 0;
- flag_count++;
- break;
- case 'b':
- bflag = 1;
- set_default_flag = 0;
- flag_count++;
- break;
- case 'c':
- cflag = 1;
- set_default_flag = 0;
- flag_count++;
- break;
- case 'd':
- dflag = 1;
- set_default_flag = 0;
- flag_count++;
- break;
- case 'g':
- gflag = 1;
- set_default_flag = 0;
- flag_count++;
- break;
- case 'k':
- kflag = 1;
- set_default_flag = 0;
- flag_count++;
- break;
- case 'm':
- mflag = 1;
- set_default_flag = 0;
- flag_count++;
- break;
- case 'n':
- nflag= 1;
- if (!strncmp(optarg, "PPP", 3))
- network_mode |= NET_PPP_MODE;
- else if (!strncmp(optarg, "DEV", 3))
- network_mode |= NET_DEV_MODE;
- else if (!strncmp(optarg, "EDEV", 4))
- network_mode |= NET_EDEV_MODE;
- else
- exit_usage();
- set_default_flag = 0;
- flag_count++;
- break;
- case 'p':
- pflag = 1;
- set_default_flag = 0;
- flag_count++;
- break;
- case 'q':
- qflag = 1;
- set_default_flag = 0;
- flag_count++;
- break;
- case 'r':
- rflag = 1;
- set_default_flag = 0;
- flag_count++;
- break;
- case 'u':
- uflag= 1;
- set_default_flag = 0;
- flag_count++;
- break;
- case 'v':
- vflag = 1;
- set_default_flag = 0;
- flag_count++;
- break;
- case 'w':
- wflag = 1;
- set_default_flag = 0;
- flag_count++;
- break;
- case 'y':
- yflag = 1;
- set_default_flag = 0;
- flag_count++;
- break;
- case 'o':
- /* open the output file */
- oflag = 1;
- outfile=optarg;
- (void)open_output_file(outfile);
- break;
- case 'e': /* eflag */
- end_time = convert_hms(optarg);
- break;
- case 'f':
- fflag = 1;
- infile=optarg;
- break;
- case 'i':
- iflag = 1;
- iseconds=atoi(optarg);
- break;
- case 's':
- start_time = convert_hms(optarg);
- break;
- default:
- exit_usage();
- break;
- }
- }
-
- /* setup default uflag option */
- if (Aflag)
- {
- dflag = gflag = pflag = uflag = 1;
- if (!nflag)
- {
- /*
- * Add network stats to the load
- * but avoid PPP data by default.
- */
- nflag = 1;
- network_mode = NET_DEV_MODE | NET_EDEV_MODE;;
- }
- flag_count = 2; /* triggers column headings */
- }
- else if (set_default_flag)
- {
- uflag=1;
- flag_count++;
- }
-
- if (nflag)
- {
- if (network_mode & NET_PPP_MODE)
- {
- if (!(network_mode & NET_DEV_MODE) &&
- !(network_mode & NET_EDEV_MODE))
- {
- /* set defaults */
- network_mode |= NET_DEV_MODE;
- network_mode |= NET_EDEV_MODE;
- flag_count++;
- }
- }
- }
-
- argc -= optind;
- argv += optind;
-
- /* set up signal handlers */
- signal(SIGINT, exit_average);
- signal(SIGQUIT, exit_average);
- signal(SIGHUP, exit_average);
- signal(SIGTERM, exit_average);
-
- if (optstringval == 1)
- {
- /* expecting a time interval */
-
- char *p;
-
- if (argc >= 1)
- {
- errno = 0;
- t_interval = strtol(argv[0], &p, 0);
- t_intervalp = argv[0];
- if (errno || (*p != '\0') || t_interval <= 0 )
- exit_usage();
- if (argc >= 2)
- {
- errno=0;
- n_samples = strtol(argv[1], &p, 0);
- n_samplesp = argv[1];
- if (errno || (*p != '\0') || n_samples <= 0)
- exit_usage();
- }
- }
- }
-
- /* where does the input come from */
- if (fflag)
- {
- (void)open_input_file(infile);
- }
- else if (optstringval == 2)
- {
- /*
- * Create a filename of the form /var/log/sa/sadd
- * where "dd" is the date of the month
- */
- curr_time = time((time_t *)0); /* returns time in seconds */
-
- /*
- timebuf will be a 26-character string of the form:
- Thu Nov 24 18:22:48 1986\n\0
- */
-
- ctime_r(&curr_time, timebuf);
- strncpy(filenamebuf, "/var/log/sa/sa", 14);
- strncpy(&filenamebuf[14], &timebuf[8], 2);
- if (filenamebuf[14] == ' ')
- filenamebuf[14] = '0';
- filenamebuf[16]='\0';
- infile = filenamebuf;
- (void)open_input_file(infile);
- }
- else if (optstringval == 1)
- {
- /* launch sadc */
- if (pipe(fd) == -1)
- {
- fprintf(stderr, "sar: pipe(2) failed, errno = (%d)\n",errno);
- exit(1);
- }
-
- if ((pid=fork()) == 0)
- {
-#if 0
- int efd;
-#endif
- int fdlimit = getdtablesize();
-
- /* This is the child */
- /* Close all file descriptors except the one we need */
-
- for (i=0; i < fdlimit; i++) {
- if ((i != fd[0]) && (i != fd[1]))
- (void)close(i);
- }
-#if 0
- efd = open("/tmp/errlog", O_CREAT|O_APPEND|O_RDWR, 0666);
- if (dup2(efd,2) == -1) {
- exit(1);
- }
-#endif
- /* Dup the two file descriptors to stdin and stdout */
- if (dup2(fd[0],0) == -1) {
- exit(1);
- }
- if (dup2(fd[1],1) == -1) {
- exit(1);
- }
- /* Exec the child process */
- if (network_mode & NET_PPP_MODE)
- execl("/usr/lib/sa/sadc", "sadc", sadc_mflagp, sadc_ppp_modep, t_intervalp, n_samplesp, NULL);
- else
- execl("/usr/lib/sa/sadc", "sadc", t_intervalp, n_samplesp, NULL);
-
- perror("execlp sadc");
- exit(2); /* This call of exit(2) should never be reached... */
- }
- else
- { /* This is the parent */
- if (pid == -1) {
- fprintf(stderr, "sar: fork(2) failed, errno = (%d)\n",errno);
- exit(1);
- }
- close (fd[1]); /* parent does not write to the pipe */
- ifd = fd[0]; /* parent will read from the pipe */
- }
- }
- else
- {
- /* we're confused about source of input data - bail out */
- fprintf(stderr, "sar: no input file recognized\n");
- exit_usage();
- }
-
- /* start reading input data and format the output */
- (void)do_main_workloop();
- (void)exit_average();
- exit(0);
-}
-
-static void
-exit_usage()
-{
- fprintf(stderr, "\n%s\n\n", optionstring1_usage);
- fprintf(stderr, "%s\n", optionstring2_usage);
- exit(EXIT_FAILURE);
-}
-
-static void
-open_output_file(char *path)
-{
- if ((ofd = open(path, O_CREAT|O_APPEND|O_TRUNC|O_WRONLY, 0664)) == -1 )
- {
- /* failed to open path */
- fprintf(stderr, "sar: failed to open output file [%s]\n", path);
- exit_usage();
- }
-}
-
-
-static void
-open_input_file(char *path)
-{
- if ((ifd = open(path, O_RDONLY, 0)) == -1)
- {
- /* failed to open path */
- fprintf(stderr, "sar: failed to open input file [%d][%s]\n", ifd, path);
- exit_usage();
- }
-}
-
-static void
-read_record_hdr(hdr, writeflag)
- struct record_hdr *hdr;
- int writeflag;
-{
- errno = 0;
- int num = 0;
- int n = 0;
- size_t size = 0;
-
- size = sizeof(struct record_hdr);
-
- while (size)
- {
- num = read(ifd, &hdr[n], size);
- if (num > 0)
- {
- n += num;
- size -= num;
- }
- else if (num == 0)
- exit_average();
- else
- {
- fprintf(stderr, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno, (int)num, (int)size);
- exit(EXIT_FAILURE);
- }
- }
-
- if (oflag && writeflag)
- write_record_hdr(hdr);
-
- return;
-}
-
-static void
-read_record_data(buf, size, writeflag)
- char * buf;
- size_t size;
- int writeflag;
-{
- errno = 0;
- size_t num = 0;
- size_t n = 0;
-
- while (size)
- {
- num = read(ifd, &buf[n], size);
- if (num > 0)
- {
- n += num;
- size -= num;
- }
- else if (num == 0) /* EOF */
- exit_average();
- else
- {
- fprintf(stderr, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno, (int)num, (int)size);
- exit(EXIT_FAILURE);
- }
- }
-
- if (oflag && writeflag)
- write_record_data(buf, n);
-
- return;
-}
-
-static void
-write_record_hdr(hdr)
- struct record_hdr *hdr;
-{
- errno = 0;
- int num;
-
- if ((num = write(ofd, hdr, sizeof(struct record_hdr))) == -1)
- {
- fprintf(stderr, "sar: write_record_hdr failed, errno=%d\n", errno);
- exit(EXIT_FAILURE);
- }
- return;
-}
-
-static void
-write_record_data(char *buf, size_t nbytes)
-{
- errno = 0;
- int num;
- if ((num = write(ofd, buf, nbytes)) == -1)
- {
- fprintf(stderr, "sar: write_record_data failed, errno=%d\n", errno);
- exit(EXIT_FAILURE);
- }
- return;
-}
-
-/*
- * Convert a string of one of the forms
- * hh hh:mm hh:mm:ss
- * into the number of seconds.
- * exit on error
-*/
-
-static time_t
-convert_hms(string)
- char *string;
-{
- int hh = 0; /* hours */
- int mm = 0; /* minutes */
- int ss = 0; /* seconds */
- time_t seconds;
- time_t timestamp;
- struct tm *tm;
- int i;
-
- if (string == NULL || *string == '\0')
- goto convert_err;
-
- for (i=0; string[i] != '\0'; i++)
- {
- if ((!isdigit(string[i])) && (string[i] != ':'))
- {
- goto convert_err;
- }
- }
-
- if (sscanf(string, "%d:%d:%d", &hh, &mm, &ss) != 3)
- {
- if (sscanf(string, "%d:%d", &hh, &mm) != 2)
- {
- if (sscanf(string, "%d", &hh) != 1)
- {
- goto convert_err;
- }
- }
- }
-
- if (hh < 0 || hh >= HOURS_PER_DAY ||
- mm < 0 || mm >= MINS_PER_HOUR ||
- ss < 0 || ss > SECS_PER_MIN)
- {
- goto convert_err;
- }
-
- seconds = ((((hh * MINS_PER_HOUR) + mm) * SECS_PER_MIN) + ss);
- timestamp = time((time_t *)0);
- tm=localtime(×tamp);
- seconds -= tm->tm_gmtoff;
-
- return(seconds);
-
- convert_err:
- fprintf(stderr, "sar: time format usage is hh[:mm[:ss]]\n");
- exit_usage();
- return(0);
-}
-
-
-/*
- * Use ctime_r to convert a time value into
- * a 26-character string of the form:
- *
- * Thu Nov 24 18:22:48 1986\n\0
- */
-
-static char *
-get_hms_string(tdata, tbuf)
- time_t tdata;
- char *tbuf;
-{
- time_t t;
- char *p;
-
- t = tdata;
- ctime_r(&t, tbuf);
- p=&tbuf[11];
- tbuf[19] = 0;
-
- return(p);
-}
-
-
-/* sample set flags */
-#define INIT_SET 0
-#define PRINT_SET 1
-#define PRINT_AVG 2
-
-static void
-do_main_workloop()
-{
- struct record_hdr hdr;
- time_t cur_timestamp = 0; /* seconds - Coordinated Universal Time */
- time_t next_timestamp = 0; /* seconds - Coordinated Universal Time */
-
- if (!find_restart_header(&hdr))
- exit(1);
-
- cur_timestamp = hdr.rec_timestamp;
-
- /* convert sflag's start_time from 24 hour clock time to UTC seconds */
- if (start_time < (cur_timestamp % SECS_PER_DAY))
- start_time = cur_timestamp;
- else
- start_time += cur_timestamp - (cur_timestamp % SECS_PER_DAY);
-
- /* convert end_time, from 24 hour clock time to UTC seconds */
- if (end_time != 0)
- end_time += cur_timestamp - (cur_timestamp % SECS_PER_DAY);
-
-#if 0
- fprintf(stderr, "start = %ld, end = %ld, cur=%ld, [24hour - %ld]\n",
- start_time, end_time, cur_timestamp,(cur_timestamp % SECS_PER_DAY));
-#endif
-
- while (cur_timestamp < start_time)
- {
- bypass_sample_set(&hdr, cur_timestamp);
- cur_timestamp = hdr.rec_timestamp;
- }
-
- next_timestamp = cur_timestamp + iseconds;
- print_all_column_headings(cur_timestamp);
- read_sample_set(INIT_SET, cur_timestamp, &hdr);
- cur_timestamp = hdr.rec_timestamp;
-
- while ((end_time == 0) || (next_timestamp < end_time))
- {
- if (cur_timestamp < next_timestamp)
- {
- bypass_sample_set (&hdr, cur_timestamp);
- cur_timestamp = hdr.rec_timestamp;
- }
- else
- {
- /* need to know the seconds interval when printing averages */
- if (avg_interval == 0)
- {
- if (iseconds)
- avg_interval = iseconds;
- else
- avg_interval = cur_timestamp - next_timestamp;
- }
- next_timestamp = cur_timestamp + iseconds;
- read_sample_set(PRINT_SET, cur_timestamp, &hdr);
- cur_timestamp = hdr.rec_timestamp;
- }
- }
- exit_average();
-}
-
-
-/*
- * Find and fill in a restart header. We don't write
- * the binary data when looking for SAR_RESTART.
- * Return: 1 on success
- * 0 on failure
- */
-static int
-find_restart_header (ret_hdr)
- struct record_hdr *ret_hdr;
-{
- struct record_hdr hdr;
- int bufsize = 0;
- char *buf = NULL;
-
- errno = 0;
-
- restart_loop:
- read_record_hdr(&hdr, FALSE); /* exits on error */
-
- if (hdr.rec_type == SAR_RESTART)
- {
- *ret_hdr = hdr;
- if (oflag)
- write_record_hdr(&hdr); /* writes the RESTART record */
- if (buf)
- free(buf);
- return(1);
- }
-
- /*
- * not the record we want...
- * read past data and try again
- */
- if (hdr.rec_count)
- {
- if (fflag)
- { /* seek past data in the file */
- if ((lseek(ifd, (hdr.rec_count * hdr.rec_size), SEEK_CUR)) == -1)
- {
- /*exit on error */
- fprintf(stderr, "sar: lseek failed, errno=%d\n", errno);
- exit(EXIT_FAILURE);
- }
-
- }
- /* compute data size - malloc a new buf if it's not big enough */
- else
- {
- /* have to read from the pipe */
- if (bufsize < (hdr.rec_count * hdr.rec_size))
- {
- if (buf)
- free(buf);
- bufsize = hdr.rec_count * hdr.rec_size;
- if((buf = (char *)malloc(bufsize)) == NULL)
- {
- fprintf(stderr, "sar: malloc failed\n");
- return(0);
- }
- }
- /* exits on error */
- read_record_data(buf, (hdr.rec_count * hdr.rec_size), FALSE);
- }
- }
- goto restart_loop;
-}
-
-static void
-print_all_column_headings(timestamp)
- time_t timestamp;
-{
- char timebuf[26];
- char *timebufp;
-
- timebufp = get_hms_string (timestamp, timebuf);
-
- if (uflag) /* print cpu headers */
- print_column_heading(SAR_CPU, timebufp, 0);
-
- if (gflag) /* print page-out activity */
- print_column_heading(SAR_VMSTAT, timebufp, 0);
-
- if (pflag ) /* print page-in activity */
- print_column_heading(SAR_VMSTAT, timebufp, 1);
-
- if (dflag) /* print drive stats */
- print_column_heading(SAR_DRIVESTATS, timebufp, 0);
-
- if (nflag) /* print network stats */
- {
- if (network_mode & NET_DEV_MODE)
- print_column_heading(SAR_NETSTATS, timebufp, NET_DEV_MODE);
-
- if (network_mode & NET_EDEV_MODE)
- print_column_heading(SAR_NETSTATS, timebufp, NET_EDEV_MODE);
- }
-}
-
-
-/*
- * Find and fill in a timestamp header.
- * Write the binary data when looking for SAR_TIMESTAMP
- * Don't do anything with the data, just read past it.
- * Return: 1 on success
- * 0 on failure
- */
-static int
-bypass_sample_set (ret_hdr, timestamp)
- struct record_hdr *ret_hdr;
- time_t timestamp;
-{
- struct record_hdr hdr;
- int bufsize = 0;
- char *buf = NULL;
-
- bypass_loop:
- read_record_hdr(&hdr, TRUE); /* exits on error */
-
- if (hdr.rec_type == SAR_TIMESTAMP)
- {
- *ret_hdr = hdr;
- if (buf)
- free(buf);
- return(1);
- }
-
- /*
- * not the record we want...
- * read past data and try again
- */
- if (hdr.rec_count)
- {
- if (fflag && !oflag)
- {
- /*
- * we're reading from a file and we don't have to write the
- * binary data so seek past data in the file
- */
- errno = 0;
- if ((lseek(ifd, (hdr.rec_count * hdr.rec_size), SEEK_CUR)) == -1)
- {
- /*exit on error */
- fprintf(stderr, "sar: lseek failed, errno=%d\n", errno);
- exit(EXIT_FAILURE);
- }
- }
- else
- {
- /*
- * We end up here when reading from pipe.
- * malloc a new buffer if current is not big enough
- */
- if (bufsize < (hdr.rec_count * hdr.rec_size))
- {
- if (buf)
- free(buf);
- bufsize = hdr.rec_count * hdr.rec_size;
- if((buf = (char *)malloc(bufsize)) == NULL)
- {
- fprintf(stderr, "sar: malloc failed\n");
- exit(EXIT_FAILURE);
- }
- }
-
- /* exits on error */
- read_record_data(buf, (hdr.rec_count * hdr.rec_size), TRUE);
- }
- } /* end if hdr.rec_count */
- goto bypass_loop;
-}
-
-
-/*
- * INIT_SET: This initializes the first sample for each type.
- * PRINT_SET: This read, compute and print out sample data.
- */
-static void
-read_sample_set(flag, timestamp, ret_hdr)
- int flag;
- time_t timestamp;
- struct record_hdr *ret_hdr;
-{
- struct record_hdr hdr;
- char timebuf[26];
- char *timebufp;
- char *indent_string;
- char *indent_string_wide;
- char *indent_string_narrow;
- int sar_cpu = 0;
- int sar_vmstat=0;
- int sar_drivestats=0;
- int sar_drivepath=0;
- int sar_netstats = 0;
-
- indent_string_wide = " ";
- indent_string_narrow = " ";
- indent_string = indent_string_narrow;
-
- read_record_hdr(&hdr, TRUE);
-
- while (hdr.rec_type != SAR_TIMESTAMP)
- {
- switch (hdr.rec_type)
- {
- case SAR_CPU:
- sar_cpu = get_cpu_sample(flag, &hdr);
- break;
- case SAR_VMSTAT:
- sar_vmstat=get_vmstat_sample(flag, &hdr);
- break;
- case SAR_DRIVEPATH:
- sar_drivepath = get_drivepath_sample(flag, &hdr);
- if (sar_drivepath < 0)
- fprintf(stderr, "sar: drivepath sync code error %d\n", sar_drivepath);
- break;
- case SAR_DRIVESTATS:
- sar_drivestats = get_drivestats_sample(flag, &hdr);
- break;
- case SAR_NETSTATS:
- sar_netstats = get_netstats_sample(flag, &hdr);
- break;
- default:
- break;
- }
-
- read_record_hdr(&hdr, TRUE);
- }
-
- /* return the timestamp header */
- *ret_hdr = hdr;
-
- if (flag == PRINT_SET)
- {
- avg_counter++;
- timebufp = get_hms_string(timestamp, timebuf);
-
- if (uflag && sar_cpu)
- print_cpu_sample(timebufp);
-
- if((gflag || pflag) && sar_vmstat)
- print_vmstat_sample(timebufp);
-
- if (dflag && sar_drivestats)
- print_drivestats_sample(timebufp);
-
- if (nflag && sar_netstats)
- print_netstats_sample(timebufp);
- }
-}
-
-static void
-skip_data(bufsize)
- int bufsize;
-{
- char *buf = NULL;
-
- if (fflag)
- {
- /* seek past data in the file */
- if ((lseek(ifd, bufsize, SEEK_CUR) == -1))
- {
- /*exit on error */
- fprintf(stderr, "sar: lseek failed, errno=%d\n", errno);
- exit(EXIT_FAILURE);
- }
- }
- else
- {
- /* have to read from the pipe */
- if((buf = (char *)malloc(bufsize)) == NULL)
- {
- fprintf(stderr, "sar: malloc failed\n");
- exit(EXIT_FAILURE);
- }
- /* even though we skip this data, we still write it if necessary */
- read_record_data(buf, bufsize, TRUE);
- }
- if (buf)
- free(buf);
-
- return;
-}
-
-static int
-get_cpu_sample(flag, hdr)
- int flag;
- struct record_hdr *hdr;
-{
- int datasize;
-
- datasize = hdr->rec_count * hdr->rec_size;
-
- if (datasize != sizeof(host_cpu_load_info_data_t))
- {
- /* read past the data but don't do anything with it */
- skip_data(datasize);
- return(0);
- }
-
- read_record_data ((char *)&cur_cpuload, (int)sizeof(host_cpu_load_info_data_t), TRUE );
-
- if (flag == INIT_SET)
- {
- prev_cpuload = cur_cpuload;
- bzero(&avg_cpuload, sizeof(avg_cpuload));
- }
- return(1);
-}
-
-static void
-print_cpu_sample(timebufptr)
- char * timebufptr;
-{
-
- double time;
-
- time = 0.0;
- cur_cpuload.cpu_ticks[CPU_STATE_USER]
- -= prev_cpuload.cpu_ticks[CPU_STATE_USER];
-
- prev_cpuload.cpu_ticks[CPU_STATE_USER]
- += cur_cpuload.cpu_ticks[CPU_STATE_USER];
-
- time += cur_cpuload.cpu_ticks[CPU_STATE_USER];
-
- cur_cpuload.cpu_ticks[CPU_STATE_NICE]
- -= prev_cpuload.cpu_ticks[CPU_STATE_NICE];
-
- prev_cpuload.cpu_ticks[CPU_STATE_NICE]
- += cur_cpuload.cpu_ticks[CPU_STATE_NICE];
-
- time += cur_cpuload.cpu_ticks[CPU_STATE_NICE];
-
- cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
- -= prev_cpuload.cpu_ticks[CPU_STATE_SYSTEM];
-
- prev_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
- += cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM];
-
- time += cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM];
-
- cur_cpuload.cpu_ticks[CPU_STATE_IDLE]
- -= prev_cpuload.cpu_ticks[CPU_STATE_IDLE];
-
- prev_cpuload.cpu_ticks[CPU_STATE_IDLE]
- += cur_cpuload.cpu_ticks[CPU_STATE_IDLE];
-
- time += cur_cpuload.cpu_ticks[CPU_STATE_IDLE];
-
- avg_cpuload.cpu_ticks[CPU_STATE_USER] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_USER]
- / (time ? time : 1));
-
- avg_cpuload.cpu_ticks[CPU_STATE_NICE] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_NICE]
- / (time ? time : 1));
-
- avg_cpuload.cpu_ticks[CPU_STATE_SYSTEM] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
- / (time ? time : 1));
-
- avg_cpuload.cpu_ticks[CPU_STATE_IDLE] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_IDLE]
- / (time ? time : 1));
-
- if(flag_count > 1)
- print_column_heading(SAR_CPU, timebufptr, 0);
-
- fprintf(stdout, "%s%5.0f ", timebufptr,
- rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_USER]
- / (time ? time : 1)));
-
- fprintf(stdout, "%4.0f ",
- rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_NICE]
- / (time ? time : 1)));
-
- fprintf(stdout, "%4.0f ",
- rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
- / (time ? time : 1)));
-
- fprintf(stdout, "%4.0f\n",
- rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_IDLE]
- / (time ? time : 1)));
-}
-
-static int
-get_vmstat_sample(flag, hdr)
- int flag;
- struct record_hdr *hdr;
-{
- int datasize;
-
- datasize = hdr->rec_count * hdr->rec_size;
-
- if (datasize != sizeof(struct vm_statistics))
- {
- /* read past the data but don't do anything with it */
- skip_data(datasize);
- return(0);
- }
-
- read_record_data ((char *)&cur_vmstat, (int)sizeof(struct vm_statistics), TRUE );
-
- if (flag == INIT_SET)
- {
- prev_vmstat = cur_vmstat;
- bzero(&avg_vmstat, sizeof(avg_vmstat));
- }
- return(1);
-}
-
-
-static void
-print_vmstat_sample(char *timebufptr)
-{
-
- cur_vmstat.faults -= prev_vmstat.faults;
- prev_vmstat.faults += cur_vmstat.faults;
- avg_vmstat.faults += cur_vmstat.faults;
-
- cur_vmstat.cow_faults -= prev_vmstat.cow_faults;
- prev_vmstat.cow_faults += cur_vmstat.cow_faults;
- avg_vmstat.cow_faults += cur_vmstat.cow_faults;
-
- cur_vmstat.zero_fill_count -= prev_vmstat.zero_fill_count;
- prev_vmstat.zero_fill_count += cur_vmstat.zero_fill_count;
- avg_vmstat.zero_fill_count += cur_vmstat.zero_fill_count;
-
- cur_vmstat.reactivations -= prev_vmstat.reactivations;
- prev_vmstat.reactivations += cur_vmstat.reactivations;
- avg_vmstat.reactivations += cur_vmstat.reactivations;
-
- cur_vmstat.pageins -= prev_vmstat.pageins;
- prev_vmstat.pageins += cur_vmstat.pageins;
- avg_vmstat.pageins += cur_vmstat.pageins;
-
- cur_vmstat.pageouts -= prev_vmstat.pageouts;
- prev_vmstat.pageouts += cur_vmstat.pageouts;
- avg_vmstat.pageouts += cur_vmstat.pageouts;
-
-
- if (gflag)
- {
- if (flag_count > 1)
- print_column_heading(SAR_VMSTAT, timebufptr, 0);
- fprintf(stdout, "%s %8.1f \n", timebufptr, (float)((float)cur_vmstat.pageouts/avg_interval));
- }
-
- if (pflag)
- {
- if (flag_count > 1)
- print_column_heading(SAR_VMSTAT, timebufptr, 1);
- fprintf(stdout, "%s %8.1f %8.1f %8.1f\n", timebufptr,
- (float)((float)cur_vmstat.pageins / avg_interval),
- (float)((float)cur_vmstat.cow_faults/avg_interval),
- (float)((float)cur_vmstat.faults/avg_interval));
- }
- fflush(stdout);
-}
-
-static int
-get_drivestats_sample(flag, hdr)
- int flag;
- struct record_hdr *hdr;
-{
- struct drivestats *databuf;
- struct drivestats_report *dr;
- size_t datasize;
- int datacount;
- int index;
- int i;
-
- datasize = hdr->rec_count * hdr->rec_size;
- datacount = hdr->rec_count;
-
- if (hdr->rec_size != sizeof(struct drivestats))
- {
- /* something isn't right... read past the data but don't analyze it */
- skip_data(datasize);
- return(0);
- }
-
- /* malloc read buffer */
- if ((databuf = (struct drivestats *)malloc(datasize)) == NULL)
- {
- fprintf(stderr, "sar: malloc failed\n");
- exit (EXIT_FAILURE);
- }
-
- bzero(databuf, datasize);
-
- read_record_data ((char *)databuf, datasize, TRUE );
-
- /* clear all global current fields */
- for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
- {
- dr->present = 0;
- dr->cur_Reads = 0;
- dr->cur_BytesRead = 0;
- dr->cur_Writes = 0;
- dr->cur_BytesWritten = 0;
- dr->cur_LatentReadTime = 0;
- dr->cur_LatentWriteTime = 0;
- dr->cur_ReadErrors = 0;
- dr->cur_WriteErrors = 0;
- dr->cur_ReadRetries = 0;
- dr->cur_WriteRetries = 0;
- dr->cur_TotalReadTime = 0;
- dr->cur_TotalWriteTime=0;
- }
-
- /* By this point, we have read in a complete set of diskstats from the sadc
- * data collector.
- * The order of the drives in not guaranteed.
- * The global report structure is a linked list, but may need initialization
- * We need to traverse this list and transfer the current
- * read data. If a disk entry isn't found, then we need to allocate one
- * initilize it.
- */
- for (i=0; i< datacount; i++)
- {
- struct drivestats_report *dr_last = NULL;
-
- index = databuf[i].drivepath_id; /* use this as index into dp_table */
-
- /* find disk entry or allocate new one*/
- for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
- {
- dr_last = dr;
- if(index == dr->drivepath_id)
- break;
- }
-
- if (dr == NULL)
- {
- /* allocate new entry */
- if((dr = (struct drivestats_report *)malloc(sizeof(struct drivestats_report))) == NULL)
- {
- fprintf(stderr, "sar: malloc error\n");
- exit(EXIT_FAILURE);
- }
- bzero((char *)dr, sizeof(struct drivestats_report));
- dr->blocksize = databuf[i].blocksize;
- dr->drivepath_id = index;
- dr->next = NULL;
- dr->avg_count = 0;
-
- /* get the BSDName which should be in the table by now */
- if ((index < dp_count) && (dp_table[index].state != DPSTATE_UNINITIALIZED))
- strncpy(dr->name, dp_table[index].BSDName, MAXDRIVENAME+1);
- else
- strcpy(dr->name, "disk??");
-
- if (dr_head == NULL)
- {
- dr_head = dr;
- dr_head->next = NULL;
- }
- else
- {
- dr_last->next = (char *)dr;
- }
- } /* end if dr == NULL */
-
- dr->present = TRUE;
- dr->cur_Reads = databuf[i].Reads;
- dr->cur_BytesRead = databuf[i].BytesRead;
- dr->cur_Writes = databuf[i].Writes;
- dr->cur_BytesWritten = databuf[i].BytesWritten;
- dr->cur_LatentReadTime = databuf[i].LatentReadTime;
- dr->cur_LatentWriteTime = databuf[i].LatentWriteTime;
- dr->cur_ReadErrors = databuf[i].ReadErrors;
- dr->cur_WriteErrors = databuf[i].WriteErrors;
- dr->cur_ReadRetries = databuf[i].ReadRetries;
- dr->cur_WriteRetries = databuf[i].WriteRetries;
- dr->cur_TotalReadTime = databuf[i].TotalReadTime;
- dr->cur_TotalWriteTime=databuf[i].TotalWriteTime;
- } /* end for loop */
-
- /* Reinitialize the prev and avg fields when
- * This is a new disk
- * This is a changed disk - name change implies disk swapping
- * This disk is not present in this sample
- */
- for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
- {
- if (dr->drivepath_id >= dp_count)
- {
- /* something is amiss */
- continue;
- }
- else
- {
- index = dr->drivepath_id; /* use this as index into dp_table */
- }
-
- if ((flag == INIT_SET) ||
- (dp_table[index].state == DPSTATE_NEW) ||
- (dp_table[index].state == DPSTATE_CHANGED) ||
- (!dr->present))
- {
- /*
- * prev will be set to cur
- * activate the state in dp_table
- */
- if (dr->present)
- dp_table[index].state = DPSTATE_ACTIVE;
-
- init_drivestats(dr);
- }
- }
- return(1);
-}
-
-static void
-init_drivestats(struct drivestats_report *dr)
-{
- dr->avg_count = 0;
- dr->prev_Reads = dr->cur_Reads;
- dr->avg_Reads = 0;
- dr->prev_BytesRead = dr->cur_BytesRead;
- dr->avg_BytesRead = 0;
- dr->prev_Writes = dr->cur_Writes;
- dr->avg_Writes = 0;
- dr->prev_BytesWritten = dr->cur_BytesWritten;
- dr->avg_BytesWritten = 0;
- dr->prev_LatentReadTime = dr->cur_LatentReadTime;
- dr->avg_LatentReadTime = 0;
- dr->prev_LatentWriteTime = dr->cur_LatentWriteTime ;
- dr->avg_LatentWriteTime = 0;
- dr->prev_ReadErrors = dr->cur_ReadErrors ;
- dr->avg_ReadErrors = 0;
- dr->prev_WriteErrors = dr->cur_WriteErrors ;
- dr->avg_WriteErrors = 0;
- dr->prev_ReadRetries = dr->cur_ReadRetries ;
- dr->avg_ReadRetries = 0;
- dr->prev_WriteRetries = dr->cur_WriteRetries ;
- dr->avg_WriteRetries = 0;
- dr->prev_TotalReadTime = dr->cur_TotalReadTime ;
- dr->avg_TotalReadTime = 0;
- dr->prev_TotalWriteTime = dr->cur_TotalWriteTime ;
- dr->avg_TotalWriteTime = 0;
-}
-
-
-static void
-print_drivestats_sample(char *timebufptr)
-{
- struct drivestats_report *dr;
- long double transfers_per_second;
- long double kb_per_transfer, mb_per_second;
- u_int64_t interval_bytes, interval_transfers, interval_blocks;
- u_int64_t interval_time;
- long double blocks_per_second, ms_per_transaction;
-
- if (flag_count > 1)
- print_column_heading(SAR_DRIVESTATS, timebufptr, 0);
-
- for (dr=dr_head; dr; dr=(struct drivestats_report *)dr->next)
- {
- if(!dr->present)
- continue;
-
- /*
- * This sanity check is for drives that get removed and then
- * returned during the sampling sleep interval. If anything
- * looks out of sync, reinit and skip this entry. There is
- * no way to guard against this entirely.
- */
- if ((dr->cur_Reads < dr->prev_Reads) ||
- (dr->cur_BytesRead < dr->prev_BytesRead) ||
- (dr->cur_Writes < dr->prev_Writes) ||
- (dr->cur_BytesWritten < dr->prev_BytesWritten))
- {
- init_drivestats(dr);
- continue;
- }
-
- dr->avg_count++;
-
- dr->cur_Reads -= dr->prev_Reads;
- dr->prev_Reads += dr->cur_Reads;
- dr->avg_Reads += dr->cur_Reads;
-
- dr->cur_BytesRead -= dr->prev_BytesRead;
- dr->prev_BytesRead += dr->cur_BytesRead;
- dr->avg_BytesRead += dr->cur_BytesRead;
-
- dr->cur_Writes -= dr->prev_Writes ;
- dr->prev_Writes += dr->cur_Writes ;
- dr->avg_Writes += dr->cur_Writes ;
-
- dr->cur_BytesWritten -= dr->prev_BytesWritten ;
- dr->prev_BytesWritten += dr->cur_BytesWritten ;
- dr->avg_BytesWritten += dr->cur_BytesWritten ;
-
- dr->cur_LatentReadTime -= dr->prev_LatentReadTime ;
- dr->prev_LatentReadTime += dr->cur_LatentReadTime ;
- dr->avg_LatentReadTime += dr->cur_LatentReadTime ;
-
- dr->cur_LatentWriteTime -= dr->prev_LatentWriteTime ;
- dr->prev_LatentWriteTime += dr->cur_LatentWriteTime ;
- dr->avg_LatentWriteTime += dr->cur_LatentWriteTime ;
-
- dr->cur_ReadErrors -= dr->prev_ReadErrors ;
- dr->prev_ReadErrors += dr->cur_ReadErrors ;
- dr->avg_ReadErrors += dr->cur_ReadErrors ;
-
- dr->cur_WriteErrors -= dr->prev_WriteErrors ;
- dr->prev_WriteErrors += dr->cur_WriteErrors ;
- dr->avg_WriteErrors += dr->cur_WriteErrors ;
-
- dr->cur_ReadRetries -= dr->prev_ReadRetries ;
- dr->prev_ReadRetries += dr->cur_ReadRetries ;
- dr->avg_ReadRetries += dr->cur_ReadRetries ;
-
- dr->cur_WriteRetries -= dr->prev_WriteRetries ;
- dr->prev_WriteRetries += dr->cur_WriteRetries;
- dr->avg_WriteRetries += dr->cur_WriteRetries;
-
- dr->cur_TotalReadTime -= dr->prev_TotalReadTime ;
- dr->prev_TotalReadTime += dr->cur_TotalReadTime ;
- dr->avg_TotalReadTime += dr->cur_TotalReadTime ;
-
- dr->cur_TotalWriteTime -= dr->prev_TotalWriteTime ;
- dr->prev_TotalWriteTime += dr->cur_TotalWriteTime ;
- dr->avg_TotalWriteTime += dr->cur_TotalWriteTime ;
-
- /* I/O volume */
- interval_bytes = dr->cur_BytesRead + dr->cur_BytesWritten;
-
- /* I/O counts */
- interval_transfers = dr->cur_Reads + dr->cur_Writes;
-
- /* I/O time */
- interval_time = dr->cur_LatentReadTime + dr->cur_LatentWriteTime;
-
- interval_blocks = interval_bytes / dr->blocksize;
- blocks_per_second = interval_blocks / avg_interval;
- transfers_per_second = interval_transfers / avg_interval;
- mb_per_second = (interval_bytes / avg_interval) / (1024 *1024);
-
- kb_per_transfer = (interval_transfers > 0) ?
- ((long double)interval_bytes / interval_transfers)
- / 1024 : 0;
-
- /* times are in nanoseconds, convert to milliseconds */
- ms_per_transaction = (interval_transfers > 0) ?
- ((long double)interval_time / interval_transfers)
- / 1000 : 0;
-
- /* print device name */
- fprintf(stdout, "%s %-10s", timebufptr, dr->name);
-
- /* print transfers per second */
- fprintf(stdout, "%4.0Lf ", transfers_per_second);
-
- /* print blocks per second - in device blocksize */
- fprintf(stdout, "%4.0Lf\n", blocks_per_second);
- }
-}
-
-/*
- * Print averages before exiting.
- */
-static void
-exit_average()
-{
- int i;
-
- if (avg_counter <= 0 )
- exit(0);
-
- if (oflag)
- {
- if (ofd)
- close (ofd);
- ofd = 0;
- }
-
- if (uflag) /* print cpu averages */
- {
- if(flag_count > 1)
- print_column_heading(SAR_CPU, 0, 0);
-
- fprintf(stdout, "Average: %5d ",
- (int)avg_cpuload.cpu_ticks[CPU_STATE_USER]
- / (avg_counter ? avg_counter : 1));
-
- fprintf(stdout, "%4d ",
- (int)avg_cpuload.cpu_ticks[CPU_STATE_NICE]
- / (avg_counter ? avg_counter : 1));
-
- fprintf(stdout, "%4d ",
- (int)avg_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
- / (avg_counter ? avg_counter : 1));
-
- fprintf(stdout, "%4d \n",
- (int)avg_cpuload.cpu_ticks[CPU_STATE_IDLE]
- / (avg_counter ? avg_counter : 1));
-
- fflush(stdout);
- }
-
-
- if (gflag) /* print page-out averages */
- {
- if (flag_count > 1)
- print_column_heading(SAR_VMSTAT, 0, 0);
-
- fprintf(stdout, "Average: %8.1f\n",
- (float)((avg_vmstat.pageouts / (avg_counter ? avg_counter : 1)) / avg_interval));
- fflush(stdout);
- }
-
- if (pflag) /* print page-in averages */
- {
- if (flag_count > 1)
- print_column_heading(SAR_VMSTAT, 0, 1);
-
- fprintf(stdout, "Average: %8.1f %8.1f %8.1f\n",
- (float)(((float)avg_vmstat.pageins / (avg_counter ? avg_counter : 1)) / avg_interval),
- (float)(((float)avg_vmstat.cow_faults / (avg_counter ? avg_counter : 1)) / avg_interval),
- (float)(((float)avg_vmstat.faults / (avg_counter ? avg_counter : 1)) / avg_interval));
- fflush(stdout);
- }
-
- if (dflag) /* print drivestats averages */
- {
- struct drivestats_report *dr;
- long double transfers_per_second;
- long double kb_per_transfer, mb_per_second;
- u_int64_t total_bytes, total_transfers, total_blocks;
- u_int64_t total_time;
- long double blocks_per_second, ms_per_transaction;
- int msdig;
-
- if (flag_count > 1)
- print_column_heading(SAR_DRIVESTATS, 0, 0);
-
- for (dr=dr_head; dr; dr=(struct drivestats_report *)dr->next)
- {
- /* don't bother to print out averages for disks that were removed */
- if (!dr->present)
- continue;
-
- fprintf(stdout, " %s %s\n",
- dp_table[dr->drivepath_id].BSDName, dp_table[dr->drivepath_id].ioreg_path);
-
- /* I/O volume */
- total_bytes = dr->avg_BytesRead + dr->avg_BytesWritten;
-
- /* I/O counts */
- total_transfers = dr->avg_Reads + dr->avg_Writes;
-
- /* I/O time */
- total_time = dr->avg_LatentReadTime + dr->avg_LatentWriteTime;
-
- total_blocks = total_bytes / dr->blocksize;
- blocks_per_second = total_blocks / avg_interval;
- transfers_per_second = total_transfers / avg_interval;
- mb_per_second = (total_bytes / avg_interval) / (1024 *1024);
-
- kb_per_transfer = (total_transfers > 0) ?
- ((long double)total_bytes / total_transfers)
- / 1024 : 0;
-
- /* times are in nanoseconds, convert to milliseconds */
- ms_per_transaction = (total_transfers > 0) ?
- ((long double)total_time / total_transfers)
- / 1000 : 0;
- msdig = (ms_per_transaction < 100.0) ? 1 : 0;
- fprintf(stdout, "Average: %-10s %4.0Lf %4.0Lf\n",
- dr->name,
- (transfers_per_second / dr->avg_count),
- (blocks_per_second / dr->avg_count));
-
- fflush(stdout);
- }
- } /* end if dflag */
-
- if (nflag)
- {
- int avg_count;
-
- if (network_mode & NET_DEV_MODE)
- {
- if (flag_count > 1)
- print_column_heading(SAR_NETSTATS, 0, NET_DEV_MODE);
- for (i = 0; i < nr_count; i++)
- {
- if (!nr_table[i].valid)
- continue;
-
- if(nr_table[i].avg_count == 0)
- avg_count = 1;
- else
- avg_count = nr_table[i].avg_count;
-
- fprintf(stdout, "Average: %-8.8s", nr_table[i].tname_unit);
-
- fprintf (stdout, "%8llu ",
- ((nr_table[i].avg_ipackets / avg_count) / avg_interval));
-
- fprintf (stdout, "%10llu ",
- ((nr_table[i].avg_ibytes / avg_count) / avg_interval));
-
- fprintf (stdout, "%8llu ",
- ((nr_table[i].avg_opackets / avg_count) / avg_interval));
-
- fprintf (stdout, "%10llu\n",
- ((nr_table[i].avg_obytes / avg_count) / avg_interval));
-
- fflush(stdout);
- }
- }
-
- if (network_mode & NET_EDEV_MODE)
- {
-
- if(flag_count > 1)
- print_column_heading(SAR_NETSTATS, 0, NET_EDEV_MODE);
-
- for (i = 0; i < nr_count; i++)
- {
- if (!nr_table[i].valid)
- continue;
-
- if(nr_table[i].avg_count == 0)
- avg_count = 1;
- else
- avg_count = nr_table[i].avg_count;
-
- fprintf(stdout, "Average: %-8.8s ", nr_table[i].tname_unit);
-
- fprintf (stdout, "%7llu ",
- ((nr_table[i].avg_ierrors / avg_count) / avg_interval));
-
- fprintf (stdout, "%7llu ",
- ((nr_table[i].avg_oerrors / avg_count) / avg_interval));
-
- fprintf (stdout, "%5llu ",
- ((nr_table[i].avg_collisions / avg_count) / avg_interval));
-
- fprintf (stdout, " %5llu\n",
- ((nr_table[i].avg_drops / avg_count) / avg_interval));
-
- fflush(stdout);
- }
- }
-
- } /* end if nflag */
- exit(0);
-}
-
-
-/*
- * Return < 0 failure, debugging purposes only
- * Return = 0 data skipped
- * Return > 0 success
- */
-
-static int
-get_drivepath_sample(flag, hdr)
- int flag;
- struct record_hdr *hdr;
-{
- size_t datasize;
- struct drivepath dp;
- struct drivestats_report *dr;
- int i, n;
-
- datasize = hdr->rec_count * hdr->rec_size;
-
- if (datasize != sizeof(struct drivepath))
- {
- /* read past the data but don't do anything with it */
- skip_data(datasize);
- return(0);
- }
-
- read_record_data ((char *)&dp, (int)sizeof(struct drivepath), TRUE );
-
- /*
- * If state is new -- put a new entry in the dp_table.
- * If state is changed -- traverse the drivestats_report table
- * and copy new name.
- */
- if (dp.state == DPSTATE_NEW)
- {
-
- if (dp_table == NULL)
- {
- if (dp.drivepath_id != 0)
- return(-1);
- /* First setup of internal drivepath table */
- dp_table = (struct drivepath *)malloc(sizeof(struct drivepath));
- if (dp_table == NULL)
- return(-2);
- dp_count = 1;
- }
-
- if (dflag)
- fprintf(stdout, "New Disk: [%s] %s\n", dp.BSDName, dp.ioreg_path);
-
- /* traverse table and find next uninitialized entry */
- for (i = 0; i< dp_count; i++)
- {
- if (dp_table[i].state == DPSTATE_UNINITIALIZED)
- {
- if (dp.drivepath_id != i)
- {
- /* the table is out of sync - this should not happen */
- return (-3);
- }
- dp_table[i] = dp;
- return(1);
- }
- }
- /*
- * If we get here, we've run out of table entries.
- * Double the size of the table, then assign the next entry.
- */
- if (dp.drivepath_id != i)
- {
- /* the table is out of sync - this should not happen */
- return (-4);
- }
- n = dp_count * 2;
- dp_table = (struct drivepath *)realloc(dp_table, n * sizeof(struct drivepath));
- bzero(&dp_table[dp_count], dp_count * sizeof(struct drivepath));
- dp_table[dp_count] = dp;
- dp_count = n;
- return(1);
-
- }
- else if (dp.state == DPSTATE_CHANGED)
- {
-
- /* Update the name in the table */
- if ((dp.drivepath_id < dp_count) && (dp_table[dp.drivepath_id].state != DPSTATE_UNINITIALIZED))
- {
- if (strcmp(dp_table[dp.drivepath_id].ioreg_path, dp.ioreg_path) != 0)
- {
- /* something is amiss */
- return (-5);
- }
- else
- {
- if (dflag)
- {
- fprintf(stdout, "Change: [%s] %s\n", dp.BSDName,
- dp_table[dp.drivepath_id].ioreg_path);
- }
- strcpy(dp_table[dp.drivepath_id].BSDName, dp.BSDName);
-
- for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
- {
- if (dr->drivepath_id == dp.drivepath_id)
- strcpy(dr->name, dp.BSDName);
- }
- return(1);
- }
- }
- else
- return(-6);
- }
- return(-7);
-}
-
-/*
- * Bytes and packet counts are used to track
- * counter wraps. So, don't enforce the
- * NET_DEV_MODE or NET_EDEV_MODE in here.
- * Maintain all the stats.
- */
-static void
-set_cur_netstats(struct netstats_report *nr, struct netstats *ns)
-{
-
- nr->cur_ipackets = ns->net_ipackets;
- nr->cur_ibytes = ns->net_ibytes;
- nr->cur_opackets = ns->net_opackets;
- nr->cur_obytes = ns->net_obytes;
-
- nr->cur_ierrors = ns->net_ierrors;
- nr->cur_oerrors = ns->net_oerrors;
- nr->cur_collisions = ns->net_collisions;
- nr->cur_drops = ns->net_drops;
-
- nr->cur_imcasts = ns->net_imcasts;
- nr->cur_omcasts = ns->net_omcasts;
-
-}
-
-static void
-init_prev_netstats(struct netstats_report *nr)
-{
- nr->avg_count = 0;
- nr->valid = 1;
- nr->present = 1;
-
- nr->prev_ipackets = nr->cur_ipackets;
- nr->avg_ipackets = 0;
- nr->prev_ibytes = nr->cur_ibytes;
- nr->avg_ibytes = 0;
- nr->prev_opackets = nr->cur_opackets;
- nr->avg_opackets = 0;
- nr->prev_obytes = nr->cur_obytes;
- nr->avg_obytes = 0;
-
- nr->prev_ierrors = nr->cur_ierrors;
- nr->avg_ierrors = 0;
- nr->prev_oerrors = nr->cur_oerrors ;
- nr->avg_oerrors = 0;
- nr->prev_collisions = nr->cur_collisions ;
- nr->avg_collisions = 0;
- nr->prev_drops = nr->cur_drops ;
- nr->avg_drops = 0;
-
- /* track these, but never displayed */
- nr->prev_imcasts = nr->cur_imcasts;
- nr->avg_imcasts = 0;
- nr->prev_omcasts = nr->cur_omcasts;
- nr->avg_omcasts = 0;
-}
-
-/*
- * Success : 1
- * Failure : 0
- */
-static int
-get_netstats_sample(flag, hdr)
- int flag;
- struct record_hdr *hdr;
-{
- struct netstats *databuf = NULL;
- size_t datasize;
- int datacount;
- int i, j;
-
- datasize = hdr->rec_count * hdr->rec_size;
- datacount = hdr->rec_count;
-
- if (hdr->rec_size != sizeof(struct netstats))
- {
- /* something isn't right... read past the data but don't analyze it */
- skip_data(datasize);
- return(0);
- }
-
- /* malloc new or bigger read buffer */
- if((netstat_readbuf == NULL) || (netstat_readbuf_size < datasize))
- {
- if (netstat_readbuf)
- free (netstat_readbuf);
-
- if ((netstat_readbuf = (struct netstats *)malloc(datasize)) == NULL)
- {
- fprintf(stderr, "sar: malloc failed\n");
- exit (EXIT_FAILURE);
- }
- netstat_readbuf_size = datasize;
- }
-
- bzero(netstat_readbuf, netstat_readbuf_size);
- databuf = netstat_readbuf;
-
- read_record_data ((char *)databuf, datasize, TRUE );
-
- if (nr_table == NULL)
- {
- /* initial internal table setup */
- nr_table = (struct netstats_report *)malloc(datacount * sizeof(struct netstats_report));
- nr_count = datacount;
- bzero(nr_table, (datacount * sizeof(struct netstats_report)));
-
- /* on first init, this is faster than finding our way to NEW_ENTRY */
- for (i = 0; i < datacount; i++)
- {
- if (!(network_mode & NET_PPP_MODE))
- {
- if (!strncmp(databuf[i].tname_unit, "ppp", 3))
- continue; /*
- * Skip ppp interfaces.
- * ie don't even put them in this internal table.
- */
- }
- strncpy(nr_table[i].tname_unit, databuf[i].tname_unit, MAX_TNAME_UNIT_SIZE);
- nr_table[i].tname_unit[MAX_TNAME_UNIT_SIZE] = '\0';
- set_cur_netstats(&nr_table[i], &databuf[i]);
- init_prev_netstats(&nr_table[i]);
- }
- return(1);
- }
-
- /*
- * clear all the present flags.
- * As we traverse the current sample set
- * and update the internal table, the flag
- * is reset.
- */
- for (i = 0; i < nr_count; i++)
- {
- nr_table[i].present = 0;
- }
-
- /*
- * Find and update table entries.
- * Init new entries.
- */
- for (i=0; i<datacount; i++)
- {
- int found;
- char *name;
- int nr_index;
- int n;
-
- name = databuf[i].tname_unit;
- found = 0;
-
- if (!(network_mode & NET_PPP_MODE))
- {
- if (!strncmp(name, "ppp", 3))
- continue; /* skip ppp interfaces */
- }
-
- /* Find the matching entry using the interface name */
- for (j=0; j < nr_count && !found; j++)
- {
- if (nr_table[j].valid)
- {
- if(!strcmp(nr_table[j].tname_unit, name))
- {
- found = 1;
- nr_table[j].present = 1;
- set_cur_netstats(&nr_table[j], &databuf[i]);
- }
- }
- } /* end for */
-
- if (!found) /* this is a new entry */
- {
- /* Find an invalid entry in the table and init it */
- for (j=0; j < nr_count; j++)
- {
- if (!nr_table[j].valid)
- {
- nr_index = j;
- goto NEW_ENTRY;
- }
- }
-
- /* we ran out of entries... grow the table */
- n = nr_count * 2;
- nr_table = (struct netstats_report *)realloc(nr_table, n * sizeof(struct netstats_report));
- bzero(&nr_table[nr_count], nr_count * sizeof (struct netstats_report));
- nr_index = nr_count;
- nr_count = n;
-
- NEW_ENTRY:
- strncpy(nr_table[nr_index].tname_unit, databuf[i].tname_unit, MAX_TNAME_UNIT_SIZE);
- nr_table[nr_index].tname_unit[MAX_TNAME_UNIT_SIZE] = '\0';
- set_cur_netstats(&nr_table[nr_index], &databuf[i]);
- init_prev_netstats(&nr_table[nr_index]);
- }
-
- } /* end for */
-
- /*
- * Traverse the internal table. Any valid entry that wasn't
- * present in this sample is cleared for reuse.
- */
- for (i = 0; i < nr_count; i++)
- {
- if (nr_table[i].valid)
- {
- if (nr_table[i].present == 0)
- bzero(&nr_table[i], sizeof(struct netstats_report));
- }
- }
- return (1);
-}
-
-static void
-print_netstats_sample(char *timebufptr)
-{
- int i;
-
- for (i=0; i < nr_count; i++)
- {
- if (!nr_table[i].valid)
- continue;
-
- /*
- * This is where we attempt to handle counters that
- * might wrap ... the kernel netstats are only 32 bits.
- *
- * Interfaces may go away and then return within the
- * sampling period. This can't be detected and it
- * may look like a counter wrap. An interface generation
- * counter will help... but isn't implemented at this time.
- */
-
- /*
- * The ppp interfaces are very likely to come and go during
- * a sampling period. During the normal life of a ppp interface,
- * it's less likely that the packet counter will wrap, so if
- * it appears to have done so, is probably because the
- * interface unit number has been reused.
- * We reinitialize that interface in that case.
- */
- if (network_mode & NET_PPP_MODE)
- {
- /*
- * ppp interfaces won't even make it into this table
- * when NET_PPP_MODE isn't set
- */
- if (!strncmp(nr_table[i].tname_unit, "ppp", 3))
- {
- /*
- * Both ipackets and opackets have to be less
- * than the previous counter to cause us to reinit.
- */
-
- if ((nr_table[i].cur_ipackets < nr_table[i].prev_ipackets)
- && (nr_table[i].cur_opackets < nr_table[i].prev_opackets))
- {
- init_prev_netstats(&nr_table[i]);
- continue;
- }
- }
- }
-
- nr_table[i].avg_count ++;
-
-#ifdef IFNET_32_BIT_COUNTERS
- while (nr_table[i].cur_ipackets < nr_table[i].prev_ipackets)
- nr_table[i].cur_ipackets += 0x100000000LL;
-#endif /* IFNET_32_BIT_COUNTERS */
- nr_table[i].cur_ipackets -= nr_table[i].prev_ipackets;
- nr_table[i].prev_ipackets += nr_table[i].cur_ipackets;
- nr_table[i].avg_ipackets += nr_table[i].cur_ipackets;
-
-
-#ifdef IFNET_32_BIT_COUNTERS
- while (nr_table[i].cur_ibytes < nr_table[i].prev_ibytes)
- nr_table[i].cur_ibytes += 0x100000000LL;
-#endif /* IFNET_32_BIT_COUNTERS */
- nr_table[i].cur_ibytes -= nr_table[i].prev_ibytes;
- nr_table[i].prev_ibytes += nr_table[i].cur_ibytes;
- nr_table[i].avg_ibytes += nr_table[i].cur_ibytes;
-
-
-#ifdef IFNET_32_BIT_COUNTERS
- while (nr_table[i].cur_opackets < nr_table[i].prev_opackets)
- nr_table[i].cur_opackets += 0x100000000LL;
-#endif /* IFNET_32_BIT_COUNTERS */
- nr_table[i].cur_opackets -= nr_table[i].prev_opackets;
- nr_table[i].prev_opackets += nr_table[i].cur_opackets;
- nr_table[i].avg_opackets += nr_table[i].cur_opackets;
-
-#ifdef IFNET_32_BIT_COUNTERS
- while (nr_table[i].cur_obytes < nr_table[i].prev_obytes)
- nr_table[i].cur_obytes += 0x100000000LL;
-#endif /* IFNET_32_BIT_COUNTERS */
- nr_table[i].cur_obytes -= nr_table[i].prev_obytes;
- nr_table[i].prev_obytes += nr_table[i].cur_obytes;
- nr_table[i].avg_obytes += nr_table[i].cur_obytes;
-
-
-#ifdef IFNET_32_BIT_COUNTERS
- while (nr_table[i].cur_ierrors < nr_table[i].prev_ierrors)
- nr_table[i].cur_ierrors += 0x100000000LL;
-#endif /* IFNET_32_BIT_COUNTERS */
- nr_table[i].cur_ierrors -= nr_table[i].prev_ierrors;
- nr_table[i].prev_ierrors += nr_table[i].cur_ierrors;
- nr_table[i].avg_ierrors += nr_table[i].cur_ierrors;
-
-#ifdef IFNET_32_BIT_COUNTERS
- while (nr_table[i].cur_oerrors < nr_table[i].prev_oerrors)
- nr_table[i].cur_oerrors += 0x100000000LL;
-#endif /* IFNET_32_BIT_COUNTERS */
- nr_table[i].cur_oerrors -= nr_table[i].prev_oerrors;
- nr_table[i].prev_oerrors += nr_table[i].cur_oerrors;
- nr_table[i].avg_oerrors += nr_table[i].cur_oerrors;
-
-#ifdef IFNET_32_BIT_COUNTERS
- while (nr_table[i].cur_collisions < nr_table[i].prev_collisions)
- nr_table[i].cur_collisions += 0x100000000LL;
-#endif /* IFNET_32_BIT_COUNTERS */
- nr_table[i].cur_collisions -= nr_table[i].prev_collisions;
- nr_table[i].prev_collisions += nr_table[i].cur_collisions;
- nr_table[i].avg_collisions += nr_table[i].cur_collisions;
-
-#ifdef IFNET_32_BIT_COUNTERS
- while (nr_table[i].cur_drops < nr_table[i].prev_drops)
- nr_table[i].cur_drops += 0x100000000LL;
-#endif /* IFNET_32_BIT_COUNTERS */
- nr_table[i].cur_drops -= nr_table[i].prev_drops;
- nr_table[i].prev_drops += nr_table[i].cur_drops;
- nr_table[i].avg_drops += nr_table[i].cur_drops;
-
-
-#ifdef IFNET_32_BIT_COUNTERS
- while (nr_table[i].cur_imcasts < nr_table[i].prev_imcasts)
- nr_table[i].cur_imcasts += 0x100000000LL;
-#endif /* IFNET_32_BIT_COUNTERS */
- nr_table[i].cur_imcasts -= nr_table[i].prev_imcasts;
- nr_table[i].prev_imcasts += nr_table[i].cur_imcasts;
- nr_table[i].avg_imcasts += nr_table[i].cur_imcasts;
-
-#ifdef IFNET_32_BIT_COUNTERS
- while (nr_table[i].cur_omcasts < nr_table[i].prev_omcasts)
- nr_table[i].cur_omcasts += 0x100000000LL;
-#endif /* IFNET_32_BIT_COUNTERS */
- nr_table[i].cur_omcasts -= nr_table[i].prev_omcasts;
- nr_table[i].prev_omcasts += nr_table[i].cur_omcasts;
- nr_table[i].avg_omcasts += nr_table[i].cur_omcasts;
- }
-
-
- if (!(flag_count > 1))
- fprintf(stdout, "\n");
-
- if (network_mode & NET_DEV_MODE)
- {
- if (flag_count > 1)
- print_column_heading(SAR_NETSTATS, timebufptr, NET_DEV_MODE);
-
- for (i=0; i < nr_count; i++)
- {
- if (!nr_table[i].valid)
- continue;
-
- if (!(network_mode & NET_PPP_MODE))
- {
- if (!strncmp(nr_table[i].tname_unit, "ppp", 3))
- {
- continue; /* skip any ppp interfaces */
- }
- }
-
- /* print the interface name */
- fprintf(stdout, "%s %-8.8s", timebufptr, nr_table[i].tname_unit);
-
- fprintf (stdout, "%8llu ",
- (nr_table[i].cur_ipackets / avg_interval));
-
- fprintf (stdout, "%10llu ",
- (nr_table[i].cur_ibytes / avg_interval));
-
- fprintf (stdout, "%8llu ",
- (nr_table[i].cur_opackets / avg_interval));
-
- fprintf (stdout, "%10llu\n",
- (nr_table[i].cur_obytes / avg_interval));
- }
- }
-
-
- if (network_mode & NET_EDEV_MODE)
- {
- if(flag_count > 1)
- {
- print_column_heading(SAR_NETSTATS, timebufptr, NET_EDEV_MODE);
- }
-
- for (i=0; i < nr_count; i++)
- {
- if (!nr_table[i].valid)
- continue;
-
- if (!(network_mode & NET_PPP_MODE))
- {
- if (!strncmp(nr_table[i].tname_unit, "ppp", 3))
- {
- continue; /* skip any ppp interfaces */
- }
- }
-
- /* print the interface name */
- fprintf(stdout, "%s %-8.8s ", timebufptr, nr_table[i].tname_unit);
-
- fprintf (stdout, "%7llu ",
- (nr_table[i].cur_ierrors / avg_interval));
-
- fprintf (stdout, "%7llu ",
- (nr_table[i].cur_oerrors / avg_interval));
-
- fprintf (stdout, "%5llu ",
- (nr_table[i].cur_collisions / avg_interval));
-
- fprintf (stdout, " %5llu\n",
- (nr_table[i].cur_drops / avg_interval));
- }
- fflush(stdout);
- }
-}
-
-static void
-print_column_heading(int type, char *timebufptr, int mode)
-{
- char *p;
-
- p = timebufptr;
-
- if (p == NULL)
- p = "Average:";
-
- if (!(flag_count > 1))
- fprintf(stdout, "\n");
-
- switch (type)
- {
- case SAR_CPU:
- fprintf (stdout, "\n%s %%usr %%nice %%sys %%idle\n", p);
- break;
-
- case SAR_VMSTAT:
- if (mode == 0) /* gflag */
- fprintf(stdout, "\n%s pgout/s\n", p);
- else if (mode == 1) /* pflag */
- fprintf(stdout, "\n%s pgin/s pflt/s vflt/s\n", p);
- break;
- case SAR_DRIVESTATS:
- fprintf(stdout, "\n%s device r+w/s blks/s\n", p);
- break;
- case SAR_NETSTATS:
- if (mode == NET_DEV_MODE)
- {
- fprintf(stdout, "\n%s %-8.8s %8.8s %10.10s %8.8s %10.10s\n", p,
- " IFACE", "Ipkts/s", "Ibytes/s", "Opkts/s", "Obytes/s");
- }
- else if (mode == NET_EDEV_MODE)
- {
- fprintf(stdout, "\n%s %-8.8s %7.7s %7.7s %5s %s\n", p,
- " IFACE", "Ierrs/s", "Oerrs/s", "Coll/s", "Drop/s");
- }
- break;
- default:
- break;
- }
-}
-