]> granicus.if.org Git - sysstat/blob - pidstat.c
sa_common.c: Remove some dead code
[sysstat] / pidstat.c
1 /*
2  * pidstat: Report statistics for Linux tasks
3  * (C) 2007-2020 by Sebastien GODARD (sysstat <at> orange.fr)
4  *
5  ***************************************************************************
6  * This program is free software; you can redistribute it and/or modify it *
7  * under the terms of the GNU General Public License as published  by  the *
8  * Free Software Foundation; either version 2 of the License, or (at  your *
9  * option) any later version.                                              *
10  *                                                                         *
11  * This program is distributed in the hope that it  will  be  useful,  but *
12  * WITHOUT ANY WARRANTY; without the implied warranty  of  MERCHANTABILITY *
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
14  * for more details.                                                       *
15  *                                                                         *
16  * You should have received a copy of the GNU General Public License along *
17  * with this program; if not, write to the Free Software Foundation, Inc., *
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA              *
19  ***************************************************************************
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <signal.h>
28 #include <dirent.h>
29 #include <ctype.h>
30 #include <sys/types.h>
31 #include <pwd.h>
32 #include <sys/utsname.h>
33 #include <regex.h>
34
35 #ifdef HAVE_LINUX_SCHED_H
36 #include <linux/sched.h>
37 #endif
38
39 #include "version.h"
40 #include "pidstat.h"
41 #include "rd_stats.h"
42 #include "count.h"
43
44 #ifdef USE_NLS
45 #include <locale.h>
46 #include <libintl.h>
47 #define _(string) gettext(string)
48 #else
49 #define _(string) (string)
50 #endif
51
52 #ifdef USE_SCCSID
53 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
54 char *sccsid(void) { return (SCCSID); }
55 #endif
56
57 unsigned long long tot_jiffies[3] = {0, 0, 0};
58 unsigned long long uptime_cs[3] = {0, 0, 0};
59 struct st_pid *pid_list = NULL;
60
61 struct tm ps_tstamp[3];
62 char commstr[MAX_COMM_LEN];
63 char userstr[MAX_USER_LEN];
64 char procstr[MAX_COMM_LEN];
65
66 int cpu_nr = 0;                 /* Nb of processors on the machine */
67 unsigned long tlmkb;            /* Total memory in kB */
68 long interval = -1;
69 long count = 0;
70 unsigned int pidflag = 0;       /* General flags */
71 unsigned int tskflag = 0;       /* TASK/CHILD stats */
72 unsigned int actflag = 0;       /* Activity flag */
73
74 struct sigaction alrm_act, int_act, chld_act;
75 int signal_caught = 0;
76
77 int dplaces_nr = -1;            /* Number of decimal places */
78
79 /*
80  ***************************************************************************
81  * Print usage and exit.
82  *
83  * IN:
84  * @progname    Name of sysstat command
85  ***************************************************************************
86  */
87 void usage(char *progname)
88 {
89         fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ] [ -e <program> <args> ]\n"),
90                 progname);
91
92         fprintf(stderr, _("Options are:\n"
93                           "[ -d ] [ -H ] [ -h ] [ -I ] [ -l ] [ -R ] [ -r ] [ -s ] [ -t ] [ -U [ <username> ] ]\n"
94                           "[ -u ] [ -V ] [ -v ] [ -w ] [ -C <command> ] [ -G <process_name> ]\n"
95                           "[ -p { <pid> [,...] | SELF | ALL } ] [ -T { TASK | CHILD | ALL } ]\n"
96                           "[ --dec={ 0 | 1 | 2 } ] [ --human ]\n"));
97         exit(1);
98 }
99
100 /*
101  ***************************************************************************
102  * SIGALRM signal handler. No need to reset the handler here.
103  *
104  * IN:
105  * @sig Signal number.
106  ***************************************************************************
107  */
108 void alarm_handler(int sig)
109 {
110         alarm(interval);
111 }
112
113 /*
114  ***************************************************************************
115  * SIGINT and SIGCHLD signals handler.
116  *
117  * IN:
118  * @sig Signal number.
119  ***************************************************************************
120  */
121 void int_handler(int sig)
122 {
123         signal_caught = 1;
124 }
125
126 /*
127  ***************************************************************************
128  * Free unused PID structures.
129  *
130  * IN
131  * @plist       Pointer address on the start of the linked list.
132  * @force       Set to TRUE if all PID structures shall be freed.
133  ***************************************************************************
134  */
135 void sfree_pid(struct st_pid **plist, int force)
136 {
137         int i;
138         struct st_pid *p;
139
140         while (*plist != NULL) {
141                 p = *plist;
142                 if (!p->exist || force) {
143                         *plist = p->next;
144                         for (i = 0; i < 3; i++) {
145                                 if (p->pstats[i]) {
146                                         free(p->pstats[i]);
147                                 }
148                         }
149                         free(p);
150                 }
151                 else {
152                         plist = &(p->next);
153                 }
154         }
155 }
156
157 /*
158  ***************************************************************************
159  * Set every PID in list to nonexistent status.
160  *
161  * IN:
162  * @plist       Pointer on the start of the linked list.
163  ***************************************************************************
164  */
165 void set_pid_nonexistent(struct st_pid *plist)
166 {
167         while (plist != NULL) {
168                 plist->exist = FALSE;
169                 plist = plist->next;
170         }
171 }
172
173 /*
174  ***************************************************************************
175  * Check flags and set default values.
176  ***************************************************************************
177  */
178 void check_flags(void)
179 {
180         unsigned int act = 0;
181
182         /* Display CPU usage for active tasks by default */
183         if (!actflag) {
184                 actflag |= P_A_CPU;
185         }
186
187         if (!DISPLAY_PID(pidflag)) {
188                 pidflag |= P_D_ACTIVE_PID + P_D_PID + P_D_ALL_PID;
189         }
190
191         if (!tskflag) {
192                 tskflag |= P_TASK;
193         }
194
195         /* Check that requested activities are available */
196         if (DISPLAY_TASK_STATS(tskflag)) {
197                 act |= P_A_CPU + P_A_MEM + P_A_IO + P_A_CTXSW
198                      + P_A_STACK + P_A_KTAB + P_A_RT;
199         }
200         if (DISPLAY_CHILD_STATS(tskflag)) {
201                 act |= P_A_CPU + P_A_MEM;
202         }
203
204         actflag &= act;
205
206         if (!actflag) {
207                 fprintf(stderr, _("Requested activities not available\n"));
208                 exit(1);
209         }
210 }
211
212 /*
213  ***************************************************************************
214  * Look for the PID in the list and store it if necessary.
215  *       PID ->  PID -> TGID ->  TID ->  TID ->  TID ->  PID -> NULL
216  * Eg.: 1234 -> 1289 -> 1356 -> 1356 -> 1361 -> 4678 -> 1376 -> NULL
217  *
218  * IN:
219  * @plist       Pointer address on the start of the linked list.
220  * @pid         PID number.
221  * @tgid        If PID is a TID then @tgid is its TGID number. 0 otherwise.
222  *
223  * RETURNS:
224  * Pointer on the st_pid structure in the list where the PID is located
225  * (whether it was already in the list or if it has been added).
226  * NULL if the PID is 0 or it is a TID and its TGID has not been found in
227  * list.
228  ***************************************************************************
229  */
230 struct st_pid *add_list_pid(struct st_pid **plist, pid_t pid, pid_t tgid)
231 {
232         struct st_pid *p, *ps, *tgid_p = NULL;
233         int i;
234         int tgid_found = FALSE;
235
236         if (!pid)
237                 return NULL;
238
239         if (!tgid) {
240                 /*
241                  * Add a true PID to the list.
242                  * Add it in ascending order, not taking into account
243                  * other TIDs.
244                  */
245                 while (*plist != NULL) {
246                         p = *plist;
247                         if (!p->tgid && (p->pid == pid))
248                                 /* PID found in list */
249                                 return p;
250
251                         if (!p->tgid && (p->pid > pid))
252                                 /* Stop now to insert PID in list */
253                                 break;
254
255                         plist = &(p->next);
256                 }
257         }
258         else {
259                 /*
260                  * PID is a TID.
261                  * It will be inserted in ascending order immediately
262                  * following its TGID.
263                  */
264                 while (*plist != NULL) {
265                         p = *plist;
266                         if (p->pid == tgid) {
267                                 /* TGID found in list */
268                                 tgid_found = TRUE;
269                                 tgid_p = p;
270                                 break;
271                         }
272
273                         plist = &(p->next);
274                 }
275                 if (!tgid_found)
276                         /* TGID not found: Stop now */
277                         return NULL;
278
279                 plist = &(p->next);
280                 while (*plist != NULL) {
281                         p = *plist;
282                         if ((p->tgid == tgid_p) && (p->pid == pid))
283                                 /* TID found in list */
284                                 return p;
285
286                         if ((p->tgid == tgid_p) && (p->pid > pid))
287                                 /* Stop now to insert TID in list */
288                                 break;
289                         if (p->tgid != tgid_p)
290                                 /* End of TID list: insert TID here */
291                                 break;
292
293                         plist = &(p->next);
294                 }
295         }
296
297         /* PID not found */
298         ps = *plist;
299
300         /* Add PID to the list */
301         if ((*plist = (struct st_pid *) malloc(sizeof(struct st_pid))) == NULL) {
302                 perror("malloc");
303                 exit(4);
304         }
305         memset(*plist, 0, sizeof(struct st_pid));
306
307         p = *plist;
308         for (i = 0; i < 3; i++) {
309                 if ((p->pstats[i] = (struct pid_stats *) malloc(sizeof(struct pid_stats))) == NULL) {
310                         perror("malloc");
311                         exit(4);
312                 }
313                 memset(p->pstats[i], 0, PID_STATS_SIZE);
314         }
315         p->pid = pid;
316         p->next = ps;
317         if (tgid_p) {
318                 p->tgid = tgid_p;
319         }
320
321         return p;
322 }
323
324 /*
325  ***************************************************************************
326  * Get pointer on task's command string.
327  * If this is a thread then return the short command name so that threads
328  * can still be identified.
329  *
330  * IN:
331  * @plist       Pointer address on the start of the linked list.
332  ***************************************************************************
333  */
334 char *get_tcmd(struct st_pid *plist)
335 {
336         if (DISPLAY_CMDLINE(pidflag) && strlen(plist->cmdline) && !plist->tgid)
337                 /* Option "-l" used */
338                 return plist->cmdline;
339         else
340                 return plist->comm;
341 }
342
343 /*
344  ***************************************************************************
345  * Display process command name or command line.
346  *
347  * IN:
348  * @plist       Pointer address on the start of the linked list.
349  ***************************************************************************
350  */
351 void print_comm(struct st_pid *plist)
352 {
353         char *p;
354
355         /* Get pointer on task's command string */
356         p = get_tcmd(plist);
357
358         if (plist->tgid) {
359                 if (IS_PID_DISPLAYED(plist->tgid->flags)) {
360                         cprintf_s(IS_ZERO, "  |__%s\n", p);
361                 }
362                 else {
363                         /* Its TGID has not been displayed */
364                         cprintf_s(IS_STR, "  (%s)", plist->tgid->comm);
365                         cprintf_s(IS_ZERO, "__%s\n", p);
366
367                         /* We can now consider this has been the case */
368                         plist->tgid->flags |= F_PID_DISPLAYED;
369                 }
370         }
371         else {
372                 cprintf_s(IS_STR, "  %s\n", p);
373         }
374 }
375
376 /*
377  ***************************************************************************
378  * Read /proc/meminfo.
379  ***************************************************************************
380  */
381 void read_proc_meminfo(void)
382 {
383         struct stats_memory st_mem;
384
385         memset(&st_mem, 0, STATS_MEMORY_SIZE);
386         read_meminfo(&st_mem);
387         tlmkb = st_mem.tlmkb;
388 }
389
390 /*
391  ***************************************************************************
392  * Read stats from /proc/#[/task/##]/stat.
393  *
394  * IN:
395  * @pid         Process whose stats are to be read.
396  * @plist       Pointer on the linked list where PID is saved.
397  * @tgid        If !=0, thread whose stats are to be read.
398  * @curr        Index in array for current sample statistics.
399  *
400  * OUT:
401  * @thread_nr   Number of threads of the process.
402  *
403  * RETURNS:
404  * 0 if stats have been successfully read, and 1 otherwise.
405  ***************************************************************************
406  */
407 int read_proc_pid_stat(pid_t pid, struct st_pid *plist,
408                        unsigned int *thread_nr, pid_t tgid, int curr)
409 {
410         int fd, sz, rc, commsz;
411         char filename[128];
412         static char buffer[1024 + 1];
413         char *start, *end;
414         struct pid_stats *pst = plist->pstats[curr];
415
416         if (tgid) {
417                 sprintf(filename, TASK_STAT, tgid, pid);
418         }
419         else {
420                 sprintf(filename, PID_STAT, pid);
421         }
422
423         if ((fd = open(filename, O_RDONLY)) < 0)
424                 /* No such process */
425                 return 1;
426
427         sz = read(fd, buffer, 1024);
428         close(fd);
429         if (sz <= 0)
430                 return 1;
431         buffer[sz] = '\0';
432
433         if ((start = strchr(buffer, '(')) == NULL)
434                 return 1;
435         start += 1;
436         if ((end = strrchr(start, ')')) == NULL)
437                 return 1;
438         commsz = end - start;
439         if (commsz >= MAX_COMM_LEN)
440                 return 1;
441         memcpy(plist->comm, start, commsz);
442         plist->comm[commsz] = '\0';
443         start = end + 2;
444
445         rc = sscanf(start,
446                     "%*s %*d %*d %*d %*d %*d %*u %llu %llu"
447                     " %llu %llu %llu %llu %lld %lld %*d %*d %u %*u %*d %llu %llu"
448                     " %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u"
449                     " %*u %u %u %u %llu %llu %lld\n",
450                     &pst->minflt, &pst->cminflt, &pst->majflt, &pst->cmajflt,
451                     &pst->utime,  &pst->stime, &pst->cutime, &pst->cstime,
452                     thread_nr, &pst->vsz, &pst->rss, &pst->processor,
453                     &pst->priority, &pst->policy,
454                     &pst->blkio_swapin_delays, &pst->gtime, &pst->cgtime);
455
456         if (rc < 15)
457                 return 1;
458
459         if (rc < 17) {
460                 /* gtime and cgtime fields are unavailable in file */
461                 pst->gtime = pst->cgtime = 0;
462         }
463
464         /* Convert to kB */
465         pst->vsz >>= 10;
466         pst->rss = PG_TO_KB(pst->rss);
467
468         return 0;
469 }
470
471 /*
472  ***************************************************************************
473  * Read stats from /proc/#[/task/##]/schedstat.
474  *
475  * IN:
476  * @pid         Process whose stats are to be read.
477  * @plist       Pointer on the linked list where PID is saved.
478  * @tgid        If != 0, thread whose stats are to be read.
479  * @curr        Index in array for current sample statistics.
480  *
481  * RETURNS:
482  * 0 if stats have been successfully read, and 1 otherwise.
483  ***************************************************************************
484  */
485 int read_proc_pid_sched(pid_t pid, struct st_pid *plist, pid_t tgid, int curr)
486 {
487         int fd, sz, rc = 0;
488         char filename[128];
489         static char buffer[1024 + 1];
490         unsigned long long wtime = 0;
491         struct pid_stats *pst = plist->pstats[curr];
492
493         if (tgid) {
494                 sprintf(filename, TASK_SCHED, tgid, pid);
495         }
496         else {
497                 sprintf(filename, PID_SCHED, pid);
498         }
499
500         if ((fd = open(filename, O_RDONLY)) >= 0) {
501                 /* schedstat file found for process */
502                 sz = read(fd, buffer, 1024);
503                 close(fd);
504                 if (sz > 0) {
505                         buffer[sz] = '\0';
506
507                         rc = sscanf(buffer, "%*u %llu %*d\n", &wtime);
508                 }
509         }
510
511         /* Convert ns to jiffies */
512         pst->wtime = wtime * HZ / 1000000000;
513
514         if (rc < 1)
515                 return 1;
516
517         return 0;
518 }
519
520 /*
521  *****************************************************************************
522  * Read stats from /proc/#[/task/##]/status.
523  *
524  * IN:
525  * @pid         Process whose stats are to be read.
526  * @plist       Pointer on the linked list where PID is saved.
527  * @tgid        If != 0, thread whose stats are to be read.
528  * @curr        Index in array for current sample statistics.
529  *
530  * RETURNS:
531  * 0 if stats have been successfully read, and 1 otherwise.
532  *****************************************************************************
533  */
534 int read_proc_pid_status(pid_t pid, struct st_pid *plist, pid_t tgid, int curr)
535 {
536         FILE *fp;
537         char filename[128], line[256];
538         struct pid_stats *pst = plist->pstats[curr];
539
540         if (tgid) {
541                 sprintf(filename, TASK_STATUS, tgid, pid);
542         }
543         else {
544                 sprintf(filename, PID_STATUS, pid);
545         }
546
547         if ((fp = fopen(filename, "r")) == NULL)
548                 /* No such process */
549                 return 1;
550
551         while (fgets(line, sizeof(line), fp) != NULL) {
552
553                 if (!strncmp(line, "Uid:", 4)) {
554                         sscanf(line + 5, "%u", &plist->uid);
555                 }
556                 else if (!strncmp(line, "Threads:", 8)) {
557                         sscanf(line + 9, "%u", &pst->threads);
558                 }
559                 else if (!strncmp(line, "voluntary_ctxt_switches:", 24)) {
560                         sscanf(line + 25, "%lu", &pst->nvcsw);
561                 }
562                 else if (!strncmp(line, "nonvoluntary_ctxt_switches:", 27)) {
563                         sscanf(line + 28, "%lu", &pst->nivcsw);
564                 }
565         }
566
567         fclose(fp);
568
569         return 0;
570 }
571
572 /*
573  *****************************************************************************
574  * Read information from /proc/#[/task/##}/smaps.
575  *
576  * @pid         Process whose stats are to be read.
577  * @plist       Pointer on the linked list where PID is saved.
578  * @tgid        If != 0, thread whose stats are to be read.
579  * @curr        Index in array for current sample statistics.
580  *
581  * RETURNS:
582  * 0 if stats have been successfully read, and 1 otherwise.
583  *****************************************************************************
584  */
585 int read_proc_pid_smap(pid_t pid, struct st_pid *plist, pid_t tgid, int curr)
586 {
587         FILE *fp;
588         char filename[128], line[256];
589         int state = 0;
590         struct pid_stats *pst = plist->pstats[curr];
591
592         if (tgid) {
593                 sprintf(filename, TASK_SMAP, tgid, pid);
594         }
595         else {
596                 sprintf(filename, PID_SMAP, pid);
597         }
598
599         if ((fp = fopen(filename, "rt")) == NULL)
600                 /* No such process */
601                 return 1;
602
603         while ((state < 3) && (fgets(line, sizeof(line), fp) != NULL)) {
604                 switch (state) {
605                         case 0:
606                                 if (strstr(line, "[stack]")) {
607                                         state = 1;
608                                 }
609                                 break;
610                         case 1:
611                                 if (strstr(line, "Size:")) {
612                                         sscanf(line + sizeof("Size:"), "%lu", &pst->stack_size);
613                                         state = 2;
614                                 }
615                                 break;
616                         case 2:
617                                 if (strstr(line, "Referenced:")) {
618                                         sscanf(line + sizeof("Referenced:"), "%lu", &pst->stack_ref);
619                                         state = 3;
620                                 }
621                                 break;
622                 }
623         }
624
625         fclose(fp);
626
627         return 0;
628 }
629
630 /*
631  *****************************************************************************
632  * Read process command line from /proc/#[/task/##]/cmdline.
633  *
634  * IN:
635  * @pid         Process whose command line is to be read.
636  * @plist       Pointer on the linked list where PID is saved.
637  * @tgid        If != 0, thread whose stats are to be read.
638  *
639  * OUT:
640  * @pst         Pointer on structure where command line has been saved.
641  *
642  * RETURNS:
643  * 0 if command line has been successfully read (even if the /proc/.../cmdline
644  * is just empty), and 1 otherwise (the process has terminated).
645  *****************************************************************************
646  */
647 int read_proc_pid_cmdline(pid_t pid, struct st_pid *plist, pid_t tgid)
648 {
649         FILE *fp;
650         char filename[128], line[MAX_CMDLINE_LEN];
651         size_t len;
652         int i, found = FALSE;
653
654         if (tgid) {
655                 sprintf(filename, TASK_CMDLINE, tgid, pid);
656         }
657         else {
658                 sprintf(filename, PID_CMDLINE, pid);
659         }
660
661         if ((fp = fopen(filename, "r")) == NULL)
662                 /* No such process */
663                 return 1;
664
665         memset(line, 0, MAX_CMDLINE_LEN);
666
667         len = fread(line, 1, sizeof(line) - 1, fp);
668         fclose(fp);
669
670         if (len) {
671                 for (i = len - 2; i >= 0; i--) {
672                         if (line[i]) {
673                                 found = TRUE;
674                         }
675                         else if (found) {
676                                 line[i] = ' ';
677                         }
678                 }
679                 strncpy(plist->cmdline, line, sizeof(plist->cmdline) - 1);
680                 plist->cmdline[sizeof(plist->cmdline) - 1] = '\0';
681         }
682         else {
683                 /* proc/.../cmdline was empty */
684                 plist->cmdline[0] = '\0';
685         }
686         return 0;
687 }
688
689 /*
690  ***************************************************************************
691  * Read stats from /proc/#[/task/##]/io.
692  *
693  * IN:
694  * @pid         Process whose stats are to be read.
695  * @plist       Pointer on the linked list where PID is saved.
696  * @tgid        If != 0, thread whose stats are to be read.
697  * @curr        Index in array for current sample statistics.
698  *
699  * RETURNS:
700  * 0 if stats have been successfully read.
701  * Also returns 0 if current process has terminated or if its io file
702  * doesn't exist, but in this case, set process' F_NO_PID_IO flag to
703  * indicate that I/O stats should no longer be read for it.
704  ***************************************************************************
705  */
706 int read_proc_pid_io(pid_t pid, struct st_pid *plist, pid_t tgid, int curr)
707 {
708         FILE *fp;
709         char filename[128], line[256];
710         struct pid_stats *pst = plist->pstats[curr];
711
712         if (tgid) {
713                 sprintf(filename, TASK_IO, tgid, pid);
714         }
715         else {
716                 sprintf(filename, PID_IO, pid);
717         }
718
719         if ((fp = fopen(filename, "r")) == NULL) {
720                 /* No such process... or file non existent! */
721                 plist->flags |= F_NO_PID_IO;
722                 /*
723                  * Also returns 0 since io stats file doesn't necessarily exist,
724                  * depending on the kernel version used.
725                  */
726                 return 0;
727         }
728
729         while (fgets(line, sizeof(line), fp) != NULL) {
730
731                 if (!strncmp(line, "read_bytes:", 11)) {
732                         sscanf(line + 12, "%llu", &pst->read_bytes);
733                 }
734                 else if (!strncmp(line, "write_bytes:", 12)) {
735                         sscanf(line + 13, "%llu", &pst->write_bytes);
736                 }
737                 else if (!strncmp(line, "cancelled_write_bytes:", 22)) {
738                         sscanf(line + 23, "%llu", &pst->cancelled_write_bytes);
739                 }
740         }
741
742         fclose(fp);
743
744         plist->flags &= ~F_NO_PID_IO;
745
746         return 0;
747 }
748
749 /*
750  ***************************************************************************
751  * Count number of file descriptors in /proc/#[/task/##]/fd directory.
752  *
753  * IN:
754  * @pid         Process whose stats are to be read.
755  * @plist       Pointer on the linked list where PID is saved.
756  * @tgid        If != 0, thread whose stats are to be read.
757  * @curr        Index in array for current sample statistics.
758  *
759  * RETURNS:
760  * 0 if stats have been successfully read.
761  * Also returns 0 if current process has terminated or if we cannot read its
762  * fd directory, but in this case, set process' F_NO_PID_FD flag to
763  * indicate that fd directory couldn't be read.
764  ***************************************************************************
765  */
766 int read_proc_pid_fd(pid_t pid, struct st_pid *plist, pid_t tgid, int curr)
767 {
768         DIR *dir;
769         struct dirent *drp;
770         char filename[128];
771         struct pid_stats *pst = plist->pstats[curr];
772
773         if (tgid) {
774                 sprintf(filename, TASK_FD, tgid, pid);
775         }
776         else {
777                 sprintf(filename, PID_FD, pid);
778         }
779
780         if ((dir = opendir(filename)) == NULL) {
781                 /* Cannot read fd directory */
782                 plist->flags |= F_NO_PID_FD;
783                 return 0;
784         }
785
786         pst->fd_nr = 0;
787
788         /* Count number of entries if fd directory */
789         while ((drp = readdir(dir)) != NULL) {
790                 if (isdigit(drp->d_name[0])) {
791                         (pst->fd_nr)++;
792                 }
793         }
794
795         closedir(dir);
796
797         plist->flags &= ~F_NO_PID_FD;
798
799         return 0;
800 }
801
802 /*
803  ***************************************************************************
804  * Read various stats for given PID.
805  *
806  * IN:
807  * @pid         Process whose stats are to be read.
808  * @plist       Pointer on the linked list where PID is saved.
809  * @tgid        If !=0, thread whose stats are to be read.
810  * @curr        Index in array for current sample statistics.
811  *
812  * OUT:
813  * @thread_nr   Number of threads of the process.
814  *
815  * RETURNS:
816  * 0 if stats have been successfully read, and 1 otherwise.
817  ***************************************************************************
818  */
819 int read_pid_stats(pid_t pid, struct st_pid *plist, unsigned int *thread_nr,
820                    pid_t tgid, int curr)
821 {
822         if (read_proc_pid_stat(pid, plist, thread_nr, tgid, curr))
823                 return 1;
824
825         /*
826          * No need to test the return code here: Not finding
827          * the schedstat files shouldn't make pidstat stop.
828          */
829         read_proc_pid_sched(pid, plist, tgid, curr);
830
831         if (DISPLAY_CMDLINE(pidflag) && !plist->cmdline[0]) {
832                 if (read_proc_pid_cmdline(pid, plist, tgid))
833                         return 1;
834         }
835
836         if (read_proc_pid_status(pid, plist, tgid, curr))
837                 return 1;
838
839         if (DISPLAY_STACK(actflag)) {
840                 if (read_proc_pid_smap(pid, plist, tgid, curr))
841                         return 1;
842         }
843
844         if (DISPLAY_KTAB(actflag)) {
845                 if (read_proc_pid_fd(pid, plist, tgid, curr))
846                         return 1;
847         }
848
849         if (DISPLAY_IO(actflag))
850                 /* Assume that /proc/#/task/#/io exists! */
851                 return (read_proc_pid_io(pid, plist, tgid, curr));
852
853         return 0;
854 }
855
856 /*
857  ***************************************************************************
858  * Read stats for threads in /proc/#/task directory.
859  *
860  * IN:
861  * @pid         Process number whose threads stats are to be read.
862  * @plist       Pointer on the linked list where PID is saved.
863  * @curr        Index in array for current sample statistics.
864  ***************************************************************************
865  */
866 void read_task_stats(pid_t pid, struct st_pid *plist, int curr)
867 {
868         DIR *dir;
869         pid_t tid;
870         struct dirent *drp;
871         char filename[128];
872         unsigned int thr_nr;
873         struct st_pid *tlist;
874
875         /* Open /proc/#/task directory */
876         sprintf(filename, PROC_TASK, pid);
877         if ((dir = __opendir(filename)) == NULL)
878                 return;
879
880         while ((drp = __readdir(dir)) != NULL) {
881                 if (!isdigit(drp->d_name[0])) {
882                         continue;
883                 }
884
885                 tid = atoi(drp->d_name);
886
887                 tlist = add_list_pid(&pid_list, tid, pid);
888                 if (!tlist)
889                         continue;
890                 tlist->exist = TRUE;
891
892                 if (read_pid_stats(tid, tlist, &thr_nr, pid, curr)) {
893                         /* Thread doesn't exist */
894                         tlist->exist = FALSE;
895                 }
896         }
897
898         __closedir(dir);
899 }
900
901 /*
902  ***************************************************************************
903  * Read various stats.
904  *
905  * IN:
906  * @curr        Index in array for current sample statistics.
907  ***************************************************************************
908  */
909 void read_stats(int curr)
910 {
911         DIR *dir;
912         struct dirent *drp;
913         unsigned int thr_nr;
914         pid_t pid;
915         struct st_pid *plist;
916         struct stats_cpu *st_cpu;
917
918         /*
919          * Allocate two structures for CPU statistics.
920          * No need to init them (done by read_stat_cpu() function).
921          */
922         if ((st_cpu = (struct stats_cpu *) malloc(STATS_CPU_SIZE * 2)) == NULL) {
923                 perror("malloc");
924                 exit(4);
925         }
926         /* Read statistics for CPUs "all" */
927         read_stat_cpu(st_cpu, 1);
928
929         /*
930          * Compute the total number of jiffies spent by all processors.
931          * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
932          * already include them.
933          */
934         tot_jiffies[curr] = st_cpu->cpu_user + st_cpu->cpu_nice +
935                             st_cpu->cpu_sys + st_cpu->cpu_idle +
936                             st_cpu->cpu_iowait + st_cpu->cpu_hardirq +
937                             st_cpu->cpu_steal + st_cpu->cpu_softirq;
938         free(st_cpu);
939
940         if (DISPLAY_ALL_PID(pidflag)) {
941
942                 /* Open /proc directory */
943                 if ((dir = __opendir(PROC)) == NULL) {
944                         perror("opendir");
945                         exit(4);
946                 }
947
948                 /* Get directory entries */
949                 while ((drp = __readdir(dir)) != NULL) {
950                         if (!isdigit(drp->d_name[0])) {
951                                 continue;
952                         }
953
954                         pid = atoi(drp->d_name);
955
956                         plist = add_list_pid(&pid_list, pid, 0);
957                         if (!plist)
958                                 continue;
959                         plist->exist = TRUE;
960
961                         if (read_pid_stats(pid, plist, &thr_nr, 0, curr)) {
962                                 /* PID has terminated */
963                                 plist->exist = FALSE;
964
965                         } else if (DISPLAY_TID(pidflag)) {
966                                 /* Read stats for threads in task subdirectory */
967                                 read_task_stats(pid, plist, curr);
968                         }
969                 }
970
971                 /* Close /proc directory */
972                 __closedir(dir);
973         }
974
975         else if (DISPLAY_PID(pidflag)) {
976                 /* Read stats for each PID in the list */
977                 for (plist = pid_list; plist != NULL; plist = plist->next) {
978
979                         if (plist->tgid)
980                                 /*
981                                  * Ignore TIDs.
982                                  * The user can only enter PIDs on the command line.
983                                  * If there is a TID then this is because the user has
984                                  * used option -t, and the TID has been inserted in the
985                                  * list by read_task_stats() function below.
986                                  */
987                                 continue;
988
989                         if (read_pid_stats(plist->pid, plist, &thr_nr, 0, curr)) {
990                                 /* PID has terminated */
991                                 plist->exist = FALSE;
992                         }
993                         else {
994                                 plist->exist = TRUE;
995
996                                 if (DISPLAY_TID(pidflag)) {
997                                         read_task_stats(plist->pid, plist, curr);
998                                 }
999                         }
1000                 }
1001         }
1002
1003         /* Free unused PID structures */
1004         sfree_pid(&pid_list, FALSE);
1005 }
1006
1007 /*
1008  ***************************************************************************
1009  * Get current PID to display.
1010  * First, check that PID exists. *Then* check that it's an active process
1011  * and/or that the string (entered on the command line with option -C)
1012  * is found in command name, or that the process string (entered on the
1013  * command line with option -G) is found either in its command name (in case
1014  * PID is a process) or in command name of its thread leader (in case
1015  * PID is a thread).
1016  *
1017  * IN:
1018  * @prev        Index in array where stats used as reference are.
1019  * @curr        Index in array for current sample statistics.
1020  * @activity    Current activity to display (CPU, memory...).
1021  *              Can be more than one if stats are displayed on one line.
1022  * @pflag       Flag indicating whether stats are to be displayed for
1023  *              individual tasks or for all their children.
1024  * @plist       Pointer on the linked list where PID is saved.
1025  *
1026  * RETURNS:
1027  *  0 if PID no longer exists.
1028  * -1 if PID exists but should not be displayed.
1029  *  1 if PID can be displayed.
1030  ***************************************************************************
1031  */
1032 int get_pid_to_display(int prev, int curr, unsigned int activity, unsigned int pflag,
1033                        struct st_pid *plist)
1034 {
1035         int rc;
1036         char *pc;
1037         regex_t regex;
1038         struct passwd *pwdent;
1039         struct pid_stats *pstc = plist->pstats[curr], *pstp = plist->pstats[prev];
1040
1041         if (!plist->exist)
1042                 /* PID no longer exists */
1043                 return 0;
1044
1045         if (!plist->tgid) {
1046                 /* This is group leader: Set it as not displayed by default */
1047                 plist->flags &= ~F_PID_DISPLAYED;
1048         }
1049
1050         if ((DISPLAY_ALL_PID(pidflag) || DISPLAY_TID(pidflag)) &&
1051                 DISPLAY_ACTIVE_PID(pidflag)) {
1052                 int isActive = FALSE;
1053
1054                 /* Check that it's an "active" process */
1055                 if (DISPLAY_CPU(activity)) {
1056                         /* User time already includes guest time */
1057                         if ((pstc->utime != pstp->utime) ||
1058                             (pstc->stime != pstp->stime)) {
1059                                 isActive = TRUE;
1060                         }
1061                         else {
1062                                 /*
1063                                  * Process is not active but if we are showing
1064                                  * child stats then we need to look there.
1065                                  */
1066                                 if (DISPLAY_CHILD_STATS(pflag)) {
1067                                         /* User time already includes guest time */
1068                                         if ((pstc->cutime != pstp->cutime) ||
1069                                             (pstc->cstime != pstp->cstime)) {
1070                                                 isActive = TRUE;
1071                                         }
1072                                 }
1073                         }
1074                 }
1075
1076                 if (DISPLAY_MEM(activity) && !isActive) {
1077                         if ((pstc->minflt != pstp->minflt) ||
1078                             (pstc->majflt != pstp->majflt)) {
1079                                 isActive = TRUE;
1080                         }
1081                         else {
1082                                 if (DISPLAY_TASK_STATS(pflag)) {
1083                                         if ((pstc->vsz != pstp->vsz) ||
1084                                             (pstc->rss != pstp->rss)) {
1085                                                 isActive = TRUE;
1086                                         }
1087                                 }
1088                                 else if (DISPLAY_CHILD_STATS(pflag)) {
1089                                         if ((pstc->cminflt != pstp->cminflt) ||
1090                                             (pstc->cmajflt != pstp->cmajflt)) {
1091                                                 isActive = TRUE;
1092                                         }
1093                                 }
1094                         }
1095                 }
1096
1097                 if (DISPLAY_STACK(activity) && !isActive) {
1098                         if ((pstc->stack_size != pstp->stack_size) ||
1099                             (pstc->stack_ref != pstp->stack_ref)) {
1100                                 isActive = TRUE;
1101                         }
1102                 }
1103
1104                 if (DISPLAY_IO(activity) && !isActive) {
1105                         if (pstc->blkio_swapin_delays !=
1106                              pstp->blkio_swapin_delays) {
1107                                 isActive = TRUE;
1108                         }
1109                         if (!(NO_PID_IO(plist->flags)) && !isActive) {
1110                                 /* /proc/#/io file should exist to check I/O stats */
1111                                 if ((pstc->read_bytes  != pstp->read_bytes)  ||
1112                                     (pstc->write_bytes != pstp->write_bytes) ||
1113                                     (pstc->cancelled_write_bytes !=
1114                                      pstp->cancelled_write_bytes)) {
1115                                         isActive = TRUE;
1116                                 }
1117                         }
1118                 }
1119
1120                 if (DISPLAY_CTXSW(activity) && !isActive) {
1121                         if ((pstc->nvcsw  != pstp->nvcsw) ||
1122                             (pstc->nivcsw != pstp->nivcsw)) {
1123                                 isActive = TRUE;
1124                         }
1125                 }
1126
1127                 if (DISPLAY_RT(activity) && !isActive) {
1128                         if ((pstc->priority != pstp->priority) ||
1129                             (pstc->policy != pstp->policy)) {
1130                                 isActive = TRUE;
1131                         }
1132                 }
1133
1134                 if (DISPLAY_KTAB(activity) && !isActive &&
1135                         !(NO_PID_FD(plist->flags))) {   /* /proc/#/fd directory should be readable */
1136                         if ((pstc->threads != pstp->threads) ||
1137                             (pstc->fd_nr != pstp->fd_nr)) {
1138                                 isActive = TRUE;
1139                         }
1140                 }
1141
1142                 /* If PID isn't active for any of the activities then return */
1143                 if (!isActive)
1144                         return -1;
1145         }
1146
1147         if (COMMAND_STRING(pidflag)) {
1148                 if (regcomp(&regex, commstr, REG_EXTENDED | REG_NOSUB) != 0)
1149                         /* Error in preparing regex structure */
1150                         return -1;
1151
1152                 pc = get_tcmd(plist);   /* Get pointer on task's command string */
1153                 rc = regexec(&regex, pc, 0, NULL, 0);
1154                 regfree(&regex);
1155
1156                 if (rc)
1157                         /* regex pattern not found in command name */
1158                         return -1;
1159         }
1160
1161         if (PROCESS_STRING(pidflag)) {
1162                 if (!plist->tgid) {
1163                         /* This PID is a process ("thread group leader") */
1164                         if (regcomp(&regex, procstr, REG_EXTENDED | REG_NOSUB) != 0)
1165                                 /* Error in preparing regex structure */
1166                                 return -1;
1167
1168                         pc = get_tcmd(plist);   /* Get pointer on task's command string */
1169                         rc = regexec(&regex, pc, 0, NULL, 0);
1170                         regfree(&regex);
1171
1172                         if (rc)
1173                                 /* regex pattern not found in command name */
1174                                 return -1;
1175
1176                 }
1177                 else if (!IS_PID_DISPLAYED(plist->tgid->flags))
1178                         /* This pid is a thread and is not part of a process to display */
1179                         return -1;
1180         }
1181
1182         if (USER_STRING(pidflag)) {
1183                 if ((pwdent = __getpwuid(plist->uid)) != NULL) {
1184                         if (strcmp(pwdent->pw_name, userstr))
1185                                 /* This PID doesn't belong to user */
1186                                 return -1;
1187                 }
1188         }
1189
1190         plist->flags |= F_PID_DISPLAYED;
1191         return 1;
1192 }
1193
1194 /*
1195  ***************************************************************************
1196  * Display UID/username, PID and TID.
1197  *
1198  * IN:
1199  * @plist       Pointer on the linked list where PID is saved.
1200  * @c           No-op character.
1201  ***************************************************************************
1202  */
1203 void __print_line_id(struct st_pid *plist, char c)
1204 {
1205         char format[32];
1206         struct passwd *pwdent;
1207
1208         if (DISPLAY_USERNAME(pidflag) && ((pwdent = __getpwuid(plist->uid)) != NULL)) {
1209                 cprintf_in(IS_STR, " %8s", pwdent->pw_name, 0);
1210         }
1211         else {
1212                 cprintf_in(IS_INT, " %5d", "", plist->uid);
1213         }
1214
1215         if (DISPLAY_TID(pidflag)) {
1216
1217                 if (plist->tgid) {
1218                         /* This is a TID */
1219                         if (IS_PID_DISPLAYED(plist->tgid->flags)) {
1220                                 sprintf(format, "         %c %%9u", c);
1221                         }
1222                         else {
1223                                 strcpy(format, " %9u");
1224                                 cprintf_in(IS_INT, format, "", plist->tgid->pid);
1225                         }
1226                 }
1227                 else {
1228                         /* This is a PID (TGID) */
1229                         sprintf(format, " %%9u         %c", c);
1230                 }
1231         }
1232         else {
1233                 strcpy(format, " %9u");
1234         }
1235
1236         cprintf_in(IS_INT, format, "", plist->pid);
1237 }
1238
1239 /*
1240  ***************************************************************************
1241  * Display timestamp, PID and TID.
1242  *
1243  * IN:
1244  * @timestamp   Current timestamp.
1245  * @plist       Pointer on the linked list where PID is saved.
1246  ***************************************************************************
1247  */
1248 void print_line_id(char *timestamp, struct st_pid *plist)
1249 {
1250         printf("%-11s", timestamp);
1251         __print_line_id(plist, '-');
1252 }
1253
1254 /*
1255  ***************************************************************************
1256  * Display all statistics for tasks in one line format.
1257  *
1258  * IN:
1259  * @prev        Index in array where stats used as reference are.
1260  * @curr        Index in array for current sample statistics.
1261  * @dis         TRUE if a header line must be printed.
1262  * @prev_string String displayed at the beginning of a header line. This is
1263  *              the timestamp of the previous sample.
1264  * @curr_string String displayed at the beginning of current sample stats.
1265  *              This is the timestamp of the current sample.
1266  * @itv         Interval of time in jiffies.
1267  * @deltot_jiffies
1268  *              Number of jiffies spent on the interval by all processors.
1269  *
1270  * RETURNS:
1271  * 0 if all the processes to display have terminated.
1272  * <> 0 if there are still some processes left to display.
1273  ***************************************************************************
1274  */
1275 int write_pid_task_all_stats(int prev, int curr, int dis,
1276                              char *prev_string, char *curr_string,
1277                              unsigned long long itv,
1278                              unsigned long long deltot_jiffies)
1279 {
1280         struct pid_stats *pstc, *pstp;
1281         struct st_pid *plist;
1282         char dstr[32];
1283         int again = 0;
1284
1285         if (dis) {
1286                 PRINT_ID_HDR(prev_string, pidflag);
1287                 if (DISPLAY_CPU(actflag)) {
1288                         printf("    %%usr %%system  %%guest   %%wait    %%CPU   CPU");
1289                 }
1290                 if (DISPLAY_MEM(actflag)) {
1291                         printf("  minflt/s  majflt/s     VSZ     RSS   %%MEM");
1292                 }
1293                 if (DISPLAY_STACK(actflag)) {
1294                         printf(" StkSize  StkRef");
1295                 }
1296                 if (DISPLAY_IO(actflag)) {
1297                         printf("   kB_rd/s   kB_wr/s kB_ccwr/s iodelay");
1298                 }
1299                 if (DISPLAY_CTXSW(actflag)) {
1300                         printf("   cswch/s nvcswch/s");
1301                 }
1302                 if (DISPLAY_KTAB(actflag)) {
1303                         printf(" threads   fd-nr");
1304                 }
1305                 if (DISPLAY_RT(actflag)) {
1306                         printf(" prio policy");
1307                 }
1308                 printf("  Command\n");
1309         }
1310
1311         for (plist = pid_list; plist != NULL; plist = plist->next) {
1312
1313                 if (get_pid_to_display(prev, curr, actflag, P_TASK, plist) <= 0)
1314                         continue;
1315
1316                 print_line_id(curr_string, plist);
1317
1318                 pstc = plist->pstats[curr];
1319                 pstp = plist->pstats[prev];
1320
1321                 if (DISPLAY_CPU(actflag)) {
1322                         cprintf_pc(DISPLAY_UNIT(pidflag), 5, 7, 2,
1323                                    (pstc->utime - pstc->gtime) < (pstp->utime - pstp->gtime) ?
1324                                    0.0 :
1325                                    SP_VALUE(pstp->utime - pstp->gtime,
1326                                             pstc->utime - pstc->gtime, itv * HZ / 100),
1327                                    SP_VALUE(pstp->stime,  pstc->stime, itv * HZ / 100),
1328                                    SP_VALUE(pstp->gtime,  pstc->gtime, itv * HZ / 100),
1329                                    SP_VALUE(pstp->wtime,  pstc->wtime, itv * HZ / 100),
1330                                    /* User time already includes guest time */
1331                                    IRIX_MODE_OFF(pidflag) ?
1332                                    SP_VALUE(pstp->utime + pstp->stime,
1333                                             pstc->utime + pstc->stime, deltot_jiffies) :
1334                                    SP_VALUE(pstp->utime + pstp->stime,
1335                                             pstc->utime + pstc->stime, itv * HZ / 100));
1336
1337                         cprintf_in(IS_INT, "   %3d", "", pstc->processor);
1338                 }
1339
1340                 if (DISPLAY_MEM(actflag)) {
1341                         cprintf_f(NO_UNIT, 2, 9, 2,
1342                                   S_VALUE(pstp->minflt, pstc->minflt, itv),
1343                                   S_VALUE(pstp->majflt, pstc->majflt, itv));
1344                         cprintf_u64(DISPLAY_UNIT(pidflag) ? UNIT_KILOBYTE : NO_UNIT, 2, 7,
1345                                     (unsigned long long) pstc->vsz,
1346                                     (unsigned long long) pstc->rss);
1347                         cprintf_pc(DISPLAY_UNIT(pidflag), 1, 6, 2,
1348                                    tlmkb ? SP_VALUE(0, pstc->rss, tlmkb) : 0.0);
1349                 }
1350
1351                 if (DISPLAY_STACK(actflag)) {
1352                         cprintf_u64(DISPLAY_UNIT(pidflag) ? UNIT_KILOBYTE : NO_UNIT, 2, 7,
1353                                     (unsigned long long) pstc->stack_size,
1354                                     (unsigned long long) pstc->stack_ref);
1355                 }
1356
1357                 if (DISPLAY_IO(actflag)) {
1358                         if (!NO_PID_IO(plist->flags))
1359                         {
1360                                 double rbytes, wbytes, cbytes;
1361
1362                                 rbytes = S_VALUE(pstp->read_bytes,  pstc->read_bytes, itv);
1363                                 wbytes = S_VALUE(pstp->write_bytes, pstc->write_bytes, itv);
1364                                 cbytes = S_VALUE(pstp->cancelled_write_bytes,
1365                                                  pstc->cancelled_write_bytes, itv);
1366                                 if (!DISPLAY_UNIT(pidflag)) {
1367                                         rbytes /= 1024;
1368                                         wbytes /= 1024;
1369                                         cbytes /= 1024;
1370                                 }
1371                                 cprintf_f(DISPLAY_UNIT(pidflag) ? UNIT_BYTE : NO_UNIT, 3, 9, 2,
1372                                           rbytes, wbytes, cbytes);
1373                         }
1374                         else {
1375                                 /*
1376                                  * Keep the layout even though this task has no I/O
1377                                  * typically threads with no I/O measurements.
1378                                  */
1379                                 sprintf(dstr, " %9.2f %9.2f %9.2f", -1.0, -1.0, -1.0);
1380                                 cprintf_s(IS_ZERO, "%s", dstr);
1381                         }
1382                         /* I/O delays come from another file (/proc/#/stat) */
1383                         cprintf_u64(NO_UNIT, 1, 7,
1384                                     (unsigned long long) (pstc->blkio_swapin_delays - pstp->blkio_swapin_delays));
1385                 }
1386
1387                 if (DISPLAY_CTXSW(actflag)) {
1388                         cprintf_f(NO_UNIT, 2, 9, 2,
1389                                   S_VALUE(pstp->nvcsw, pstc->nvcsw, itv),
1390                                   S_VALUE(pstp->nivcsw, pstc->nivcsw, itv));
1391                 }
1392
1393                 if (DISPLAY_KTAB(actflag)) {
1394                         cprintf_u64(NO_UNIT, 1, 7,
1395                                     (unsigned long long) pstc->threads);
1396                         if (NO_PID_FD(plist->flags)) {
1397                                 /* /proc/#/fd directory not readable */
1398                                 cprintf_s(IS_ZERO, " %7s", "-1");
1399                         }
1400                         else {
1401                                 cprintf_u64(NO_UNIT, 1, 7, (unsigned long long) pstc->fd_nr);
1402                         }
1403                 }
1404
1405                 if (DISPLAY_RT(actflag)) {
1406                         cprintf_u64(NO_UNIT, 1, 4,
1407                                     (unsigned long long) pstc->priority);
1408                         cprintf_s(IS_STR, " %6s",
1409                                   GET_POLICY(pstc->policy));
1410                 }
1411
1412                 print_comm(plist);
1413                 again = 1;
1414         }
1415
1416         return again;
1417 }
1418
1419 /*
1420  ***************************************************************************
1421  * Display all statistics for tasks' children in one line format.
1422  *
1423  * IN:
1424  * @prev        Index in array where stats used as reference are.
1425  * @curr        Index in array for current sample statistics.
1426  * @dis         TRUE if a header line must be printed.
1427  * @prev_string String displayed at the beginning of a header line. This is
1428  *              the timestamp of the previous sample.
1429  * @curr_string String displayed at the beginning of current sample stats.
1430  *              This is the timestamp of the current sample.
1431  *
1432  * RETURNS:
1433  * 0 if all the processes to display have terminated.
1434  * <> 0 if there are still some processes left to display.
1435  ***************************************************************************
1436  */
1437 int write_pid_child_all_stats(int prev, int curr, int dis,
1438                               char *prev_string, char *curr_string)
1439 {
1440         struct pid_stats *pstc, *pstp;
1441         struct st_pid *plist;
1442         int again = 0;
1443
1444         if (dis) {
1445                 PRINT_ID_HDR(prev_string, pidflag);
1446                 if (DISPLAY_CPU(actflag))
1447                         printf("    usr-ms system-ms  guest-ms");
1448                 if (DISPLAY_MEM(actflag))
1449                         printf(" minflt-nr majflt-nr");
1450                 printf("  Command\n");
1451         }
1452
1453         for (plist = pid_list; plist != NULL; plist = plist->next) {
1454
1455                 if (get_pid_to_display(prev, curr, actflag, P_CHILD, plist) <= 0)
1456                         continue;
1457
1458                 print_line_id(curr_string, plist);
1459
1460                 pstc = plist->pstats[curr];
1461                 pstp = plist->pstats[prev];
1462
1463                 if (DISPLAY_CPU(actflag)) {
1464                         cprintf_f(NO_UNIT, 3, 9, 0,
1465                                   (pstc->utime + pstc->cutime - pstc->gtime - pstc->cgtime) <
1466                                   (pstp->utime + pstp->cutime - pstp->gtime - pstp->cgtime) ?
1467                                   0.0 :
1468                                   (double) ((pstc->utime + pstc->cutime - pstc->gtime - pstc->cgtime) -
1469                                             (pstp->utime + pstp->cutime - pstp->gtime - pstp->cgtime)) /
1470                                             HZ * 1000,
1471                                   (double) ((pstc->stime + pstc->cstime) -
1472                                             (pstp->stime + pstp->cstime)) / HZ * 1000,
1473                                   (double) ((pstc->gtime + pstc->cgtime) -
1474                                             (pstp->gtime + pstp->cgtime)) / HZ * 1000);
1475                 }
1476
1477                 if (DISPLAY_MEM(actflag)) {
1478                         cprintf_u64(NO_UNIT, 2, 9,
1479                                     (unsigned long long) ((pstc->minflt + pstc->cminflt) - (pstp->minflt + pstp->cminflt)),
1480                                     (unsigned long long) ((pstc->majflt + pstc->cmajflt) - (pstp->majflt + pstp->cmajflt)));
1481                 }
1482
1483                 print_comm(plist);
1484                 again = 1;
1485         }
1486
1487         return again;
1488 }
1489
1490 /*
1491  ***************************************************************************
1492  * Display CPU statistics for tasks.
1493  *
1494  * IN:
1495  * @prev        Index in array where stats used as reference are.
1496  * @curr        Index in array for current sample statistics.
1497  * @dis         TRUE if a header line must be printed.
1498  * @disp_avg    TRUE if average stats are displayed.
1499  * @prev_string String displayed at the beginning of a header line. This is
1500  *              the timestamp of the previous sample, or "Average" when
1501  *              displaying average stats.
1502  * @curr_string String displayed at the beginning of current sample stats.
1503  *              This is the timestamp of the current sample, or "Average"
1504  *              when displaying average stats.
1505  * @itv         Interval of time in 1/100th of a second.
1506  * @deltot_jiffies
1507  *              Number of jiffies spent on the interval by all processors.
1508  *
1509  * RETURNS:
1510  * 0 if all the processes to display have terminated.
1511  * <> 0 if there are still some processes left to display.
1512  ***************************************************************************
1513  */
1514 int write_pid_task_cpu_stats(int prev, int curr, int dis, int disp_avg,
1515                              char *prev_string, char *curr_string,
1516                              unsigned long long itv,
1517                              unsigned long long deltot_jiffies)
1518 {
1519         struct pid_stats *pstc, *pstp;
1520         struct st_pid *plist;
1521         int again = 0;
1522
1523         if (dis) {
1524                 PRINT_ID_HDR(prev_string, pidflag);
1525                 printf("    %%usr %%system  %%guest   %%wait    %%CPU   CPU  Command\n");
1526         }
1527
1528         for (plist = pid_list; plist != NULL; plist = plist->next) {
1529
1530                 if (get_pid_to_display(prev, curr, P_A_CPU, P_TASK, plist) <= 0)
1531                         continue;
1532
1533                 print_line_id(curr_string, plist);
1534
1535                 pstc = plist->pstats[curr];
1536                 pstp = plist->pstats[prev];
1537
1538                 cprintf_pc(DISPLAY_UNIT(pidflag), 5, 7, 2,
1539                            (pstc->utime - pstc->gtime) < (pstp->utime - pstp->gtime) ?
1540                            0.0 :
1541                            SP_VALUE(pstp->utime - pstp->gtime,
1542                                     pstc->utime - pstc->gtime, itv * HZ / 100),
1543                            SP_VALUE(pstp->stime, pstc->stime, itv * HZ / 100),
1544                            SP_VALUE(pstp->gtime, pstc->gtime, itv * HZ / 100),
1545                            SP_VALUE(pstp->wtime, pstc->wtime, itv * HZ / 100),
1546                            /* User time already includes guest time */
1547                            IRIX_MODE_OFF(pidflag) ?
1548                            SP_VALUE(pstp->utime + pstp->stime,
1549                                     pstc->utime + pstc->stime, deltot_jiffies) :
1550                            SP_VALUE(pstp->utime + pstp->stime,
1551                                     pstc->utime + pstc->stime, itv * HZ / 100));
1552
1553                 if (!disp_avg) {
1554                         cprintf_in(IS_INT, "   %3d", "", pstc->processor);
1555                 }
1556                 else {
1557                         cprintf_in(IS_STR, "%s", "     -", 0);
1558                 }
1559                 print_comm(plist);
1560                 again = 1;
1561         }
1562
1563         return again;
1564 }
1565
1566 /*
1567  ***************************************************************************
1568  * Display CPU statistics for tasks' children.
1569  *
1570  * IN:
1571  * @prev        Index in array where stats used as reference are.
1572  * @curr        Index in array for current sample statistics.
1573  * @dis         TRUE if a header line must be printed.
1574  * @disp_avg    TRUE if average stats are displayed.
1575  * @prev_string String displayed at the beginning of a header line. This is
1576  *              the timestamp of the previous sample, or "Average" when
1577  *              displaying average stats.
1578  * @curr_string String displayed at the beginning of current sample stats.
1579  *              This is the timestamp of the current sample, or "Average"
1580  *              when displaying average stats.
1581  *
1582  * RETURNS:
1583  * 0 if all the processes to display have terminated.
1584  * <> 0 if there are still some processes left to display.
1585  ***************************************************************************
1586  */
1587 int write_pid_child_cpu_stats(int prev, int curr, int dis, int disp_avg,
1588                               char *prev_string, char *curr_string)
1589 {
1590         struct pid_stats *pstc, *pstp;
1591         struct st_pid *plist;
1592         int rc, again = 0;
1593
1594         if (dis) {
1595                 PRINT_ID_HDR(prev_string, pidflag);
1596                 printf("    usr-ms system-ms  guest-ms  Command\n");
1597         }
1598
1599         for (plist = pid_list; plist != NULL; plist = plist->next) {
1600
1601                 if ((rc = get_pid_to_display(prev, curr, P_A_CPU, P_CHILD, plist)) == 0)
1602                         /* PID no longer exists */
1603                         continue;
1604
1605                 /* This will be used to compute average */
1606                 if (!disp_avg) {
1607                         plist->uc_asum_count += 1;
1608                 }
1609
1610                 if (rc < 0)
1611                         /* PID should not be displayed */
1612                         continue;
1613
1614                 print_line_id(curr_string, plist);
1615
1616                 pstc = plist->pstats[curr];
1617                 pstp = plist->pstats[prev];
1618
1619                 if (disp_avg) {
1620                         cprintf_f(NO_UNIT, 3, 9, 0,
1621                                   (pstc->utime + pstc->cutime - pstc->gtime - pstc->cgtime) <
1622                                   (pstp->utime + pstp->cutime - pstp->gtime - pstp->cgtime) ?
1623                                   0.0 :
1624                                   (double) ((pstc->utime + pstc->cutime - pstc->gtime - pstc->cgtime) -
1625                                             (pstp->utime + pstp->cutime - pstp->gtime - pstp->cgtime)) /
1626                                             (HZ * plist->uc_asum_count) * 1000,
1627                                   (double) ((pstc->stime + pstc->cstime) -
1628                                             (pstp->stime + pstp->cstime)) /
1629                                             (HZ * plist->uc_asum_count) * 1000,
1630                                   (double) ((pstc->gtime + pstc->cgtime) -
1631                                             (pstp->gtime + pstp->cgtime)) /
1632                                             (HZ * plist->uc_asum_count) * 1000);
1633                 }
1634                 else {
1635                         cprintf_f(NO_UNIT, 3, 9, 0,
1636                                   (pstc->utime + pstc->cutime - pstc->gtime - pstc->cgtime) <
1637                                   (pstp->utime + pstp->cutime - pstp->gtime - pstp->cgtime) ?
1638                                   0.0 :
1639                                   (double) ((pstc->utime + pstc->cutime - pstc->gtime - pstc->cgtime) -
1640                                             (pstp->utime + pstp->cutime - pstp->gtime - pstp->cgtime)) /
1641                                             HZ * 1000,
1642                                   (double) ((pstc->stime + pstc->cstime) -
1643                                             (pstp->stime + pstp->cstime)) / HZ * 1000,
1644                                   (double) ((pstc->gtime + pstc->cgtime) -
1645                                             (pstp->gtime + pstp->cgtime)) / HZ * 1000);
1646                 }
1647                 print_comm(plist);
1648                 again = 1;
1649         }
1650
1651         return again;
1652 }
1653
1654 /*
1655  ***************************************************************************
1656  * Display memory statistics for tasks.
1657  *
1658  * IN:
1659  * @prev        Index in array where stats used as reference are.
1660  * @curr        Index in array for current sample statistics.
1661  * @dis         TRUE if a header line must be printed.
1662  * @disp_avg    TRUE if average stats are displayed.
1663  * @prev_string String displayed at the beginning of a header line. This is
1664  *              the timestamp of the previous sample, or "Average" when
1665  *              displaying average stats.
1666  * @curr_string String displayed at the beginning of current sample stats.
1667  *              This is the timestamp of the current sample, or "Average"
1668  *              when displaying average stats.
1669  * @itv         Interval of time in 1/100th of a second.
1670  *
1671  * RETURNS:
1672  * 0 if all the processes to display have terminated.
1673  * <> 0 if there are still some processes left to display.
1674  ***************************************************************************
1675  */
1676 int write_pid_task_memory_stats(int prev, int curr, int dis, int disp_avg,
1677                                 char *prev_string, char *curr_string,
1678                                 unsigned long long itv)
1679 {
1680         struct pid_stats *pstc, *pstp;
1681         struct st_pid *plist;
1682         int rc, again = 0;
1683
1684         if (dis) {
1685                 PRINT_ID_HDR(prev_string, pidflag);
1686                 printf("  minflt/s  majflt/s     VSZ     RSS   %%MEM  Command\n");
1687         }
1688
1689         for (plist = pid_list; plist != NULL; plist = plist->next) {
1690
1691                 if ((rc = get_pid_to_display(prev, curr, P_A_MEM, P_TASK, plist)) == 0)
1692                         /* PID no longer exists */
1693                         continue;
1694
1695                 pstc = plist->pstats[curr];
1696                 pstp = plist->pstats[prev];
1697
1698                 /* This will be used to compute average */
1699                 if (!disp_avg) {
1700                         plist->total_vsz += pstc->vsz;
1701                         plist->total_rss += pstc->rss;
1702                         plist->rt_asum_count += 1;
1703                 }
1704
1705                 if (rc < 0)
1706                         /* PID should not be displayed */
1707                         continue;
1708
1709                 print_line_id(curr_string, plist);
1710
1711                 cprintf_f(NO_UNIT, 2, 9, 2,
1712                           S_VALUE(pstp->minflt, pstc->minflt, itv),
1713                           S_VALUE(pstp->majflt, pstc->majflt, itv));
1714
1715                 if (disp_avg) {
1716                         cprintf_f(DISPLAY_UNIT(pidflag) ? UNIT_KILOBYTE : NO_UNIT, 2, 7, 0,
1717                                   (double) plist->total_vsz / plist->rt_asum_count,
1718                                   (double) plist->total_rss / plist->rt_asum_count);
1719
1720                         cprintf_pc(DISPLAY_UNIT(pidflag), 1, 6, 2,
1721                                    tlmkb ?
1722                                    SP_VALUE(0, plist->total_rss / plist->rt_asum_count, tlmkb)
1723                                    : 0.0);
1724                 }
1725                 else {
1726                         cprintf_u64(DISPLAY_UNIT(pidflag) ? UNIT_KILOBYTE : NO_UNIT, 2, 7,
1727                                     (unsigned long long) pstc->vsz,
1728                                     (unsigned long long) pstc->rss);
1729
1730                         cprintf_pc(DISPLAY_UNIT(pidflag), 1, 6, 2,
1731                                    tlmkb ? SP_VALUE(0, pstc->rss, tlmkb) : 0.0);
1732                 }
1733
1734                 print_comm(plist);
1735                 again = 1;
1736         }
1737
1738         return again;
1739 }
1740
1741 /*
1742  ***************************************************************************
1743  * Display memory statistics for tasks' children.
1744  *
1745  * IN:
1746  * @prev        Index in array where stats used as reference are.
1747  * @curr        Index in array for current sample statistics.
1748  * @dis         TRUE if a header line must be printed.
1749  * @disp_avg    TRUE if average stats are displayed.
1750  * @prev_string String displayed at the beginning of a header line. This is
1751  *              the timestamp of the previous sample, or "Average" when
1752  *              displaying average stats.
1753  * @curr_string String displayed at the beginning of current sample stats.
1754  *              This is the timestamp of the current sample, or "Average"
1755  *              when displaying average stats.
1756  *
1757  * RETURNS:
1758  * 0 if all the processes to display have terminated.
1759  * <> 0 if there are still some processes left to display.
1760  ***************************************************************************
1761  */
1762 int write_pid_child_memory_stats(int prev, int curr, int dis, int disp_avg,
1763                                  char *prev_string, char *curr_string)
1764 {
1765         struct pid_stats *pstc, *pstp;
1766         struct st_pid *plist;
1767         int rc, again = 0;
1768
1769         if (dis) {
1770                 PRINT_ID_HDR(prev_string, pidflag);
1771                 printf(" minflt-nr majflt-nr  Command\n");
1772         }
1773
1774         for (plist = pid_list; plist != NULL; plist = plist->next) {
1775
1776                 if ((rc = get_pid_to_display(prev, curr, P_A_MEM, P_CHILD, plist)) == 0)
1777                         /* PID no longer exists */
1778                         continue;
1779
1780                 /* This will be used to compute average */
1781                 if (!disp_avg) {
1782                         plist->rc_asum_count += 1;
1783                 }
1784
1785                 if (rc < 0)
1786                         /* PID should not be displayed */
1787                         continue;
1788
1789                 print_line_id(curr_string, plist);
1790
1791                 pstc = plist->pstats[curr];
1792                 pstp = plist->pstats[prev];
1793
1794                 if (disp_avg) {
1795                         cprintf_f(NO_UNIT, 2, 9, 0,
1796                                   (double) ((pstc->minflt + pstc->cminflt) -
1797                                             (pstp->minflt + pstp->cminflt)) / plist->rc_asum_count,
1798                                   (double) ((pstc->majflt + pstc->cmajflt) -
1799                                             (pstp->majflt + pstp->cmajflt)) / plist->rc_asum_count);
1800                 }
1801                 else {
1802                         cprintf_u64(NO_UNIT, 2, 9,
1803                                     (unsigned long long) ((pstc->minflt + pstc->cminflt) - (pstp->minflt + pstp->cminflt)),
1804                     (unsigned long long) ((pstc->majflt + pstc->cmajflt) - (pstp->majflt + pstp->cmajflt)));
1805                 }
1806                 print_comm(plist);
1807                 again = 1;
1808         }
1809
1810         return again;
1811 }
1812
1813 /*
1814  ***************************************************************************
1815  * Display stack size statistics for tasks.
1816  *
1817  * IN:
1818  * @prev        Index in array where stats used as reference are.
1819  * @curr        Index in array for current sample statistics.
1820  * @dis         TRUE if a header line must be printed.
1821  * @disp_avg    TRUE if average stats are displayed.
1822  * @prev_string String displayed at the beginning of a header line. This is
1823  *              the timestamp of the previous sample, or "Average" when
1824  *              displaying average stats.
1825  * @curr_string String displayed at the beginning of current sample stats.
1826  *              This is the timestamp of the current sample, or "Average"
1827  *              when displaying average stats.
1828  *
1829  * RETURNS:
1830  * 0 if all the processes to display have terminated.
1831  * <> 0 if there are still some processes left to display.
1832  ***************************************************************************
1833  */
1834 int write_pid_stack_stats(int prev, int curr, int dis, int disp_avg,
1835                           char *prev_string, char *curr_string)
1836 {
1837         struct pid_stats *pstc;
1838         struct st_pid *plist;
1839         int rc, again = 0;
1840
1841         if (dis) {
1842                 PRINT_ID_HDR(prev_string, pidflag);
1843                 printf(" StkSize  StkRef  Command\n");
1844         }
1845
1846         for (plist = pid_list; plist != NULL; plist = plist->next) {
1847
1848                 if ((rc = get_pid_to_display(prev, curr, P_A_STACK, P_NULL, plist)) == 0)
1849                         /* PID no longer exists */
1850                         continue;
1851
1852                 pstc = plist->pstats[curr];
1853
1854                 /* This will be used to compute average */
1855                 if (!disp_avg) {
1856                         plist->total_stack_size += pstc->stack_size;
1857                         plist->total_stack_ref  += pstc->stack_ref;
1858                         plist->sk_asum_count += 1;
1859                 }
1860
1861                 if (rc < 0)
1862                         /* PID should not be displayed */
1863                         continue;
1864
1865                 print_line_id(curr_string, plist);
1866
1867                 if (disp_avg) {
1868                         cprintf_f(DISPLAY_UNIT(pidflag) ? UNIT_KILOBYTE : NO_UNIT, 2, 7, 0,
1869                                   (double) plist->total_stack_size / plist->sk_asum_count,
1870                                   (double) plist->total_stack_ref  / plist->sk_asum_count);
1871                 }
1872                 else {
1873                         cprintf_u64(DISPLAY_UNIT(pidflag) ? UNIT_KILOBYTE : NO_UNIT, 2, 7,
1874                                     (unsigned long long) pstc->stack_size,
1875                                     (unsigned long long) pstc->stack_ref);
1876                 }
1877
1878                 print_comm(plist);
1879                 again = 1;
1880         }
1881
1882         return again;
1883 }
1884
1885 /*
1886  ***************************************************************************
1887  * Display I/O statistics.
1888  *
1889  * IN:
1890  * @prev        Index in array where stats used as reference are.
1891  * @curr        Index in array for current sample statistics.
1892  * @dis         TRUE if a header line must be printed.
1893  * @disp_avg    TRUE if average stats are displayed.
1894  * @prev_string String displayed at the beginning of a header line. This is
1895  *              the timestamp of the previous sample, or "Average" when
1896  *              displaying average stats.
1897  * @curr_string String displayed at the beginning of current sample stats.
1898  *              This is the timestamp of the current sample, or "Average"
1899  *              when displaying average stats.
1900  * @itv         Interval of time in 1/100th of a second.
1901  *
1902  * RETURNS:
1903  * 0 if all the processes to display have terminated.
1904  * <> 0 if there are still some processes left to display.
1905  ***************************************************************************
1906  */
1907 int write_pid_io_stats(int prev, int curr, int dis, int disp_avg,
1908                        char *prev_string, char *curr_string,
1909                        unsigned long long itv)
1910 {
1911         struct pid_stats *pstc, *pstp;
1912         struct st_pid *plist;
1913         char dstr[32];
1914         int rc, again = 0;
1915         double rbytes, wbytes, cbytes;
1916
1917         if (dis) {
1918                 PRINT_ID_HDR(prev_string, pidflag);
1919                 printf("   kB_rd/s   kB_wr/s kB_ccwr/s iodelay  Command\n");
1920         }
1921
1922         for (plist = pid_list; plist != NULL; plist = plist->next) {
1923
1924                 if ((rc = get_pid_to_display(prev, curr, P_A_IO, P_NULL, plist)) == 0)
1925                         /* PID no longer exists */
1926                         continue;
1927
1928                 /* This will be used to compute average delays */
1929                 if (!disp_avg) {
1930                         plist->delay_asum_count += 1;
1931                 }
1932
1933                 if (rc < 0)
1934                         /* PID should not be displayed */
1935                         continue;
1936
1937                 print_line_id(curr_string, plist);
1938
1939                 pstc = plist->pstats[curr];
1940                 pstp = plist->pstats[prev];
1941
1942                 if (!NO_PID_IO(plist->flags)) {
1943                         rbytes = S_VALUE(pstp->read_bytes,  pstc->read_bytes, itv);
1944                         wbytes = S_VALUE(pstp->write_bytes, pstc->write_bytes, itv);
1945                         cbytes = S_VALUE(pstp->cancelled_write_bytes,
1946                                          pstc->cancelled_write_bytes, itv);
1947                         if (!DISPLAY_UNIT(pidflag)) {
1948                                 rbytes /= 1024;
1949                                 wbytes /= 1024;
1950                                 cbytes /= 1024;
1951                         }
1952                         cprintf_f(DISPLAY_UNIT(pidflag) ? UNIT_BYTE : NO_UNIT, 3, 9, 2,
1953                                   rbytes, wbytes, cbytes);
1954                 }
1955                 else {
1956                         /* I/O file not readable (permission denied or file non existent) */
1957                         sprintf(dstr, " %9.2f %9.2f %9.2f", -1.0, -1.0, -1.0);
1958                         cprintf_s(IS_ZERO, "%s", dstr);
1959                 }
1960                 /* I/O delays come from another file (/proc/#/stat) */
1961                 if (disp_avg) {
1962                         cprintf_f(NO_UNIT, 1, 7, 0,
1963                                   (double) (pstc->blkio_swapin_delays - pstp->blkio_swapin_delays) /
1964                                             plist->delay_asum_count);
1965                 }
1966                 else {
1967                         cprintf_u64(NO_UNIT, 1, 7,
1968                                     (unsigned long long) (pstc->blkio_swapin_delays - pstp->blkio_swapin_delays));
1969                 }
1970
1971                 print_comm(plist);
1972                 again = 1;
1973         }
1974
1975         return again;
1976 }
1977
1978 /*
1979  ***************************************************************************
1980  * Display context switches statistics.
1981  *
1982  * IN:
1983  * @prev        Index in array where stats used as reference are.
1984  * @curr        Index in array for current sample statistics.
1985  * @dis         TRUE if a header line must be printed.
1986  * @prev_string String displayed at the beginning of a header line. This is
1987  *              the timestamp of the previous sample, or "Average" when
1988  *              displaying average stats.
1989  * @curr_string String displayed at the beginning of current sample stats.
1990  *              This is the timestamp of the current sample, or "Average"
1991  *              when displaying average stats.
1992  * @itv         Interval of time in 1/100th of a second.
1993  *
1994  * RETURNS:
1995  * 0 if all the processes to display have terminated.
1996  * <> 0 if there are still some processes left to display.
1997  ***************************************************************************
1998  */
1999 int write_pid_ctxswitch_stats(int prev, int curr, int dis,
2000                               char *prev_string, char *curr_string,
2001                               unsigned long long itv)
2002 {
2003         struct pid_stats *pstc, *pstp;
2004         struct st_pid *plist;
2005         int again = 0;
2006
2007         if (dis) {
2008                 PRINT_ID_HDR(prev_string, pidflag);
2009                 printf("   cswch/s nvcswch/s  Command\n");
2010         }
2011
2012         for (plist = pid_list; plist != NULL; plist = plist->next) {
2013
2014                 if (get_pid_to_display(prev, curr, P_A_CTXSW, P_NULL, plist) <= 0)
2015                         continue;
2016
2017                 print_line_id(curr_string, plist);
2018
2019                 pstc = plist->pstats[curr];
2020                 pstp = plist->pstats[prev];
2021
2022                 cprintf_f(NO_UNIT, 2, 9, 2,
2023                           S_VALUE(pstp->nvcsw,  pstc->nvcsw,  itv),
2024                           S_VALUE(pstp->nivcsw, pstc->nivcsw, itv));
2025
2026                 print_comm(plist);
2027                 again = 1;
2028         }
2029
2030         return again;
2031 }
2032
2033 /*
2034  ***************************************************************************
2035  * Display scheduling priority and policy information.
2036  *
2037  * IN:
2038  * @prev        Index in array where stats used as reference are.
2039  * @curr        Index in array for current sample statistics.
2040  * @dis         TRUE if a header line must be printed.
2041  * @prev_string String displayed at the beginning of a header line. This is
2042  *              the timestamp of the previous sample, or "Average" when
2043  *              displaying average stats.
2044  * @curr_string String displayed at the beginning of current sample stats.
2045  *              This is the timestamp of the current sample, or "Average"
2046  *              when displaying average stats.
2047  *
2048  * RETURNS:
2049  * 0 if all the processes to display have terminated.
2050  * <> 0 if there are still some processes left to display.
2051  ***************************************************************************
2052  */
2053 int write_pid_rt_stats(int prev, int curr, int dis,
2054                        char *prev_string, char *curr_string)
2055 {
2056         struct pid_stats *pstc;
2057         struct st_pid *plist;
2058         int again = 0;
2059
2060         if (dis) {
2061                 PRINT_ID_HDR(prev_string, pidflag);
2062                 printf(" prio policy  Command\n");
2063         }
2064
2065         for (plist = pid_list; plist != NULL; plist = plist->next) {
2066
2067                 if (get_pid_to_display(prev, curr, P_A_RT, P_NULL, plist) <= 0)
2068                         continue;
2069
2070                 print_line_id(curr_string, plist);
2071
2072                 pstc = plist->pstats[curr];
2073
2074                 cprintf_u64(NO_UNIT, 1, 4,
2075                             (unsigned long long) pstc->priority);
2076                 cprintf_s(IS_STR, " %6s", GET_POLICY(pstc->policy));
2077
2078                 print_comm(plist);
2079                 again = 1;
2080         }
2081
2082         return again;
2083 }
2084
2085 /*
2086  ***************************************************************************
2087  * Display some kernel tables values for tasks.
2088  *
2089  * IN:
2090  * @prev        Index in array where stats used as reference are.
2091  * @curr        Index in array for current sample statistics.
2092  * @dis         TRUE if a header line must be printed.
2093  * @disp_avg    TRUE if average stats are displayed.
2094  * @prev_string String displayed at the beginning of a header line. This is
2095  *              the timestamp of the previous sample, or "Average" when
2096  *              displaying average stats.
2097  * @curr_string String displayed at the beginning of current sample stats.
2098  *              This is the timestamp of the current sample, or "Average"
2099  *              when displaying average stats.
2100  *
2101  * RETURNS:
2102  * 0 if all the processes to display have terminated.
2103  * <> 0 if there are still some processes left to display.
2104  ***************************************************************************
2105  */
2106 int write_pid_ktab_stats(int prev, int curr, int dis, int disp_avg,
2107                          char *prev_string, char *curr_string)
2108 {
2109         struct pid_stats *pstc;
2110         struct st_pid *plist;
2111         int rc, again = 0;
2112
2113         if (dis) {
2114                 PRINT_ID_HDR(prev_string, pidflag);
2115                 printf(" threads   fd-nr");
2116                 printf("  Command\n");
2117         }
2118
2119         for (plist = pid_list; plist != NULL; plist = plist->next) {
2120
2121                 if ((rc = get_pid_to_display(prev, curr, P_A_KTAB, P_NULL, plist)) == 0)
2122                         /* PID no longer exists */
2123                         continue;
2124
2125                 pstc = plist->pstats[curr];
2126
2127                 /* This will be used to compute average */
2128                 if (!disp_avg) {
2129                         plist->total_threads += pstc->threads;
2130                         plist->total_fd_nr   += pstc->fd_nr;
2131                         plist->tf_asum_count += 1;
2132                 }
2133
2134                 if (rc < 0)
2135                         /* PID should not be displayed */
2136                         continue;
2137
2138                 print_line_id(curr_string, plist);
2139
2140                 if (disp_avg) {
2141                         cprintf_f(NO_UNIT, 2, 7, 0,
2142                                   (double) plist->total_threads / plist->tf_asum_count,
2143                                   NO_PID_FD(plist->flags) ?
2144                                   -1.0 :
2145                                   (double) plist->total_fd_nr / plist->tf_asum_count);
2146                 }
2147                 else {
2148                         cprintf_u64(NO_UNIT, 1, 7,
2149                                     (unsigned long long) pstc->threads);
2150                         if (NO_PID_FD(plist->flags)) {
2151                                 cprintf_s(IS_ZERO, " %7s", "-1");
2152                         }
2153                         else {
2154                                 cprintf_u64(NO_UNIT, 1, 7,
2155                                             (unsigned long long) pstc->fd_nr);
2156                         }
2157                 }
2158
2159                 print_comm(plist);
2160                 again = 1;
2161         }
2162
2163         return again;
2164 }
2165
2166 /*
2167  ***************************************************************************
2168  * Display statistics.
2169  *
2170  * IN:
2171  * @prev        Index in array where stats used as reference are.
2172  * @curr        Index in array for current sample statistics.
2173  * @dis         TRUE if a header line must be printed.
2174  * @disp_avg    TRUE if average stats are displayed.
2175  * @prev_string String displayed at the beginning of a header line. This is
2176  *              the timestamp of the previous sample, or "Average" when
2177  *              displaying average stats.
2178  * @curr_string String displayed at the beginning of current sample stats.
2179  *              This is the timestamp of the current sample, or "Average"
2180  *              when displaying average stats.
2181  *
2182  * RETURNS:
2183  * 0 if all the processes to display have terminated.
2184  * <> 0 if there are still some processes left to display.
2185  ***************************************************************************
2186  */
2187 int write_stats_core(int prev, int curr, int dis, int disp_avg,
2188                      char *prev_string, char *curr_string)
2189 {
2190         unsigned long long itv, deltot_jiffies;
2191         int again = 0;
2192
2193         /* Test stdout */
2194         TEST_STDOUT(STDOUT_FILENO);
2195
2196         /* Total number of jiffies spent on the interval */
2197         deltot_jiffies = get_interval(tot_jiffies[prev], tot_jiffies[curr]);
2198
2199         itv = get_interval(uptime_cs[prev], uptime_cs[curr]);
2200
2201         if (DISPLAY_ONELINE(pidflag)) {
2202                 if (DISPLAY_TASK_STATS(tskflag)) {
2203                         again += write_pid_task_all_stats(prev, curr, dis, prev_string, curr_string,
2204                                                           itv, deltot_jiffies);
2205                 }
2206                 if (DISPLAY_CHILD_STATS(tskflag)) {
2207                         again += write_pid_child_all_stats(prev, curr, dis, prev_string, curr_string);
2208                 }
2209         }
2210         else {
2211                 /* Display CPU stats */
2212                 if (DISPLAY_CPU(actflag)) {
2213
2214                         if (DISPLAY_TASK_STATS(tskflag)) {
2215                                 again += write_pid_task_cpu_stats(prev, curr, dis, disp_avg,
2216                                                                   prev_string, curr_string,
2217                                                                   itv, deltot_jiffies);
2218                         }
2219                         if (DISPLAY_CHILD_STATS(tskflag)) {
2220                                 again += write_pid_child_cpu_stats(prev, curr, dis, disp_avg,
2221                                                                    prev_string, curr_string);
2222                         }
2223                 }
2224
2225                 /* Display memory stats */
2226                 if (DISPLAY_MEM(actflag)) {
2227
2228                         if (DISPLAY_TASK_STATS(tskflag)) {
2229                                 again += write_pid_task_memory_stats(prev, curr, dis, disp_avg,
2230                                                                      prev_string, curr_string, itv);
2231                         }
2232                         if (DISPLAY_CHILD_STATS(tskflag) && DISPLAY_MEM(actflag)) {
2233                                 again += write_pid_child_memory_stats(prev, curr, dis, disp_avg,
2234                                                                       prev_string, curr_string);
2235                         }
2236                 }
2237
2238                 /* Display stack stats */
2239                 if (DISPLAY_STACK(actflag)) {
2240                         again += write_pid_stack_stats(prev, curr, dis, disp_avg,
2241                                                        prev_string, curr_string);
2242                 }
2243
2244                 /* Display I/O stats */
2245                 if (DISPLAY_IO(actflag)) {
2246                         again += write_pid_io_stats(prev, curr, dis, disp_avg, prev_string,
2247                                                     curr_string, itv);
2248                 }
2249
2250                 /* Display context switches stats */
2251                 if (DISPLAY_CTXSW(actflag)) {
2252                         again += write_pid_ctxswitch_stats(prev, curr, dis, prev_string,
2253                                                            curr_string, itv);
2254                 }
2255
2256                 /* Display kernel table stats */
2257                 if (DISPLAY_KTAB(actflag)) {
2258                         again += write_pid_ktab_stats(prev, curr, dis, disp_avg,
2259                                                       prev_string, curr_string);
2260                 }
2261
2262                 /* Display scheduling priority and policy information */
2263                 if (DISPLAY_RT(actflag)) {
2264                         again += write_pid_rt_stats(prev, curr, dis, prev_string, curr_string);
2265                 }
2266         }
2267
2268         if (DISPLAY_ALL_PID(pidflag)) {
2269                 again = 1;
2270         }
2271
2272         return again;
2273 }
2274
2275 /*
2276  ***************************************************************************
2277  * Print statistics average.
2278  *
2279  * IN:
2280  * @curr        Index in array for current sample statistics.
2281  * @dis         TRUE if a header line must be printed.
2282  ***************************************************************************
2283  */
2284 void write_stats_avg(int curr, int dis)
2285 {
2286         char string[16];
2287
2288         strncpy(string, _("Average:"), 16);
2289         string[15] = '\0';
2290         write_stats_core(2, curr, dis, TRUE, string, string);
2291 }
2292
2293 /*
2294  ***************************************************************************
2295  * Get previous and current timestamps, then display statistics.
2296  *
2297  * IN:
2298  * @curr        Index in array for current sample statistics.
2299  * @dis         TRUE if a header line must be printed.
2300  *
2301  * RETURNS:
2302  * 0 if all the processes to display have terminated.
2303  * <> 0 if there are still some processes left to display.
2304  ***************************************************************************
2305  */
2306 int write_stats(int curr, int dis)
2307 {
2308         char cur_time[2][TIMESTAMP_LEN];
2309
2310         /* Get previous timestamp */
2311         if (DISPLAY_ONELINE(pidflag)) {
2312                 strcpy(cur_time[!curr], "# Time     ");
2313         }
2314         else if (PRINT_SEC_EPOCH(pidflag)) {
2315                 snprintf(cur_time[!curr], sizeof(cur_time[!curr]), "%-11ld", mktime(&ps_tstamp[!curr]));
2316                 cur_time[!curr][sizeof(cur_time[!curr]) - 1] = '\0';
2317         }
2318         else if (is_iso_time_fmt()) {
2319                 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%H:%M:%S", &ps_tstamp[!curr]);
2320         }
2321         else {
2322                 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%X", &ps_tstamp[!curr]);
2323         }
2324
2325         /* Get current timestamp */
2326         if (PRINT_SEC_EPOCH(pidflag)) {
2327                 snprintf(cur_time[curr], sizeof(cur_time[curr]), "%-11ld", mktime(&ps_tstamp[curr]));
2328                 cur_time[curr][sizeof(cur_time[curr]) - 1] = '\0';
2329         }
2330         else if (is_iso_time_fmt()) {
2331                 strftime(cur_time[curr], sizeof(cur_time[curr]), "%H:%M:%S", &ps_tstamp[curr]);
2332         }
2333         else {
2334                 strftime(cur_time[curr], sizeof(cur_time[curr]), "%X", &ps_tstamp[curr]);
2335         }
2336
2337         return (write_stats_core(!curr, curr, dis, FALSE,
2338                                  cur_time[!curr], cur_time[curr]));
2339 }
2340
2341 /*
2342  ***************************************************************************
2343  * Main loop: Read and display PID stats.
2344  *
2345  * IN:
2346  * @dis_hdr     Set to TRUE if the header line must always be printed.
2347  * @rows        Number of rows of screen.
2348  ***************************************************************************
2349  */
2350 void rw_pidstat_loop(int dis_hdr, int rows)
2351 {
2352         int curr = 1, dis = 1;
2353         int again;
2354         unsigned long lines = rows;
2355         struct st_pid *plist;
2356
2357         /* Read system uptime */
2358         read_uptime(&uptime_cs[0]);
2359         read_stats(0);
2360
2361         if (DISPLAY_MEM(actflag)) {
2362                 /* Get total memory */
2363                 read_proc_meminfo();
2364         }
2365
2366         if (!interval) {
2367                 /* Display since boot time */
2368                 ps_tstamp[1] = ps_tstamp[0];
2369                 write_stats(0, DISP_HDR);
2370                 exit(0);
2371         }
2372
2373         /* Set a handler for SIGALRM */
2374         memset(&alrm_act, 0, sizeof(alrm_act));
2375         alrm_act.sa_handler = alarm_handler;
2376         sigaction(SIGALRM, &alrm_act, NULL);
2377         alarm(interval);
2378
2379         /* Save the first stats collected. Will be used to compute the average */
2380         ps_tstamp[2] = ps_tstamp[0];
2381         tot_jiffies[2] = tot_jiffies[0];
2382         uptime_cs[2] = uptime_cs[0];
2383         for (plist = pid_list; plist != NULL; plist = plist->next) {
2384                 memcpy(plist->pstats[2], plist->pstats[0], PID_STATS_SIZE);
2385         }
2386
2387         /* Set a handler for SIGINT */
2388         memset(&int_act, 0, sizeof(int_act));
2389         int_act.sa_handler = int_handler;
2390         sigaction(SIGINT, &int_act, NULL);
2391
2392         /* Wait for SIGALRM (or possibly SIGINT) signal */
2393         __pause();
2394
2395         if (signal_caught)
2396                 /* SIGINT/SIGCHLD signals caught during first interval: Exit immediately */
2397                 return;
2398
2399         do {
2400                 /* Every PID is potentially nonexistent */
2401                 set_pid_nonexistent(pid_list);
2402
2403                 /* Get time */
2404                 get_localtime(&ps_tstamp[curr], 0);
2405
2406                 /* Read system uptime (in 1/100th of a second) */
2407                 read_uptime(&(uptime_cs[curr]));
2408
2409                 /* Read stats */
2410                 read_stats(curr);
2411
2412                 if (!dis_hdr) {
2413                         dis = lines / rows;
2414                         if (dis) {
2415                                 lines %= rows;
2416                         }
2417                         lines++;
2418                 }
2419
2420                 /* Print results */
2421                 again = write_stats(curr, dis);
2422
2423                 if (!again)
2424                         return;
2425
2426                 if (count > 0) {
2427                         count--;
2428                 }
2429
2430                 if (count) {
2431
2432                         __pause();
2433
2434                         if (signal_caught) {
2435                                 /* SIGINT/SIGCHLD signals caught => Display average stats */
2436                                 count = 0;
2437                                 printf("\n");   /* Skip "^C" displayed on screen */
2438                         }
2439                         else {
2440                                 curr ^= 1;
2441                         }
2442                 }
2443         }
2444         while (count);
2445
2446         /*
2447          * The one line format uses a raw time value rather than time strings
2448          * so the average doesn't really fit.
2449          */
2450         if (!DISPLAY_ONELINE(pidflag))
2451         {
2452                 /* Write stats average */
2453                 write_stats_avg(curr, dis_hdr);
2454         }
2455 }
2456
2457 /*
2458  ***************************************************************************
2459  * Start a program that will be monitored by pidstat.
2460  *
2461  * IN:
2462  * @argc        Number of arguments.
2463  * @argv        Arguments values.
2464  *
2465  * RETURNS:
2466  * The PID of the program executed.
2467  ***************************************************************************
2468  */
2469 pid_t exec_pgm(int argc, char **argv)
2470 {
2471         pid_t child;
2472         char *args[argc + 1];
2473         int i;
2474
2475         child = __fork();
2476
2477         switch(child) {
2478
2479                 case -1:
2480                         perror("fork");
2481                         exit(4);
2482                         break;
2483
2484                 case 0:
2485                         /* Child */
2486                         for (i = 0; i < argc; i++) {
2487                                 args[i] = argv[i];
2488                         }
2489                         args[argc] = NULL;
2490
2491                         execvp(args[0], args);
2492                         perror("exec");
2493                         exit(4);
2494                         break;
2495
2496                 default:
2497                         /*
2498                          * Parent.
2499                          * Set a handler for SIGCHLD (signal that will be received
2500                          * by pidstat when the child program terminates).
2501                          * The handler is the same as for SIGINT: Stop and display
2502                          * average statistics.
2503                          */
2504                         memset(&chld_act, 0, sizeof(chld_act));
2505                         chld_act.sa_handler = int_handler;
2506                         sigaction(SIGCHLD, &chld_act, NULL);
2507
2508                         return child;
2509         }
2510 }
2511
2512 /*
2513  ***************************************************************************
2514  * Main entry to the pidstat program.
2515  ***************************************************************************
2516  */
2517 int main(int argc, char **argv)
2518 {
2519         int opt = 1, dis_hdr = -1, pid_nr = 0;
2520         int i;
2521         unsigned int pid;
2522         struct utsname header;
2523         int rows = 23;
2524         char *t;
2525
2526 #ifdef USE_NLS
2527         /* Init National Language Support */
2528         init_nls();
2529 #endif
2530
2531         /* Init color strings */
2532         init_colors();
2533
2534         /* Get HZ */
2535         get_HZ();
2536
2537         /* Compute page shift in kB */
2538         get_kb_shift();
2539
2540         /* Process args... */
2541         while (opt < argc) {
2542
2543                 if (!strcmp(argv[opt], "-e")) {
2544                         if (!argv[++opt]) {
2545                                 usage(argv[0]);
2546                         }
2547                         pidflag |= P_D_PID;
2548                         add_list_pid(&pid_list, exec_pgm(argc - opt, argv + opt), 0);
2549                         break;
2550                 }
2551
2552                 else if (!strcmp(argv[opt], "-p")) {
2553                         pidflag |= P_D_PID;
2554                         if (!argv[++opt]) {
2555                                 usage(argv[0]);
2556                         }
2557
2558                         for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ","), pid_nr++) {
2559                                 if (!strcmp(t, K_ALL)) {
2560                                         pidflag |= P_D_ALL_PID;
2561                                         pid_nr++;
2562                                 }
2563                                 else if (!strcmp(t, K_SELF)) {
2564                                         add_list_pid(&pid_list, getpid(), 0);
2565                                 }
2566                                 else {
2567                                         if (strspn(t, DIGITS) != strlen(t)) {
2568                                                 usage(argv[0]);
2569                                         }
2570                                         pid = atoi(t);
2571                                         if (pid < 1) {
2572                                                 usage(argv[0]);
2573                                         }
2574                                         add_list_pid(&pid_list, pid, 0);
2575                                 }
2576                         }
2577                         opt++;
2578                 }
2579
2580                 else if (!strcmp(argv[opt], "-C")) {
2581                         if (!argv[++opt]) {
2582                                 usage(argv[0]);
2583                         }
2584                         strncpy(commstr, argv[opt++], sizeof(commstr));
2585                         commstr[sizeof(commstr) - 1] = '\0';
2586                         pidflag |= P_F_COMMSTR;
2587                         if (!strlen(commstr)) {
2588                                 usage(argv[0]);
2589                         }
2590                 }
2591
2592                 else if (!strcmp(argv[opt], "-G")) {
2593                         if (!argv[++opt]) {
2594                                 usage(argv[0]);
2595                         }
2596                         strncpy(procstr, argv[opt++], sizeof(procstr));
2597                         procstr[sizeof(procstr) - 1] = '\0';
2598                         pidflag |= P_F_PROCSTR;
2599                         if (!strlen(procstr)) {
2600                                 usage(argv[0]);
2601                         }
2602                 }
2603
2604                 else if (!strcmp(argv[opt], "--human")) {
2605                         pidflag |= P_D_UNIT;
2606                         opt++;
2607                 }
2608
2609                 else if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) {
2610                         /* Get number of decimal places */
2611                         dplaces_nr = atoi(argv[opt] + 6);
2612                         if ((dplaces_nr < 0) || (dplaces_nr > 2)) {
2613                                 usage(argv[0]);
2614                         }
2615                         opt++;
2616                 }
2617
2618                 else if (!strcmp(argv[opt], "-T")) {
2619                         if (!argv[++opt]) {
2620                                 usage(argv[0]);
2621                         }
2622                         if (tskflag) {
2623                                 dis_hdr++;
2624                         }
2625                         if (!strcmp(argv[opt], K_P_TASK)) {
2626                                 tskflag |= P_TASK;
2627                         }
2628                         else if (!strcmp(argv[opt], K_P_CHILD)) {
2629                                 tskflag |= P_CHILD;
2630                         }
2631                         else if (!strcmp(argv[opt], K_P_ALL)) {
2632                                 tskflag |= P_TASK + P_CHILD;
2633                                 dis_hdr++;
2634                         }
2635                         else {
2636                                 usage(argv[0]);
2637                         }
2638                         opt++;
2639                 }
2640
2641                 /* Option used individually. See below for grouped option */
2642                 else if (!strcmp(argv[opt], "-U")) {
2643                         /* Display username instead of UID */
2644                         pidflag |= P_D_USERNAME;
2645                         if (argv[++opt] && (argv[opt][0] != '-') &&
2646                             (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
2647                                 strncpy(userstr, argv[opt++], sizeof(userstr));
2648                                 userstr[sizeof(userstr) - 1] = '\0';
2649                                 pidflag |= P_F_USERSTR;
2650                                 if (!strlen(userstr)) {
2651                                         usage(argv[0]);
2652                                 }
2653                         }
2654                 }
2655
2656                 else if (!strncmp(argv[opt], "-", 1)) {
2657                         for (i = 1; *(argv[opt] + i); i++) {
2658
2659                                 switch (*(argv[opt] + i)) {
2660
2661                                 case 'd':
2662                                         /* Display I/O usage */
2663                                         actflag |= P_A_IO;
2664                                         dis_hdr++;
2665                                         break;
2666
2667                                 case 'H':
2668                                         /* Display timestamps in sec since the epoch */
2669                                         pidflag |= P_D_SEC_EPOCH;
2670                                         break;
2671
2672                                 case 'h':
2673                                         /* Display stats on one line */
2674                                         pidflag |= P_D_ONELINE;
2675                                         break;
2676
2677                                 case 'I':
2678                                         /* IRIX mode off */
2679                                         pidflag |= P_F_IRIX_MODE;
2680                                         break;
2681
2682                                 case 'l':
2683                                         /* Display whole command line */
2684                                         pidflag |= P_D_CMDLINE;
2685                                         break;
2686
2687                                 case 'R':
2688                                         /* Display priority and policy info */
2689                                         actflag |= P_A_RT;
2690                                         dis_hdr++;
2691                                         break;
2692
2693                                 case 'r':
2694                                         /* Display memory usage */
2695                                         actflag |= P_A_MEM;
2696                                         dis_hdr++;
2697                                         break;
2698
2699                                 case 's':
2700                                         /* Display stack sizes */
2701                                         actflag |= P_A_STACK;
2702                                         dis_hdr++;
2703                                         break;
2704
2705                                 case 't':
2706                                         /* Display stats for threads */
2707                                         pidflag |= P_D_TID;
2708                                         break;
2709
2710                                 case 'U':
2711                                         /* When option is grouped, it cannot take an arg */
2712                                         pidflag |= P_D_USERNAME;
2713                                         break;
2714
2715                                 case 'u':
2716                                         /* Display CPU usage */
2717                                         actflag |= P_A_CPU;
2718                                         dis_hdr++;
2719                                         break;
2720
2721                                 case 'V':
2722                                         /* Print version number and exit */
2723                                         print_version();
2724                                         break;
2725
2726                                 case 'v':
2727                                         /* Display some kernel tables values */
2728                                         actflag |= P_A_KTAB;
2729                                         dis_hdr++;
2730                                         break;
2731
2732                                 case 'w':
2733                                         /* Display context switches */
2734                                         actflag |= P_A_CTXSW;
2735                                         dis_hdr++;
2736                                         break;
2737
2738                                 default:
2739                                         usage(argv[0]);
2740                                 }
2741                         }
2742                         opt++;
2743                 }
2744
2745                 else if (interval < 0) {        /* Get interval */
2746                         if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
2747                                 usage(argv[0]);
2748                         }
2749                         interval = atol(argv[opt++]);
2750                         if (interval < 0) {
2751                                 usage(argv[0]);
2752                         }
2753                         count = -1;
2754                 }
2755
2756                 else if (count <= 0) {  /* Get count value */
2757                         if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
2758                             !interval) {
2759                                 usage(argv[0]);
2760                         }
2761                         count = atol(argv[opt++]);
2762                         if (count < 1) {
2763                                 usage(argv[0]);
2764                         }
2765                 }
2766                 else {
2767                         usage(argv[0]);
2768                 }
2769         }
2770
2771         if (interval < 0) {
2772                 /* Interval not set => display stats since boot time */
2773                 interval = 0;
2774         }
2775
2776         if (!DISPLAY_PID(pidflag)) {
2777                 dis_hdr = 1;
2778         }
2779
2780         /* Check flags and set default values */
2781         check_flags();
2782
2783         /* Count nb of proc */
2784         cpu_nr = get_cpu_nr(~0, FALSE);
2785
2786         if (dis_hdr < 0) {
2787                 dis_hdr = 0;
2788         }
2789         if (!dis_hdr) {
2790                 if ((pid_nr > 1)) {
2791                         dis_hdr = 1;
2792                 }
2793                 else {
2794                         rows = get_win_height();
2795                 }
2796         }
2797
2798         /* Get time */
2799         get_localtime(&(ps_tstamp[0]), 0);
2800
2801         /*
2802          * Don't buffer data if redirected to a pipe.
2803          * Note: With musl-c, the behavior of this function is undefined except
2804          * when it is the first operation on the stream.
2805          */
2806         setbuf(stdout, NULL);
2807
2808         /* Get system name, release number and hostname */
2809         __uname(&header);
2810         print_gal_header(&(ps_tstamp[0]), header.sysname, header.release,
2811                          header.nodename, header.machine, cpu_nr,
2812                          PLAIN_OUTPUT);
2813
2814         /* Main loop */
2815         rw_pidstat_loop(dis_hdr, rows);
2816
2817         /* Free structures */
2818         sfree_pid(&pid_list, TRUE);
2819
2820         return 0;
2821 }