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