1/* Modified by Broadcom Corp. Portions Copyright (c) Broadcom Corp, 2010. */
2// old: "Copyright 1994 by Henry Ware <al172@yfn.ysu.edu>. Copyleft same year."
3// most code copyright 2002 Albert Cahalan
4//
5// 27/05/2003 (Fabian Frederick) : Add unit conversion + interface
6//               	 Export proc/stat access to libproc
7//			 Adapt vmstat helpfile
8// 31/05/2003 (Fabian) : Add diskstat support (/libproc)
9// June 2003 (Fabian) : -S <x> -s & -s -S <x> patch
10// June 2003 (Fabian) : -Adding diskstat against 3.1.9, slabinfo
11//			 -patching 'header' in disk & slab
12// July 2003 (Fabian) : -Adding disk partition output
13//			-Adding disk table
14//			-Syncing help / usage
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <ctype.h>
19#include <string.h>
20#include <assert.h>
21#include <fcntl.h>
22#include <limits.h>
23#include <termios.h>
24#include <unistd.h>
25#include <sys/types.h>
26#include <sys/ioctl.h>
27#include <sys/dir.h>
28#include <dirent.h>
29
30#include "proc/sysinfo.h"
31#include "proc/version.h"
32
33static unsigned long dataUnit=1024;
34static char szDataUnit [16];
35#define UNIT_B        1
36#define UNIT_k        1000
37#define UNIT_K        1024
38#define UNIT_m        1000000
39#define UNIT_M        1048576
40
41#define VMSTAT        0
42#define DISKSTAT      0x00000001
43#define VMSUMSTAT     0x00000002
44#define SLABSTAT      0x00000004
45#define PARTITIONSTAT 0x00000008
46#define DISKSUMSTAT   0x00000010
47#define ITLBSTAT      0x00000020
48#define DTLBSTAT      0x00000040
49#define CPUCACHESTAT  0x00000080
50
51static int statMode=VMSTAT;
52
53#define FALSE 0
54#define TRUE 1
55
56static int a_option; /* "-a" means "show active/inactive" */
57
58static unsigned sleep_time = 1;
59static unsigned long num_updates;
60
61static unsigned int height;   // window height
62static unsigned int moreheaders=TRUE;
63
64
65/////////////////////////////////////////////////////////////////////////
66
67static void usage(void) NORETURN;
68static void usage(void) {
69  fprintf(stderr,"usage: vmstat [-V] [-n] [delay [count]]\n");
70  fprintf(stderr,"              -V prints version.\n");
71  fprintf(stderr,"              -n causes the headers not to be reprinted regularly.\n");
72  fprintf(stderr,"              -a print inactive/active page stats.\n");
73  fprintf(stderr,"              -d prints disk statistics\n");
74  fprintf(stderr,"              -D prints disk table\n");
75  fprintf(stderr,"              -p prints disk partition statistics\n");
76  fprintf(stderr,"              -s prints vm table\n");
77  fprintf(stderr,"              -m prints slabinfo\n");
78  fprintf(stderr,"              -S unit size\n");
79  fprintf(stderr,"              -I ITLB stats\n");
80  fprintf(stderr,"              -P DTLB stats\n");
81  fprintf(stderr,"              -C I/D cache stats\n");
82  fprintf(stderr,"              delay is the delay between updates in seconds. \n");
83  fprintf(stderr,"              unit size k:1000 K:1024 m:1000000 M:1048576 (default is K)\n");
84  fprintf(stderr,"              count is the number of updates.\n");
85  exit(EXIT_FAILURE);
86}
87
88/////////////////////////////////////////////////////////////////////////////
89
90
91////////////////////////////////////////////////////////////////////////////
92
93static void new_header(void){
94  printf("procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----");
95  if (statMode & ITLBSTAT) {
96    printf(" -----------itlb------------");
97  } else if(statMode & DTLBSTAT) {
98    printf(" -------dtlb--------");
99  } else if (statMode & CPUCACHESTAT) {
100    printf(" ------------i/d cache-------------");
101  }
102  printf("\n");
103
104  printf(
105    "%2s %2s %6s %6s %6s %6s %4s %4s %5s %5s %4s %4s %2s %2s %2s %2s",
106    "r","b",
107    "swpd", "free", a_option?"inact":"buff", a_option?"active":"cache",
108    "si","so",
109    "bi","bo",
110    "in","cs",
111    "us","sy","id","wa"
112  );
113
114  if (statMode & ITLBSTAT) {
115    printf(" %6s %6s %6s", "ia", "im", "jm");
116  } else if(statMode & DTLBSTAT) {
117    printf(" %6s %6s", "ja", "jm");
118  } else if (statMode & CPUCACHESTAT) {
119    printf(" %6s %6s %6s %6s", "ia", "im", "dw", "dm");
120  }
121
122  printf("\n");
123}
124
125////////////////////////////////////////////////////////////////////////////
126
127static unsigned long unitConvert(unsigned int size){
128 float cvSize;
129 cvSize=(float)size/dataUnit*((statMode==SLABSTAT)?1:1024);
130 return ((unsigned long) cvSize);
131}
132
133////////////////////////////////////////////////////////////////////////////
134
135static void new_format(int mode) {
136  const char format[]="%2u %2u %6lu %6lu %6lu %6lu %4u %4u %5u %5u %4u %4u %2u %2u %2u %2u";
137  unsigned int tog=0; /* toggle switch for cleaner code */
138  unsigned int i;
139  unsigned int hz = Hertz;
140  unsigned int running,blocked,dummy_1,dummy_2;
141  jiff cpu_use[2], cpu_nic[2], cpu_sys[2], cpu_idl[2], cpu_iow[2], cpu_xxx[2], cpu_yyy[2], cpu_zzz[2];
142  jiff duse, dsys, didl, diow, dstl, Div, divo2;
143  unsigned long itlb_access[2], itlb_miss[2], ijtlb_miss[2];
144  unsigned long itlba, itlbm, ijtlbm;
145  unsigned long djtlb_access[2], djtlb_miss[2];
146  unsigned long djtlba, djtlbm;
147  unsigned long icache_access[2], icache_miss[2], dcache_wb[2], dcache_miss[2];
148  unsigned long icachea, icachem, dcachewb, dcachem;
149  unsigned long pgpgin[2], pgpgout[2], pswpin[2], pswpout[2];
150  unsigned int intr[2], ctxt[2];
151  unsigned int sleep_half;
152  unsigned long kb_per_page = sysconf(_SC_PAGESIZE) / 1024ul;
153  int debt = 0;  // handle idle ticks running backwards
154
155  sleep_half=(sleep_time/2);
156  new_header();
157  meminfo();
158
159  getstat(cpu_use,cpu_nic,cpu_sys,cpu_idl,cpu_iow,cpu_xxx,cpu_yyy,cpu_zzz,
160	  pgpgin,pgpgout,pswpin,pswpout,
161	  intr,ctxt,
162	  &running,&blocked,
163	  &dummy_1, &dummy_2);
164
165  duse= *cpu_use + *cpu_nic;
166  dsys= *cpu_sys + *cpu_xxx + *cpu_yyy;
167  didl= *cpu_idl;
168  diow= *cpu_iow;
169  dstl= *cpu_zzz;
170  Div= duse+dsys+didl+diow+dstl;
171  divo2= Div/2UL;
172  printf(format,
173	 running, blocked,
174	 unitConvert(kb_swap_used), unitConvert(kb_main_free),
175	 unitConvert(a_option?kb_inactive:kb_main_buffers),
176	 unitConvert(a_option?kb_active:kb_main_cached),
177	 (unsigned)( (*pswpin  * unitConvert(kb_per_page) * hz + divo2) / Div ),
178	 (unsigned)( (*pswpout * unitConvert(kb_per_page) * hz + divo2) / Div ),
179	 (unsigned)( (*pgpgin                * hz + divo2) / Div ),
180	 (unsigned)( (*pgpgout               * hz + divo2) / Div ),
181	 (unsigned)( (*intr                  * hz + divo2) / Div ),
182	 (unsigned)( (*ctxt                  * hz + divo2) / Div ),
183	 (unsigned)( (100*duse                    + divo2) / Div ),
184	 (unsigned)( (100*dsys                    + divo2) / Div ),
185	 (unsigned)( (100*didl                    + divo2) / Div ),
186	 (unsigned)( (100*diow                    + divo2) / Div ) /* ,
187	 (unsigned)( (100*dstl                    + divo2) / Div ) */
188  );
189
190  if (mode & ITLBSTAT) {
191	const char format[] = " %6lu %6lu %6lu";
192
193	getitlbstat(itlb_access, itlb_miss, ijtlb_miss);
194
195	printf(format, *itlb_access, *itlb_miss, *ijtlb_miss);
196  } else if (mode & DTLBSTAT) {
197	const char format[] = " %6lu %6lu";
198
199	getdjtlbstat(djtlb_access, djtlb_miss);
200
201	printf(format, *djtlb_access, *djtlb_miss);
202  } else if (mode & CPUCACHESTAT) {
203	const char format[] = " %6lu %6lu %6lu %6lu";
204
205	getcpucachestat(icache_access, icache_miss, dcache_wb, dcache_miss);
206
207	printf(format, *icache_access, *icache_miss, *dcache_wb, *dcache_miss);
208  }
209
210  printf("\n");
211
212  for(i=1;i<num_updates;i++) { /* \\\\\\\\\\\\\\\\\\\\ main loop ////////////////// */
213    sleep(sleep_time);
214    if (moreheaders && ((i%height)==0)) new_header();
215    tog= !tog;
216
217    meminfo();
218
219    getstat(cpu_use+tog,cpu_nic+tog,cpu_sys+tog,cpu_idl+tog,cpu_iow+tog,cpu_xxx+tog,cpu_yyy+tog,cpu_zzz+tog,
220	  pgpgin+tog,pgpgout+tog,pswpin+tog,pswpout+tog,
221	  intr+tog,ctxt+tog,
222	  &running,&blocked,
223	  &dummy_1,&dummy_2);
224
225    duse= cpu_use[tog]-cpu_use[!tog] + cpu_nic[tog]-cpu_nic[!tog];
226    dsys= cpu_sys[tog]-cpu_sys[!tog] + cpu_xxx[tog]-cpu_xxx[!tog] + cpu_yyy[tog]-cpu_yyy[!tog];
227    didl= cpu_idl[tog]-cpu_idl[!tog];
228    diow= cpu_iow[tog]-cpu_iow[!tog];
229    dstl= cpu_zzz[tog]-cpu_zzz[!tog];
230
231    /* idle can run backwards for a moment -- kernel "feature" */
232    if(debt){
233      didl = (int)didl + debt;
234      debt = 0;
235    }
236    if( (int)didl < 0 ){
237      debt = (int)didl;
238      didl = 0;
239    }
240
241    Div= duse+dsys+didl+diow+dstl;
242    divo2= Div/2UL;
243    printf(format,
244           running, blocked,
245	   unitConvert(kb_swap_used),unitConvert(kb_main_free),
246	   unitConvert(a_option?kb_inactive:kb_main_buffers),
247	   unitConvert(a_option?kb_active:kb_main_cached),
248	   (unsigned)( ( (pswpin [tog] - pswpin [!tog])*unitConvert(kb_per_page)+sleep_half )/sleep_time ), /*si*/
249	   (unsigned)( ( (pswpout[tog] - pswpout[!tog])*unitConvert(kb_per_page)+sleep_half )/sleep_time ), /*so*/
250	   (unsigned)( (  pgpgin [tog] - pgpgin [!tog]             +sleep_half )/sleep_time ), /*bi*/
251	   (unsigned)( (  pgpgout[tog] - pgpgout[!tog]             +sleep_half )/sleep_time ), /*bo*/
252	   (unsigned)( (  intr   [tog] - intr   [!tog]             +sleep_half )/sleep_time ), /*in*/
253	   (unsigned)( (  ctxt   [tog] - ctxt   [!tog]             +sleep_half )/sleep_time ), /*cs*/
254	   (unsigned)( (100*duse+divo2)/Div ), /*us*/
255	   (unsigned)( (100*dsys+divo2)/Div ), /*sy*/
256	   (unsigned)( (100*didl+divo2)/Div ), /*id*/
257	   (unsigned)( (100*diow+divo2)/Div )/*, //wa
258	   (unsigned)( (100*dstl+divo2)/Div )  //st  */
259    );
260
261    if (mode & ITLBSTAT) {
262	const char format[] = " %6lu %6lu %6lu";
263
264	getitlbstat(itlb_access+tog, itlb_miss+tog, ijtlb_miss+tog);
265
266	itlba = itlb_access[tog]-itlb_access[!tog];
267	itlbm = itlb_miss[tog]-itlb_miss[!tog];
268	ijtlbm = ijtlb_miss[tog]-ijtlb_miss[!tog];
269	printf(format, itlba, itlbm, ijtlbm);
270
271    } else if (mode & DTLBSTAT) {
272	const char format[] = " %6lu %6lu";
273
274	getdjtlbstat(djtlb_access+tog, djtlb_miss+tog);
275
276	djtlba = djtlb_access[tog]-djtlb_access[!tog];
277	djtlbm = djtlb_miss[tog]-djtlb_miss[!tog];
278	printf(format, djtlba, djtlbm);
279
280    } else if (mode & CPUCACHESTAT) {
281	const char format[] = " %6lu %6lu %6lu %6lu";
282
283	getcpucachestat(icache_access+tog, icache_miss+tog, dcache_wb+tog, dcache_miss+tog);
284
285	icachea = icache_access[tog]-icache_access[!tog];
286	icachem = icache_miss[tog]-icache_miss[!tog];
287	dcachewb = dcache_wb[tog]-dcache_wb[!tog];
288	dcachem = dcache_miss[tog]-dcache_miss[!tog];
289	printf(format, icachea, icachem, dcachewb, dcachem);
290    }
291    printf("\n");
292  }
293}
294
295////////////////////////////////////////////////////////////////////////////
296
297static void diskpartition_header(const char *partition_name){
298  printf("%-10s %10s %10s %10s %10s\n",partition_name, "reads  ", "read sectors", "writes   ", "requested writes");
299}
300
301////////////////////////////////////////////////////////////////////////////
302
303static int diskpartition_format(const char* partition_name){
304    FILE *fDiskstat;
305    struct disk_stat *disks;
306    struct partition_stat *partitions, *current_partition=NULL;
307    unsigned long ndisks, j, k, npartitions;
308    const char format[] = "%20u %10llu %10u %10u\n";
309
310    fDiskstat=fopen("/proc/diskstats","rb");
311    if(!fDiskstat){
312        fprintf(stderr, "Your kernel doesn't support diskstat. (2.5.70 or above required)\n");
313        exit(0);
314    }
315
316    fclose(fDiskstat);
317    ndisks=getdiskstat(&disks,&partitions);
318    npartitions=getpartitions_num(disks, ndisks);
319    for(k=0; k<npartitions; k++){
320       if(!strcmp(partition_name, partitions[k].partition_name)){
321                current_partition=&(partitions[k]);
322       }
323    }
324    if(!current_partition){
325         return -1;
326    }
327    diskpartition_header(partition_name);
328    printf (format,
329       current_partition->reads,current_partition->reads_sectors,current_partition->writes,current_partition->requested_writes);
330    fflush(stdout);
331    free(disks);
332    free(partitions);
333    for(j=1; j<num_updates; j++){
334        if (moreheaders && ((j%height)==0)) diskpartition_header(partition_name);
335        sleep(sleep_time);
336        ndisks=getdiskstat(&disks,&partitions);
337        npartitions=getpartitions_num(disks, ndisks);
338	current_partition=NULL;
339        for(k=0; k<npartitions; k++){
340          if(!strcmp(partition_name, partitions[k].partition_name)){
341                  current_partition=&(partitions[k]);
342          }
343        }
344        if(!current_partition){
345           return -1;
346        }
347        printf (format,
348        current_partition->reads,current_partition->reads_sectors,current_partition->writes,current_partition->requested_writes);
349        fflush(stdout);
350        free(disks);
351        free(partitions);
352    }
353    return 0;
354}
355
356////////////////////////////////////////////////////////////////////////////
357
358static void diskheader(void){
359  printf("disk- ------------reads------------ ------------writes----------- -----IO------\n");
360
361  printf("%5s %6s %6s %7s %7s %6s %6s %7s %7s %6s %6s\n",
362         " ", "total", "merged","sectors","ms","total","merged","sectors","ms","cur","sec");
363
364}
365
366////////////////////////////////////////////////////////////////////////////
367
368static void diskformat(void){
369  FILE *fDiskstat;
370  struct disk_stat *disks;
371  struct partition_stat *partitions;
372  unsigned long ndisks,i,j,k;
373  const char format[]="%-5s %6u %6u %7llu %7u %6u %6u %7llu %7u %6u %6u\n";
374  if ((fDiskstat=fopen("/proc/diskstats", "rb"))){
375    fclose(fDiskstat);
376    ndisks=getdiskstat(&disks,&partitions);
377    for(k=0; k<ndisks; k++){
378      if (moreheaders && ((k%height)==0)) diskheader();
379      printf(format,
380        disks[k].disk_name,
381        disks[k].reads,
382        disks[k].merged_reads,
383        disks[k].reads_sectors,
384        disks[k].milli_reading,
385        disks[k].writes,
386        disks[k].merged_writes,
387        disks[k].written_sectors,
388        disks[k].milli_writing,
389        disks[k].inprogress_IO?disks[k].inprogress_IO/1000:0,
390        disks[k].milli_spent_IO?disks[k].milli_spent_IO/1000:0/*,
391        disks[i].weighted_milli_spent_IO/1000*/
392      );
393      fflush(stdout);
394    }
395    free(disks);
396    free(partitions);
397    for(j=1; j<num_updates; j++){
398      sleep(sleep_time);
399      ndisks=getdiskstat(&disks,&partitions);
400      for(i=0; i<ndisks; i++,k++){
401        if (moreheaders && ((k%height)==0)) diskheader();
402        printf(format,
403          disks[i].disk_name,
404          disks[i].reads,
405          disks[i].merged_reads,
406          disks[i].reads_sectors,
407          disks[i].milli_reading,
408          disks[i].writes,
409          disks[i].merged_writes,
410          disks[i].written_sectors,
411          disks[i].milli_writing,
412          disks[i].inprogress_IO?disks[i].inprogress_IO/1000:0,
413          disks[i].milli_spent_IO?disks[i].milli_spent_IO/1000:0/*,
414          disks[i].weighted_milli_spent_IO/1000*/
415        );
416        fflush(stdout);
417      }
418      free(disks);
419      free(partitions);
420    }
421  }else{
422    fprintf(stderr, "Your kernel doesn't support diskstat (2.5.70 or above required)\n");
423    exit(0);
424  }
425}
426
427////////////////////////////////////////////////////////////////////////////
428
429static void slabheader(void){
430  printf("%-24s %6s %6s %6s %6s\n","Cache","Num", "Total", "Size", "Pages");
431}
432
433////////////////////////////////////////////////////////////////////////////
434
435static void slabformat (void){
436  FILE *fSlab;
437  struct slab_cache *slabs;
438  unsigned long nSlab,i,j,k;
439  const char format[]="%-24s %6u %6u %6u %6u\n";
440
441  fSlab=fopen("/proc/slabinfo", "rb");
442  if(!fSlab){
443    fprintf(stderr, "Your kernel doesn't support slabinfo.\n");
444    return;
445  }
446
447  nSlab = getslabinfo(&slabs);
448  for(k=0; k<nSlab; k++){
449    if (moreheaders && ((k%height)==0)) slabheader();
450    printf(format,
451      slabs[k].name,
452      slabs[k].active_objs,
453      slabs[k].num_objs,
454      slabs[k].objsize,
455      slabs[k].objperslab
456    );
457  }
458  free(slabs);
459  for(j=1,k=1; j<num_updates; j++) {
460    sleep(sleep_time);
461    nSlab = getslabinfo(&slabs);
462    for(i=0; i<nSlab; i++,k++){
463      if (moreheaders && ((k%height)==0)) slabheader();
464      printf(format,
465        slabs[i].name,
466        slabs[i].active_objs,
467        slabs[i].num_objs,
468        slabs[i].objsize,
469        slabs[i].objperslab
470      );
471    }
472    free(slabs);
473  }
474}
475
476////////////////////////////////////////////////////////////////////////////
477
478static void disksum_format(void) {
479
480  FILE *fDiskstat;
481  struct disk_stat *disks;
482  struct partition_stat *partitions;
483  int ndisks, i;
484  unsigned long reads, merged_reads, read_sectors, milli_reading, writes,
485                merged_writes, written_sectors, milli_writing, inprogress_IO,
486                milli_spent_IO, weighted_milli_spent_IO;
487
488  reads=merged_reads=read_sectors=milli_reading=writes=merged_writes= \
489  written_sectors=milli_writing=inprogress_IO=milli_spent_IO= \
490  weighted_milli_spent_IO=0;
491
492  if ((fDiskstat=fopen("/proc/diskstats", "rb"))){
493    fclose(fDiskstat);
494    ndisks=getdiskstat(&disks, &partitions);
495    printf("%13d disks \n", ndisks);
496    printf("%13d partitions \n", getpartitions_num(disks, ndisks));
497
498    for(i=0; i<ndisks; i++){
499         reads+=disks[i].reads;
500         merged_reads+=disks[i].merged_reads;
501         read_sectors+=disks[i].reads_sectors;
502         milli_reading+=disks[i].milli_reading;
503         writes+=disks[i].writes;
504         merged_writes+=disks[i].merged_writes;
505         written_sectors+=disks[i].written_sectors;
506         milli_writing+=disks[i].milli_writing;
507         inprogress_IO+=disks[i].inprogress_IO?disks[i].inprogress_IO/1000:0;
508         milli_spent_IO+=disks[i].milli_spent_IO?disks[i].milli_spent_IO/1000:0;
509      }
510
511    printf("%13lu total reads\n",reads);
512    printf("%13lu merged reads\n",merged_reads);
513    printf("%13lu read sectors\n",read_sectors);
514    printf("%13lu milli reading\n",milli_reading);
515    printf("%13lu writes\n",writes);
516    printf("%13lu merged writes\n",merged_writes);
517    printf("%13lu written sectors\n",written_sectors);
518    printf("%13lu milli writing\n",milli_writing);
519    printf("%13lu inprogress IO\n",inprogress_IO);
520    printf("%13lu milli spent IO\n",milli_spent_IO);
521
522    free(disks);
523    free(partitions);
524  }
525}
526
527////////////////////////////////////////////////////////////////////////////
528
529static void sum_format(void) {
530  unsigned int running, blocked, btime, processes;
531  jiff cpu_use, cpu_nic, cpu_sys, cpu_idl, cpu_iow, cpu_xxx, cpu_yyy, cpu_zzz;
532  unsigned long pgpgin, pgpgout, pswpin, pswpout;
533  unsigned int intr, ctxt;
534
535  meminfo();
536
537  getstat(&cpu_use, &cpu_nic, &cpu_sys, &cpu_idl,
538          &cpu_iow, &cpu_xxx, &cpu_yyy, &cpu_zzz,
539	  &pgpgin, &pgpgout, &pswpin, &pswpout,
540	  &intr, &ctxt,
541	  &running, &blocked,
542	  &btime, &processes);
543
544  printf("%13lu %s total memory\n", unitConvert(kb_main_total),szDataUnit);
545  printf("%13lu %s used memory\n", unitConvert(kb_main_used),szDataUnit);
546  printf("%13lu %s active memory\n", unitConvert(kb_active),szDataUnit);
547  printf("%13lu %s inactive memory\n", unitConvert(kb_inactive),szDataUnit);
548  printf("%13lu %s free memory\n", unitConvert(kb_main_free),szDataUnit);
549  printf("%13lu %s buffer memory\n", unitConvert(kb_main_buffers),szDataUnit);
550  printf("%13lu %s swap cache\n", unitConvert(kb_main_cached),szDataUnit);
551  printf("%13lu %s total swap\n", unitConvert(kb_swap_total),szDataUnit);
552  printf("%13lu %s used swap\n", unitConvert(kb_swap_used),szDataUnit);
553  printf("%13lu %s free swap\n", unitConvert(kb_swap_free),szDataUnit);
554  printf("%13Lu non-nice user cpu ticks\n", cpu_use);
555  printf("%13Lu nice user cpu ticks\n", cpu_nic);
556  printf("%13Lu system cpu ticks\n", cpu_sys);
557  printf("%13Lu idle cpu ticks\n", cpu_idl);
558  printf("%13Lu IO-wait cpu ticks\n", cpu_iow);
559  printf("%13Lu IRQ cpu ticks\n", cpu_xxx);
560  printf("%13Lu softirq cpu ticks\n", cpu_yyy);
561  printf("%13Lu stolen cpu ticks\n", cpu_zzz);
562  printf("%13lu pages paged in\n", pgpgin);
563  printf("%13lu pages paged out\n", pgpgout);
564  printf("%13lu pages swapped in\n", pswpin);
565  printf("%13lu pages swapped out\n", pswpout);
566  printf("%13u interrupts\n", intr);
567  printf("%13u CPU context switches\n", ctxt);
568  printf("%13u boot time\n", btime);
569  printf("%13u forks\n", processes);
570}
571
572////////////////////////////////////////////////////////////////////////////
573
574static void fork_format(void) {
575  unsigned int running, blocked, btime, processes;
576  jiff cpu_use, cpu_nic, cpu_sys, cpu_idl, cpu_iow, cpu_xxx, cpu_yyy, cpu_zzz;
577  unsigned long pgpgin, pgpgout, pswpin, pswpout;
578  unsigned int intr, ctxt;
579
580  getstat(&cpu_use, &cpu_nic, &cpu_sys, &cpu_idl,
581	  &cpu_iow, &cpu_xxx, &cpu_yyy, &cpu_zzz,
582	  &pgpgin, &pgpgout, &pswpin, &pswpout,
583	  &intr, &ctxt,
584	  &running, &blocked,
585	  &btime, &processes);
586
587  printf("%13u forks\n", processes);
588}
589
590////////////////////////////////////////////////////////////////////////////
591
592static int winhi(void) {
593    struct winsize win;
594    int rows = 24;
595
596    if (ioctl(1, TIOCGWINSZ, &win) != -1 && win.ws_row > 0)
597      rows = win.ws_row;
598
599    return rows;
600}
601
602////////////////////////////////////////////////////////////////////////////
603
604int main(int argc, char *argv[]) {
605  char partition[16];
606  unsigned long perfopt;
607
608  argc=0; /* redefined as number of integer arguments */
609  for (argv++;*argv;argv++) {
610    if ('-' ==(**argv)) {
611      switch (*(++(*argv))) {
612
613      case 'V':
614		  //display_version();
615	exit(0);
616      case 'd':
617	statMode |= DISKSTAT;
618	break;
619      case 'a':
620	/* active/inactive mode */
621	a_option=1;
622        break;
623      case 'f':
624	fork_format();
625        exit(0);
626      case 'm':
627        statMode |= SLABSTAT;
628	break;
629      case 'D':
630        statMode |= DISKSUMSTAT;
631	break;
632      case 'I':
633        statMode |= ITLBSTAT;
634	break;
635      case 'P':
636        statMode |= DTLBSTAT;
637	break;
638      case 'C':
639        statMode |= CPUCACHESTAT;
640	break;
641      case 'n':
642	/* print only one header */
643	moreheaders=FALSE;
644        break;
645      case 'p':
646        statMode |= PARTITIONSTAT;
647	if (argv[1]){
648	  char *cp = *++argv;
649	  if(!memcmp(cp,"/dev/",5)) cp += 5;
650	  snprintf(partition, sizeof partition, "%s", cp);
651	}else{
652	  fprintf(stderr, "-p requires an argument\n");
653          exit(EXIT_FAILURE);
654	}
655        break;
656      case 'S':
657	if (argv[1]){
658	      ++argv;
659	 	if (!strcmp(*argv, "k")) dataUnit=UNIT_k;
660	 	else if (!strcmp(*argv, "K")) dataUnit=UNIT_K;
661	 	else if (!strcmp(*argv, "m")) dataUnit=UNIT_m;
662	 	else if (!strcmp(*argv, "M")) dataUnit=UNIT_M;
663		else {fprintf(stderr, "-S requires k, K, m or M (default is kb)\n");
664		     exit(EXIT_FAILURE);
665		}
666		strcpy(szDataUnit, *argv);
667	 }else {fprintf(stderr, "-S requires an argument\n");
668		exit(EXIT_FAILURE);
669	 }
670	break;
671      case 's':
672        statMode |= VMSUMSTAT;
673	break;
674      default:
675	/* no other aguments defined yet. */
676	usage();
677      }
678   }else{
679      argc++;
680      switch (argc) {
681      case 1:
682        if ((sleep_time = atoi(*argv)) == 0)
683         usage();
684       num_updates = ULONG_MAX;
685       break;
686      case 2:
687        num_updates = atol(*argv);
688       break;
689      default:
690       usage();
691      } /* switch */
692  }
693}
694  perfopt = (statMode & (ITLBSTAT | DTLBSTAT | CPUCACHESTAT));
695  if (perfopt & (perfopt - 1)) {
696    printf("May use only one among I/P/C options\n");
697    exit(0);
698  }
699
700  if (moreheaders) {
701      int tmp=winhi()-3;
702      height=((tmp>0)?tmp:22);
703  }
704  setlinebuf(stdout);
705  switch(statMode){
706	case(VMSTAT):
707	case(ITLBSTAT):
708	case(DTLBSTAT):
709	case(CPUCACHESTAT):  new_format(statMode);
710			     break;
711	case(VMSUMSTAT):     sum_format();
712			     break;
713	case(DISKSTAT):      diskformat();
714			     break;
715	case(PARTITIONSTAT): if(diskpartition_format(partition)==-1)
716                                  printf("Partition was not found\n");
717			     break;
718	case(SLABSTAT):      slabformat();
719			     break;
720	case(DISKSUMSTAT):   disksum_format();
721			     break;
722	default:	     usage();
723			     break;
724  }
725  return 0;
726}
727