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"
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
37
   exit(0);
}

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

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

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

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

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

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

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

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

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

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

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

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

   Header_populateFromSettings(header);

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

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

206
207
   FunctionBar* defaultBar = FunctionBar_new(defaultFunctions, NULL, NULL);
   
Hisham Muhammad's avatar
Hisham Muhammad committed
208
209
210
211
212
213
214
215
216
   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;
217
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
218
   ProcessList_printHeader(pl, Panel_getHeader((Panel*)panel));
Hisham Muhammad's avatar
Hisham Muhammad committed
219

220
221
   IncSet* inc = IncSet_new(defaultBar);

Hisham Muhammad's avatar
Hisham Muhammad committed
222
223
224
225
226
227
228
229
230
231
   State state = {
      .inc = inc,
      .settings = settings,
      .ut = ut,
      .pl = pl,
      .panel = (Panel*) panel,
      .header = header,
   };
   MainPanel_setState(panel, &state);
   
232
233
   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
234

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

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

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

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

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

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

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

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

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

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

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

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