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