aboutsummaryrefslogtreecommitdiffstats
path: root/src/firemon/top.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firemon/top.c')
-rw-r--r--src/firemon/top.c297
1 files changed, 297 insertions, 0 deletions
diff --git a/src/firemon/top.c b/src/firemon/top.c
new file mode 100644
index 000000000..1eb753694
--- /dev/null
+++ b/src/firemon/top.c
@@ -0,0 +1,297 @@
1/*
2 * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com)
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License 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-1301 USA.
19*/
20#include "firemon.h"
21#include <termios.h>
22#include <sys/ioctl.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <unistd.h>
26
27static unsigned pgs_rss = 0;
28static unsigned pgs_shared = 0;
29static unsigned clocktick = 0;
30static unsigned long long sysuptime = 0;
31
32static char *get_header(void) {
33 char *rv;
34 if (asprintf(&rv, "%-5.5s %-9.9s %-8.8s %-8.8s %-5.5s %-4.4s %-9.9s %s",
35 "PID", "User", "RES(KiB)", "SHR(KiB)", "CPU%", "Prcs", "Uptime", "Command") == -1)
36 errExit("asprintf");
37
38 return rv;
39}
40
41
42// recursivity!!!
43static char *print_top(unsigned index, unsigned parent, unsigned *utime, unsigned *stime, unsigned itv, float *cpu, int *cnt) {
44 char *rv = NULL;
45
46 char procdir[20];
47 snprintf(procdir, 20, "/proc/%u", index);
48 struct stat s;
49 if (stat(procdir, &s) == -1)
50 return NULL;
51
52 if (pids[index].level == 1) {
53 pgs_rss = 0;
54 pgs_shared = 0;
55 *utime = 0;
56 *stime = 0;
57 *cnt = 0;
58 }
59
60 (*cnt)++;
61 pid_getmem(index, &pgs_rss, &pgs_shared);
62 unsigned utmp;
63 unsigned stmp;
64 pid_get_cpu_time(index, &utmp, &stmp);
65 *utime += utmp;
66 *stime += stmp;
67
68
69 int i;
70 for (i = index + 1; i < max_pids; i++) {
71 if (pids[i].parent == index)
72 print_top(i, index, utime, stime, itv, cpu, cnt);
73 }
74
75 if (pids[index].level == 1) {
76 // pid
77 char pidstr[10];
78 snprintf(pidstr, 10, "%u", index);
79
80 // command
81 char *cmd = pid_proc_cmdline(index);
82 char *ptrcmd;
83 if (cmd == NULL) {
84 if (pids[index].zombie)
85 ptrcmd = "(zombie)";
86 else
87 ptrcmd = "";
88 }
89 else
90 ptrcmd = cmd;
91
92 // user
93 char *user = pid_get_user_name(pids[index].uid);
94 char *ptruser;
95 if (user)
96 ptruser = user;
97 else
98 ptruser = "";
99
100 // memory
101 int pgsz = getpagesize();
102 char rss[10];
103 snprintf(rss, 10, "%u", pgs_rss * pgsz / 1024);
104 char shared[10];
105 snprintf(shared, 10, "%u", pgs_shared * pgsz / 1024);
106
107 // uptime
108 unsigned long long uptime = pid_get_start_time(index);
109 if (clocktick == 0)
110 clocktick = sysconf(_SC_CLK_TCK);
111 uptime /= clocktick;
112 uptime = sysuptime - uptime;
113 unsigned sec = uptime % 60;
114 uptime -= sec;
115 uptime /= 60;
116 unsigned min = uptime % 60;
117 uptime -= min;
118 uptime /= 60;
119 unsigned hour = uptime;
120 char uptime_str[50];
121 snprintf(uptime_str, 50, "%02u:%02u:%02u", hour, min, sec);
122
123 // cpu
124 itv *= clocktick;
125 float ud = (float) (*utime - pids[index].utime) / itv * 100;
126 float sd = (float) (*stime - pids[index].stime) / itv * 100;
127 float cd = ud + sd;
128 *cpu = cd;
129 char cpu_str[10];
130 snprintf(cpu_str, 10, "%2.1f", cd);
131
132 // process count
133 char prcs_str[10];
134 snprintf(prcs_str, 10, "%d", *cnt);
135
136 if (asprintf(&rv, "%-5.5s %-9.9s %-8.8s %-8.8s %-5.5s %-4.4s %-9.9s %s",
137 pidstr, ptruser, rss, shared, cpu_str, prcs_str, uptime_str, ptrcmd) == -1)
138 errExit("asprintf");
139
140 if (cmd)
141 free(cmd);
142 if (user)
143 free(user);
144
145 }
146
147 return rv;
148}
149
150
151typedef struct node_t {
152 struct node_t *next;
153 char *line;
154 float cpu;
155} Node;
156
157static Node *head = NULL;
158
159static void head_clear(void) {
160 Node *ptr = head;
161 while (ptr) {
162 if (ptr->line)
163 free(ptr->line);
164 Node *next = ptr->next;
165 free(ptr);
166 ptr = next;
167 }
168
169 head = NULL;
170}
171
172static void head_add(float cpu, char *line) {
173 // allocate a new node structure
174 Node *node = malloc(sizeof(Node));
175 if (!node)
176 errExit("malloc");
177 node->line = line;
178 node->cpu = cpu;
179 node->next = NULL;
180
181 // insert in first list position
182 if (head == NULL || head->cpu < cpu) {
183 node->next = head;
184 head = node;
185 return;
186 }
187
188 // insert in the right place
189 Node *ptr = head;
190 while (1) {
191 // last position
192 Node *current = ptr->next;
193 if (current == NULL) {
194 ptr->next = node;
195 return;
196 }
197
198 // current position
199 if (current->cpu < cpu) {
200 ptr->next = node;
201 node->next = current;
202 return;
203 }
204
205 ptr = current;
206 }
207}
208
209void head_print(int col, int row) {
210 Node *ptr = head;
211 int current = 0;
212 while (ptr) {
213 if (current >= row)
214 break;
215
216 if (strlen(ptr->line) > col)
217 ptr->line[col] = '\0';
218
219 if (ptr->next == NULL || current == (row - 1)) {
220 printf("%s", ptr->line);
221 fflush(0);
222 }
223 else
224 printf("%s\n", ptr->line);
225
226 ptr = ptr->next;
227 current++;
228 }
229}
230
231void top(void) {
232 if (getuid() == 0)
233 firemon_drop_privs();
234
235 while (1) {
236 // clear linked list
237 head_clear();
238
239 // set pid table
240 int i;
241 int itv = 5; // 5 second interval
242 pid_read(0);
243
244 // start cpu measurements
245 unsigned utime = 0;
246 unsigned stime = 0;
247 for (i = 0; i < max_pids; i++) {
248 if (pids[i].level == 1)
249 pid_store_cpu(i, 0, &utime, &stime);
250 }
251
252 // wait 5 seconds
253 firemon_sleep(itv);
254
255 // grab screen size
256 struct winsize sz;
257 int row = 24;
258 int col = 80;
259 if (!ioctl(0, TIOCGWINSZ, &sz)) {
260 col = sz.ws_col;
261 row = sz.ws_row;
262 }
263
264 // start printing
265 firemon_clrscr();
266 char *header = get_header();
267 if (strlen(header) > col)
268 header[col] = '\0';
269 printf("%s\n", header);
270 if (row > 0)
271 row--;
272 free(header);
273
274 // find system uptime
275 FILE *fp = fopen("/proc/uptime", "r");
276 if (fp) {
277 float f;
278 int rv = fscanf(fp, "%f", &f);
279 (void) rv;
280 sysuptime = (unsigned long long) f;
281 fclose(fp);
282 }
283
284 // print processes
285 for (i = 0; i < max_pids; i++) {
286 if (pids[i].level == 1) {
287 float cpu = 0;
288 int cnt = 0; // process count
289 char *line = print_top(i, 0, &utime, &stime, itv, &cpu, &cnt);
290 if (line)
291 head_add(cpu, line);
292 }
293 }
294 head_print(col, row);
295 }
296}
297