htop.c 12.7 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"
Hisham Muhammad's avatar
Hisham Muhammad committed
19

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

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

30
static void printVersionFlag() {
31
32
33
   fputs("htop " VERSION " - " COPYRIGHT "\n"
         "Released under the GNU GPL.\n\n",
         stdout);
Hisham Muhammad's avatar
Hisham Muhammad committed
34
35
36
   exit(0);
}

37
38
static const char* defaultFunctions[]  = {"Help  ", "Setup ", "Search", "Filter", "Tree  ", "SortBy", "Nice -", "Nice +", "Kill  ", "Quit  ", NULL};
 
39
static void printHelpFlag() {
40
41
   fputs("htop " VERSION " - " COPYRIGHT "\n"
         "Released under the GNU GPL.\n\n"
42
43
44
45
46
47
         "-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"
48
49
50
51
52
53
         "-v --version          Print version info\n"
         "\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
54
55
56
   exit(0);
}

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

Hisham Muhammad's avatar
Hisham Muhammad committed
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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,
   };
Hisham Muhammad's avatar
Hisham Muhammad committed
76

77
78
79
80
81
82
83
84
85
   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'},
86
      {"pid",      required_argument,   0, 'p'},
Hisham Muhammad's avatar
Hisham Muhammad committed
87
      {"io",       no_argument,         0, 'i'},
88
89
      {0,0,0,0}
   };
90

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

Hisham Muhammad's avatar
Hisham Muhammad committed
139
140
            if( !flags.pidWhiteList ) {
               flags.pidWhiteList = Hashtable_new(8, false);
141
142
143
144
            }

            while( pid ) {
                unsigned int num_pid = atoi(pid);
Hisham Muhammad's avatar
Hisham Muhammad committed
145
                Hashtable_put(flags.pidWhiteList, num_pid, (void *) 1);
146
                pid = strtok_r(NULL, ",", &saveptr);
147
148
149
            }
            free(argCopy);

150
            break;
151
         }
152
153
         default:
            exit(1);
Hisham Muhammad's avatar
Hisham Muhammad committed
154
155
      }
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
156
157
   return flags;
}
158

Hisham Muhammad's avatar
Hisham Muhammad committed
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
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()
180

181
182
183
184
   if (access(PROCDIR, R_OK) != 0) {
      fprintf(stderr, "Error: could not read procfs (compiled to look in %s).\n", PROCDIR);
      exit(1);
   }
185

186
   Process_setupColumnWidths();
Hisham Muhammad's avatar
Hisham Muhammad committed
187
   
Hisham Muhammad's avatar
Hisham Muhammad committed
188
189
190
191
192
193
   UsersTable* ut = UsersTable_new();
   ProcessList* pl = ProcessList_new(ut, flags.pidWhiteList, flags.userId);
   
   Settings* settings = Settings_new(pl->cpuCount);
   pl->settings = settings;

194
195
196
197
   Header* header = Header_new(pl, settings, 2);

   Header_populateFromSettings(header);

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

Hisham Muhammad's avatar
Hisham Muhammad committed
203
   CRT_init(settings->delay, settings->colorScheme);
204

205
206
   FunctionBar* defaultBar = FunctionBar_new(defaultFunctions, NULL, NULL);
   
Hisham Muhammad's avatar
Hisham Muhammad committed
207
208
209
210
211
212
213
214
215
   MainPanel* panel = MainPanel_new(defaultBar);
   ProcessList_setPanel(pl, (Panel*) panel);

   MainPanel_updateTreeFunctions(defaultBar, settings->treeView);
      
   if (flags.sortKey > 0) {
      settings->sortKey = flags.sortKey;
      settings->treeView = false;
      settings->direction = 1;
216
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
217
   ProcessList_printHeader(pl, Panel_getHeader((Panel*)panel));
Hisham Muhammad's avatar
Hisham Muhammad committed
218

219
220
   IncSet* inc = IncSet_new(defaultBar);

Hisham Muhammad's avatar
Hisham Muhammad committed
221
222
223
224
225
226
227
228
229
230
   State state = {
      .inc = inc,
      .settings = settings,
      .ut = ut,
      .pl = pl,
      .panel = (Panel*) panel,
      .header = header,
   };
   MainPanel_setState(panel, &state);
   
231
232
   ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, true);
   ScreenManager_add(scr, (Panel*) panel, defaultBar, -1);
Hisham Muhammad's avatar
Hisham Muhammad committed
233

Hisham Muhammad's avatar
Hisham Muhammad committed
234
   ProcessList_scan(pl);
235
   millisleep(75);
236
   ProcessList_scan(pl);
Hisham Muhammad's avatar
Hisham Muhammad committed
237
238

   ScreenManager_run(scr, NULL, NULL);   
Hisham Muhammad's avatar
Hisham Muhammad committed
239
   
Hisham Muhammad's avatar
Hisham Muhammad committed
240
   /*
Hisham Muhammad's avatar
Hisham Muhammad committed
241
242
243
244
245
246
247
248
   FunctionBar_draw(defaultBar, NULL);
   
   int acc = 0;
   bool follow = false;
 
   struct timeval tv;
   double oldTime = 0.0;

249
   int ch = ERR;
Hisham Muhammad's avatar
Hisham Muhammad committed
250
251
   int closeTimeout = 0;

Hisham Muhammad's avatar
Hisham Muhammad committed
252
   bool drawPanel = true;
253
   
254
255
   bool collapsed = false;
   
Hisham Muhammad's avatar
Hisham Muhammad committed
256
257
   Htop_Action keys[KEY_MAX] = { NULL };
   setBindings(keys);
258
259
260
261
262
263
264
   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
265
   
Hisham Muhammad's avatar
Hisham Muhammad committed
266
267
   while (!quit) {
      gettimeofday(&tv, NULL);
268
      double newTime = ((double)tv.tv_sec * 10) + ((double)tv.tv_usec / 100000);
Hisham Muhammad's avatar
Hisham Muhammad committed
269
270
      bool timeToRecalculate = (newTime - oldTime > settings->delay);
      if (newTime < oldTime) timeToRecalculate = true; // clock was adjusted?
271
      int following = follow ? MainPanel_selectedPid((MainPanel*)panel) : -1;
Hisham Muhammad's avatar
Hisham Muhammad committed
272
      if (timeToRecalculate) {
273
         Header_draw(header);
Hisham Muhammad's avatar
Hisham Muhammad committed
274
         oldTime = newTime;
275
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
276
      if (doRefresh) {
Hisham Muhammad's avatar
Hisham Muhammad committed
277
         if (timeToRecalculate || forceRecalculate) {
Hisham Muhammad's avatar
Hisham Muhammad committed
278
            ProcessList_scan(pl);
Hisham Muhammad's avatar
Hisham Muhammad committed
279
            forceRecalculate = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
280
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
281
         if (sortTimeout == 0 || settings->treeView) {
Hisham Muhammad's avatar
Hisham Muhammad committed
282
            ProcessList_sort(pl);
Hisham Muhammad's avatar
Hisham Muhammad committed
283
            sortTimeout = 1;
Hisham Muhammad's avatar
Hisham Muhammad committed
284
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
285
286
         ProcessList_rebuildPanel(pl, true, following, IncSet_filter(inc));
         drawPanel = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
287
288
      }
      doRefresh = true;
289
      
Hisham Muhammad's avatar
Hisham Muhammad committed
290
      if (settings->treeView) {
291
292
293
294
295
296
297
298
299
300
301
         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
302
303
      } else {
         collapsed = false;
304
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
305

Hisham Muhammad's avatar
Hisham Muhammad committed
306
      if (drawPanel) {
307
         Panel_draw(panel, true);
308
      }
309
      
Hisham Muhammad's avatar
Hisham Muhammad committed
310
      int prev = ch;
311
      if (inc->active)
312
         move(LINES-1, CRT_cursorX);
Hisham Muhammad's avatar
Hisham Muhammad committed
313
314
315
      ch = getch();

      if (ch == ERR) {
316
         if (!inc->active)
Hisham Muhammad's avatar
Hisham Muhammad committed
317
318
            sortTimeout--;
         if (prev == ch && !timeToRecalculate) {
Hisham Muhammad's avatar
Hisham Muhammad committed
319
            closeTimeout++;
320
            if (closeTimeout == 100) {
Hisham Muhammad's avatar
Hisham Muhammad committed
321
               break;
322
            }
Hisham Muhammad's avatar
Hisham Muhammad committed
323
324
         } else
            closeTimeout = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
325
         drawPanel = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
326
327
         continue;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
328
329
330
      drawPanel = true;

      Htop_Reaction reaction = HTOP_OK;
Hisham Muhammad's avatar
Hisham Muhammad committed
331
332
333
334
335

      if (ch == KEY_MOUSE) {
         MEVENT mevent;
         int ok = getmouse(&mevent);
         if (ok == OK) {
336
337
338
339
            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
340
341
342
                  if (field == settings->sortKey) {
                     Settings_invertSortOrder(settings);
                     settings->treeView = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
343
                     reaction |= HTOP_REDRAW_BAR;
344
                  } else {
Hisham Muhammad's avatar
Hisham Muhammad committed
345
                     reaction |= setSortKey(settings, field);
346
                  }
Hisham Muhammad's avatar
Hisham Muhammad committed
347
348
                  sortTimeout = 0;
                  ch = ERR;
349
350
351
               } 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
352
                  ch = ERR;
353
               } if (mevent.y == LINES - 1) {
354
                  ch = FunctionBar_synthesizeEvent(inc->bar, mevent.x);
355
               }
356
357
358
359
360
361
            } 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
362
363
364
365
            }
         }
      }

366
367
      if (inc->active) {
         doRefresh = IncSet_handleKey(inc, ch, panel, getMainPanelValue, NULL);
368
369
370
         if (!inc->active) {
            follow = true;
         }
371
372
373
374
375
376
         continue;
      }
      
      if (isdigit((char)ch)) {
         if (Panel_size(panel) == 0) continue;
         pid_t pid = ch-48 + acc;
377
         for (int i = 0; i < ProcessList_size(pl); i++) {
378
            Panel_setSelected(panel, i);
379
380
381
382
383
            Process* p = (Process*) Panel_getSelected(panel);
            if (p && p->pid == pid) {
               break;
            }
         }
384
385
386
387
388
389
390
391
         acc = pid * 10;
         if (acc > 10000000)
            acc = 0;
         continue;
      } else {
         acc = 0;
      }

Hisham Muhammad's avatar
Hisham Muhammad committed
392
      if(ch != ERR && keys[ch]) {
Hisham Muhammad's avatar
Hisham Muhammad committed
393
         reaction |= (keys[ch])(&state);
Hisham Muhammad's avatar
Hisham Muhammad committed
394
395
396
397
      } else {
         doRefresh = false;
         sortTimeout = resetSortTimeout;
         Panel_onKey(panel, ch);
Hisham Muhammad's avatar
Hisham Muhammad committed
398
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
399
400
      
      // Reaction handlers:
401

Hisham Muhammad's avatar
Hisham Muhammad committed
402
      if (reaction & HTOP_REDRAW_BAR) {
Hisham Muhammad's avatar
Hisham Muhammad committed
403
         updateTreeFunctions(defaultBar, settings->treeView);
Hisham Muhammad's avatar
Hisham Muhammad committed
404
         IncSet_drawBar(inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
405
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
406
      if (reaction & HTOP_UPDATE_PANELHDR) {
407
408
         ProcessList_printHeader(pl, Panel_getHeader(panel));
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
409
      if (reaction & HTOP_REFRESH) {
Hisham Muhammad's avatar
Hisham Muhammad committed
410
         doRefresh = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
411
412
413
414
415
416
417
         sortTimeout = 0;
      }      
      if (reaction & HTOP_RECALCULATE) {
         forceRecalculate = true;
         sortTimeout = 0;
      }
      if (reaction & HTOP_SAVE_SETTINGS) {
Hisham Muhammad's avatar
Hisham Muhammad committed
418
419
         settings->changed = true;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
420
421
422
423
      if (reaction & HTOP_QUIT) {
         quit = true;
      }
      follow = (reaction & HTOP_KEEP_FOLLOWING);
Hisham Muhammad's avatar
Hisham Muhammad committed
424
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
425
426
427
   
   */
   
Hisham Muhammad's avatar
Hisham Muhammad committed
428
429
430
431
432
433
434
435
436
437
   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
438
439

   /*   
Hisham Muhammad's avatar
Hisham Muhammad committed
440
   FunctionBar_delete((Object*)defaultBar);
Hisham Muhammad's avatar
Hisham Muhammad committed
441
   Panel_delete((Object*)panel);
Hisham Muhammad's avatar
Hisham Muhammad committed
442
443
444
   */
   
   ScreenManager_delete(scr);
Hisham Muhammad's avatar
Hisham Muhammad committed
445
446
   
   IncSet_delete(inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
447
448
   UsersTable_delete(ut);
   Settings_delete(settings);
Hisham Muhammad's avatar
Hisham Muhammad committed
449
   
Hisham Muhammad's avatar
Hisham Muhammad committed
450
451
   if(flags.pidWhiteList) {
      Hashtable_delete(flags.pidWhiteList);
452
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
453
454
   return 0;
}