htop.c 12.4 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"
47
48
49
50
51
52
         "-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
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) {
111
112
113
114
115
               fprintf(stderr, "Error: invalid column \"%s\".\n", optarg);
               exit(1);
            }
            break;
         case 'd':
Hisham Muhammad's avatar
Hisham Muhammad committed
116
117
118
            if (sscanf(optarg, "%16d", &(flags.delay)) == 1) {
               if (flags.delay < 1) flags.delay = 1;
               if (flags.delay > 100) flags.delay = 100;
119
120
121
122
            } else {
               fprintf(stderr, "Error: invalid delay value \"%s\".\n", optarg);
               exit(1);
            }
123
124
            break;
         case 'u':
Hisham Muhammad's avatar
Hisham Muhammad committed
125
            if (!Action_setUserOnly(optarg, &(flags.userId))) {
126
127
128
               fprintf(stderr, "Error: invalid user \"%s\".\n", optarg);
               exit(1);
            }
129
130
            break;
         case 'C':
Hisham Muhammad's avatar
Hisham Muhammad committed
131
            flags.useColors = false;
132
            break;
Hisham Muhammad's avatar
Hisham Muhammad committed
133
134
         case 'p': {
            char* argCopy = strdup(optarg);
135
            char* saveptr;
Hisham Muhammad's avatar
Hisham Muhammad committed
136
            char* pid = strtok_r(argCopy, ",", &saveptr);
137

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

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

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

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

180
#ifdef HAVE_PROC
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
#endif
Hisham Muhammad's avatar
Hisham Muhammad committed
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
   MainPanel* panel = MainPanel_new();
Hisham Muhammad's avatar
Hisham Muhammad committed
207
208
   ProcessList_setPanel(pl, (Panel*) panel);

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
230
   ProcessList_scan(pl);
231
   millisleep(75);
232
   ProcessList_scan(pl);
Hisham Muhammad's avatar
Hisham Muhammad committed
233
234

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

245
   int ch = ERR;
Hisham Muhammad's avatar
Hisham Muhammad committed
246
247
   int closeTimeout = 0;

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

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

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

      Htop_Reaction reaction = HTOP_OK;
Hisham Muhammad's avatar
Hisham Muhammad committed
327
328
329
330
331

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

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

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

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

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