htop.c 12.3 KB
Newer Older
Hisham Muhammad's avatar
Hisham Muhammad committed
1
2
/*
htop - htop.c
3
(C) 2004-2011 Hisham H. Muhammad
Hisham Muhammad's avatar
Hisham Muhammad committed
4
5
6
7
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/

Hisham Muhammad's avatar
Hisham Muhammad committed
8
#include "config.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
9

Hisham Muhammad's avatar
Hisham Muhammad committed
10
#include "FunctionBar.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
11
#include "Hashtable.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
12
#include "ColumnsPanel.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
13
14
15
16
17
18
#include "CRT.h"
#include "MainPanel.h"
#include "ProcessList.h"
#include "ScreenManager.h"
#include "Settings.h"
#include "UsersTable.h"
19
#include "Platform.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
20

Hisham Muhammad's avatar
Hisham Muhammad committed
21
#include <getopt.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
22
23
24
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
25
#include <string.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
26
#include <time.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
27
#include <unistd.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
28

Hisham Muhammad's avatar
Hisham Muhammad committed
29
30
//#link m

31
static void printVersionFlag() {
32
33
34
   fputs("htop " VERSION " - " COPYRIGHT "\n"
         "Released under the GNU GPL.\n\n",
         stdout);
Hisham Muhammad's avatar
Hisham Muhammad committed
35
36
   exit(0);
}
37
 
38
static void printHelpFlag() {
39
40
   fputs("htop " VERSION " - " COPYRIGHT "\n"
         "Released under the GNU GPL.\n\n"
41
42
43
44
45
46
         "-C --no-color               Use a monochrome color scheme\n"
         "-d --delay=DELAY            Set the delay between updates, in tenths of seconds\n"
         "-h --help                   Print this help screen\n"
         "-s --sort-key=COLUMN        Sort by COLUMN (try --sort-key=help for a list)\n"
         "-u --user=USERNAME          Show only processes of a given user\n"
         "-p --pid=PID,[,PID,PID...]  Show only the given PIDs\n"
Christian Hesse's avatar
Christian Hesse committed
47
         "-v --version                Print version info\n"
48
49
50
51
52
         "\n"
         "Long options may be passed with a single dash.\n\n"
         "Press F1 inside htop for online help.\n"
         "See 'man htop' for more information.\n",
         stdout);
Hisham Muhammad's avatar
Hisham Muhammad committed
53
54
55
   exit(0);
}

Hisham Muhammad's avatar
Hisham Muhammad committed
56
57
// ----------------------------------------

Hisham Muhammad's avatar
Hisham Muhammad committed
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
typedef struct CommandLineSettings_ {
   Hashtable* pidWhiteList;
   uid_t userId;
   int sortKey;
   int delay;
   bool useColors;
} CommandLineSettings;

static CommandLineSettings parseArguments(int argc, char** argv) {

   CommandLineSettings flags = {
      .pidWhiteList = NULL,
      .userId = -1, // -1 is guaranteed to be an invalid uid_t (see setreuid(2))
      .sortKey = 0,
      .delay = -1,
      .useColors = true,
   };
75
76
77
78
79
80
81
82
83
84

   static struct option long_opts[] =
   {
      {"help",     no_argument,         0, 'h'},
      {"version",  no_argument,         0, 'v'},
      {"delay",    required_argument,   0, 'd'},
      {"sort-key", required_argument,   0, 's'},
      {"user",     required_argument,   0, 'u'},
      {"no-color", no_argument,         0, 'C'},
      {"no-colour",no_argument,         0, 'C'},
85
      {"pid",      required_argument,   0, 'p'},
Hisham Muhammad's avatar
Hisham Muhammad committed
86
      {"io",       no_argument,         0, 'i'},
87
88
      {0,0,0,0}
   };
89

Hisham Muhammad's avatar
Hisham Muhammad committed
90
   int opt, opti=0;
91
   /* Parse arguments */
Hisham Muhammad's avatar
Hisham Muhammad committed
92
   while ((opt = getopt_long(argc, argv, "hvCs:d:u:p:i", long_opts, &opti))) {
93
94
95
96
97
98
99
100
101
      if (opt == EOF) break;
      switch (opt) {
         case 'h':
            printHelpFlag();
            break;
         case 'v':
            printVersionFlag();
            break;
         case 's':
Hisham Muhammad's avatar
Hisham Muhammad committed
102
            if (strcmp(optarg, "help") == 0) {
103
               for (int j = 1; j < Platform_numberOfFields; j++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
104
105
106
                  const char* name = Process_fields[j].name;
                  if (name) printf ("%s\n", name);
               }
107
108
               exit(0);
            }
Hisham Muhammad's avatar
Hisham Muhammad committed
109
110
            flags.sortKey = ColumnsPanel_fieldNameToIndex(optarg);
            if (flags.sortKey == -1) {
Hisham Muhammad's avatar
Hisham Muhammad committed
111
               fprintf(stderr, "Error: invalid column \"%s\".\n", optarg);
112
            }
113
114
            break;
         case 'd':
Hisham Muhammad's avatar
Hisham Muhammad committed
115
116
117
            if (sscanf(optarg, "%16d", &(flags.delay)) == 1) {
               if (flags.delay < 1) flags.delay = 1;
               if (flags.delay > 100) flags.delay = 100;
118
            } else {
Hisham Muhammad's avatar
Hisham Muhammad committed
119
               fprintf(stderr, "Error: invalid delay value \"%s\".\n", optarg);
120
            }
121
122
            break;
         case 'u':
Hisham Muhammad's avatar
Hisham Muhammad committed
123
            if (!Action_setUserOnly(optarg, &(flags.userId))) {
Hisham Muhammad's avatar
Hisham Muhammad committed
124
               fprintf(stderr, "Error: invalid user \"%s\".\n", optarg);
125
            }
126
127
            break;
         case 'C':
Hisham Muhammad's avatar
Hisham Muhammad committed
128
            flags.useColors = false;
129
            break;
Hisham Muhammad's avatar
Hisham Muhammad committed
130
131
         case 'p': {
            char* argCopy = strdup(optarg);
132
            char* saveptr;
Hisham Muhammad's avatar
Hisham Muhammad committed
133
            char* pid = strtok_r(argCopy, ",", &saveptr);
134

135
            if(!flags.pidWhiteList) {
Hisham Muhammad's avatar
Hisham Muhammad committed
136
               flags.pidWhiteList = Hashtable_new(8, false);
137
138
            }

139
            while(pid) {
140
                unsigned int num_pid = atoi(pid);
Hisham Muhammad's avatar
Hisham Muhammad committed
141
                Hashtable_put(flags.pidWhiteList, num_pid, (void *) 1);
142
                pid = strtok_r(NULL, ",", &saveptr);
143
144
145
            }
            free(argCopy);

146
            break;
147
         }
148
149
         default:
            exit(1);
Hisham Muhammad's avatar
Hisham Muhammad committed
150
151
      }
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
152
153
   return flags;
}
154

Hisham Muhammad's avatar
Hisham Muhammad committed
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
static void millisleep(unsigned long millisec) {
   struct timespec req = {
      .tv_sec = 0,
      .tv_nsec = millisec * 1000000L
   };
   while(nanosleep(&req,&req)==-1) {
      continue;
   }
}

int main(int argc, char** argv) {

   char *lc_ctype = getenv("LC_CTYPE");
   if(lc_ctype != NULL)
      setlocale(LC_CTYPE, lc_ctype);
   else if ((lc_ctype = getenv("LC_ALL")))
      setlocale(LC_CTYPE, lc_ctype);
   else
      setlocale(LC_CTYPE, "");

   CommandLineSettings flags = parseArguments(argc, argv); // may exit()
176

177
#ifdef HAVE_PROC
178
   if (access(PROCDIR, R_OK) != 0) {
Hisham Muhammad's avatar
Hisham Muhammad committed
179
      fprintf("Error: could not read procfs (compiled to look in %s).\n", PROCDIR);
180
   }
181
#endif
Hisham Muhammad's avatar
Hisham Muhammad committed
182
   
183
   Process_setupColumnWidths();
Hisham Muhammad's avatar
Hisham Muhammad committed
184
   
Hisham Muhammad's avatar
Hisham Muhammad committed
185
186
187
188
189
190
   UsersTable* ut = UsersTable_new();
   ProcessList* pl = ProcessList_new(ut, flags.pidWhiteList, flags.userId);
   
   Settings* settings = Settings_new(pl->cpuCount);
   pl->settings = settings;

191
192
193
194
   Header* header = Header_new(pl, settings, 2);

   Header_populateFromSettings(header);

Hisham Muhammad's avatar
Hisham Muhammad committed
195
196
197
   if (flags.delay != -1)
      settings->delay = flags.delay;
   if (!flags.useColors) 
198
      settings->colorScheme = COLORSCHEME_MONOCHROME;
199

Hisham Muhammad's avatar
Hisham Muhammad committed
200
   CRT_init(settings->delay, settings->colorScheme);
201
   
202
   MainPanel* panel = MainPanel_new();
Hisham Muhammad's avatar
Hisham Muhammad committed
203
204
   ProcessList_setPanel(pl, (Panel*) panel);

205
   MainPanel_updateTreeFunctions(panel, settings->treeView);
Hisham Muhammad's avatar
Hisham Muhammad committed
206
207
208
209
210
      
   if (flags.sortKey > 0) {
      settings->sortKey = flags.sortKey;
      settings->treeView = false;
      settings->direction = 1;
211
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
212
   ProcessList_printHeader(pl, Panel_getHeader((Panel*)panel));
Hisham Muhammad's avatar
Hisham Muhammad committed
213

Hisham Muhammad's avatar
Hisham Muhammad committed
214
215
216
217
218
219
220
221
222
   State state = {
      .settings = settings,
      .ut = ut,
      .pl = pl,
      .panel = (Panel*) panel,
      .header = header,
   };
   MainPanel_setState(panel, &state);
   
223
   ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, true);
224
   ScreenManager_add(scr, (Panel*) panel, -1);
Hisham Muhammad's avatar
Hisham Muhammad committed
225

Hisham Muhammad's avatar
Hisham Muhammad committed
226
   ProcessList_scan(pl);
227
   millisleep(75);
228
   ProcessList_scan(pl);
Hisham Muhammad's avatar
Hisham Muhammad committed
229
230

   ScreenManager_run(scr, NULL, NULL);   
Hisham Muhammad's avatar
Hisham Muhammad committed
231
   
Hisham Muhammad's avatar
Hisham Muhammad committed
232
   /*
Hisham Muhammad's avatar
Hisham Muhammad committed
233
234
235
236
237
238
239
240
   FunctionBar_draw(defaultBar, NULL);
   
   int acc = 0;
   bool follow = false;
 
   struct timeval tv;
   double oldTime = 0.0;

241
   int ch = ERR;
Hisham Muhammad's avatar
Hisham Muhammad committed
242
243
   int closeTimeout = 0;

Hisham Muhammad's avatar
Hisham Muhammad committed
244
   bool drawPanel = true;
245
   
246
247
   bool collapsed = false;
   
Hisham Muhammad's avatar
Hisham Muhammad committed
248
249
   Htop_Action keys[KEY_MAX] = { NULL };
   setBindings(keys);
250
251
252
253
254
255
256
   Platform_setBindings(keys);

   bool quit = false;
   int sortTimeout = 0;
   int resetSortTimeout = 5;
   bool doRefresh = true;
   bool forceRecalculate = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
257
   
Hisham Muhammad's avatar
Hisham Muhammad committed
258
259
   while (!quit) {
      gettimeofday(&tv, NULL);
260
      double newTime = ((double)tv.tv_sec * 10) + ((double)tv.tv_usec / 100000);
Hisham Muhammad's avatar
Hisham Muhammad committed
261
262
      bool timeToRecalculate = (newTime - oldTime > settings->delay);
      if (newTime < oldTime) timeToRecalculate = true; // clock was adjusted?
263
      int following = follow ? MainPanel_selectedPid((MainPanel*)panel) : -1;
Hisham Muhammad's avatar
Hisham Muhammad committed
264
      if (timeToRecalculate) {
265
         Header_draw(header);
Hisham Muhammad's avatar
Hisham Muhammad committed
266
         oldTime = newTime;
267
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
268
      if (doRefresh) {
Hisham Muhammad's avatar
Hisham Muhammad committed
269
         if (timeToRecalculate || forceRecalculate) {
Hisham Muhammad's avatar
Hisham Muhammad committed
270
            ProcessList_scan(pl);
Hisham Muhammad's avatar
Hisham Muhammad committed
271
            forceRecalculate = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
272
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
273
         if (sortTimeout == 0 || settings->treeView) {
Hisham Muhammad's avatar
Hisham Muhammad committed
274
            ProcessList_sort(pl);
Hisham Muhammad's avatar
Hisham Muhammad committed
275
            sortTimeout = 1;
Hisham Muhammad's avatar
Hisham Muhammad committed
276
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
277
278
         ProcessList_rebuildPanel(pl, true, following, IncSet_filter(inc));
         drawPanel = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
279
280
      }
      doRefresh = true;
281
      
Hisham Muhammad's avatar
Hisham Muhammad committed
282
      if (settings->treeView) {
283
284
285
286
287
288
289
290
291
292
293
         Process* p = (Process*) Panel_getSelected(panel);
         if (p) {
            if (!p->showChildren && !collapsed) {
               FunctionBar_setLabel(defaultBar, KEY_F(6), "Expand");
               FunctionBar_draw(defaultBar, NULL);
            } else if (p->showChildren && collapsed) {
               FunctionBar_setLabel(defaultBar, KEY_F(6), "Collap");
               FunctionBar_draw(defaultBar, NULL);
            }
            collapsed = !p->showChildren;
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
294
295
      } else {
         collapsed = false;
296
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
297

Hisham Muhammad's avatar
Hisham Muhammad committed
298
      if (drawPanel) {
299
         Panel_draw(panel, true);
300
      }
301
      
Hisham Muhammad's avatar
Hisham Muhammad committed
302
      int prev = ch;
303
      if (inc->active)
304
         move(LINES-1, CRT_cursorX);
Hisham Muhammad's avatar
Hisham Muhammad committed
305
306
307
      ch = getch();

      if (ch == ERR) {
308
         if (!inc->active)
Hisham Muhammad's avatar
Hisham Muhammad committed
309
310
            sortTimeout--;
         if (prev == ch && !timeToRecalculate) {
Hisham Muhammad's avatar
Hisham Muhammad committed
311
            closeTimeout++;
312
            if (closeTimeout == 100) {
Hisham Muhammad's avatar
Hisham Muhammad committed
313
               break;
314
            }
Hisham Muhammad's avatar
Hisham Muhammad committed
315
316
         } else
            closeTimeout = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
317
         drawPanel = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
318
319
         continue;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
320
321
322
      drawPanel = true;

      Htop_Reaction reaction = HTOP_OK;
Hisham Muhammad's avatar
Hisham Muhammad committed
323
324
325
326
327

      if (ch == KEY_MOUSE) {
         MEVENT mevent;
         int ok = getmouse(&mevent);
         if (ok == OK) {
328
329
330
331
            if (mevent.bstate & BUTTON1_CLICKED) {
               if (mevent.y == panel->y) {
                  int x = panel->scrollH + mevent.x + 1;
                  ProcessField field = ProcessList_keyAt(pl, x);
Hisham Muhammad's avatar
Hisham Muhammad committed
332
333
334
                  if (field == settings->sortKey) {
                     Settings_invertSortOrder(settings);
                     settings->treeView = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
335
                     reaction |= HTOP_REDRAW_BAR;
336
                  } else {
Hisham Muhammad's avatar
Hisham Muhammad committed
337
                     reaction |= setSortKey(settings, field);
338
                  }
Hisham Muhammad's avatar
Hisham Muhammad committed
339
340
                  sortTimeout = 0;
                  ch = ERR;
341
342
343
               } else if (mevent.y >= panel->y + 1 && mevent.y < LINES - 1) {
                  Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
                  follow = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
344
                  ch = ERR;
345
               } if (mevent.y == LINES - 1) {
346
                  ch = FunctionBar_synthesizeEvent(inc->bar, mevent.x);
347
               }
348
349
350
351
352
353
            } else if (mevent.bstate & BUTTON4_CLICKED) {
               ch = KEY_UP;
            #if NCURSES_MOUSE_VERSION > 1
            } else if (mevent.bstate & BUTTON5_CLICKED) {
               ch = KEY_DOWN;
            #endif
Hisham Muhammad's avatar
Hisham Muhammad committed
354
355
356
357
            }
         }
      }

358
359
      if (inc->active) {
         doRefresh = IncSet_handleKey(inc, ch, panel, getMainPanelValue, NULL);
360
361
362
         if (!inc->active) {
            follow = true;
         }
363
364
365
         continue;
      }
      
366
      if (ch < 255 && isdigit((char)ch)) {
367
368
         if (Panel_size(panel) == 0) continue;
         pid_t pid = ch-48 + acc;
369
         for (int i = 0; i < ProcessList_size(pl); i++) {
370
            Panel_setSelected(panel, i);
371
372
373
374
375
            Process* p = (Process*) Panel_getSelected(panel);
            if (p && p->pid == pid) {
               break;
            }
         }
376
377
378
379
380
381
382
383
         acc = pid * 10;
         if (acc > 10000000)
            acc = 0;
         continue;
      } else {
         acc = 0;
      }

Hisham Muhammad's avatar
Hisham Muhammad committed
384
      if(ch != ERR && keys[ch]) {
Hisham Muhammad's avatar
Hisham Muhammad committed
385
         reaction |= (keys[ch])(&state);
Hisham Muhammad's avatar
Hisham Muhammad committed
386
387
388
389
      } else {
         doRefresh = false;
         sortTimeout = resetSortTimeout;
         Panel_onKey(panel, ch);
Hisham Muhammad's avatar
Hisham Muhammad committed
390
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
391
392
      
      // Reaction handlers:
393

Hisham Muhammad's avatar
Hisham Muhammad committed
394
      if (reaction & HTOP_REDRAW_BAR) {
Hisham Muhammad's avatar
Hisham Muhammad committed
395
         updateTreeFunctions(defaultBar, settings->treeView);
Hisham Muhammad's avatar
Hisham Muhammad committed
396
         IncSet_drawBar(inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
397
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
398
      if (reaction & HTOP_UPDATE_PANELHDR) {
399
400
         ProcessList_printHeader(pl, Panel_getHeader(panel));
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
401
      if (reaction & HTOP_REFRESH) {
Hisham Muhammad's avatar
Hisham Muhammad committed
402
         doRefresh = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
403
404
405
406
407
408
409
         sortTimeout = 0;
      }      
      if (reaction & HTOP_RECALCULATE) {
         forceRecalculate = true;
         sortTimeout = 0;
      }
      if (reaction & HTOP_SAVE_SETTINGS) {
Hisham Muhammad's avatar
Hisham Muhammad committed
410
411
         settings->changed = true;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
412
413
414
415
      if (reaction & HTOP_QUIT) {
         quit = true;
      }
      follow = (reaction & HTOP_KEEP_FOLLOWING);
Hisham Muhammad's avatar
Hisham Muhammad committed
416
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
417
418
419
   
   */
   
Hisham Muhammad's avatar
Hisham Muhammad committed
420
421
422
423
424
425
426
427
428
429
   attron(CRT_colors[RESET_COLOR]);
   mvhline(LINES-1, 0, ' ', COLS);
   attroff(CRT_colors[RESET_COLOR]);
   refresh();
   
   CRT_done();
   if (settings->changed)
      Settings_write(settings);
   Header_delete(header);
   ProcessList_delete(pl);
Hisham Muhammad's avatar
Hisham Muhammad committed
430
431

   /*   
Hisham Muhammad's avatar
Hisham Muhammad committed
432
   FunctionBar_delete((Object*)defaultBar);
Hisham Muhammad's avatar
Hisham Muhammad committed
433
   Panel_delete((Object*)panel);
Hisham Muhammad's avatar
Hisham Muhammad committed
434
435
436
   */
   
   ScreenManager_delete(scr);
Hisham Muhammad's avatar
Hisham Muhammad committed
437
   
Hisham Muhammad's avatar
Hisham Muhammad committed
438
439
   UsersTable_delete(ut);
   Settings_delete(settings);
Hisham Muhammad's avatar
Hisham Muhammad committed
440
   
Hisham Muhammad's avatar
Hisham Muhammad committed
441
442
   if(flags.pidWhiteList) {
      Hashtable_delete(flags.pidWhiteList);
443
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
444
445
   return 0;
}