htop.c 12.8 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
188
189
190
191
192
193
194
195
196
197
198
199
200
#ifdef HAVE_LIBNCURSESW
   char *locale = setlocale(LC_ALL, NULL);
   if (locale == NULL || locale[0] == '\0')
      locale = setlocale(LC_CTYPE, NULL);
   if (locale != NULL &&
       (strstr(locale, "UTF-8") ||
        strstr(locale, "utf-8") ||
        strstr(locale, "UTF8")  ||
        strstr(locale, "utf8")))
      CRT_utf8 = true;
   else
      CRT_utf8 = false;
#endif

201
   Process_setupColumnWidths();
Hisham Muhammad's avatar
Hisham Muhammad committed
202
   
Hisham Muhammad's avatar
Hisham Muhammad committed
203
204
205
206
207
208
   UsersTable* ut = UsersTable_new();
   ProcessList* pl = ProcessList_new(ut, flags.pidWhiteList, flags.userId);
   
   Settings* settings = Settings_new(pl->cpuCount);
   pl->settings = settings;

209
210
211
212
   Header* header = Header_new(pl, settings, 2);

   Header_populateFromSettings(header);

Hisham Muhammad's avatar
Hisham Muhammad committed
213
214
215
   if (flags.delay != -1)
      settings->delay = flags.delay;
   if (!flags.useColors) 
216
      settings->colorScheme = COLORSCHEME_MONOCHROME;
217

Hisham Muhammad's avatar
Hisham Muhammad committed
218
   CRT_init(settings->delay, settings->colorScheme);
219
   
220
   MainPanel* panel = MainPanel_new();
Hisham Muhammad's avatar
Hisham Muhammad committed
221
222
   ProcessList_setPanel(pl, (Panel*) panel);

223
   MainPanel_updateTreeFunctions(panel, settings->treeView);
Hisham Muhammad's avatar
Hisham Muhammad committed
224
225
226
227
228
      
   if (flags.sortKey > 0) {
      settings->sortKey = flags.sortKey;
      settings->treeView = false;
      settings->direction = 1;
229
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
230
   ProcessList_printHeader(pl, Panel_getHeader((Panel*)panel));
Hisham Muhammad's avatar
Hisham Muhammad committed
231

Hisham Muhammad's avatar
Hisham Muhammad committed
232
233
234
235
236
237
238
239
240
   State state = {
      .settings = settings,
      .ut = ut,
      .pl = pl,
      .panel = (Panel*) panel,
      .header = header,
   };
   MainPanel_setState(panel, &state);
   
241
   ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, true);
242
   ScreenManager_add(scr, (Panel*) panel, -1);
Hisham Muhammad's avatar
Hisham Muhammad committed
243

Hisham Muhammad's avatar
Hisham Muhammad committed
244
   ProcessList_scan(pl);
245
   millisleep(75);
246
   ProcessList_scan(pl);
Hisham Muhammad's avatar
Hisham Muhammad committed
247
248

   ScreenManager_run(scr, NULL, NULL);   
Hisham Muhammad's avatar
Hisham Muhammad committed
249
   
Hisham Muhammad's avatar
Hisham Muhammad committed
250
   /*
Hisham Muhammad's avatar
Hisham Muhammad committed
251
252
253
254
255
256
257
258
   FunctionBar_draw(defaultBar, NULL);
   
   int acc = 0;
   bool follow = false;
 
   struct timeval tv;
   double oldTime = 0.0;

259
   int ch = ERR;
Hisham Muhammad's avatar
Hisham Muhammad committed
260
261
   int closeTimeout = 0;

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

Hisham Muhammad's avatar
Hisham Muhammad committed
316
      if (drawPanel) {
317
         Panel_draw(panel, true);
318
      }
319
      
Hisham Muhammad's avatar
Hisham Muhammad committed
320
      int prev = ch;
321
      if (inc->active)
322
         move(LINES-1, CRT_cursorX);
Hisham Muhammad's avatar
Hisham Muhammad committed
323
324
325
      ch = getch();

      if (ch == ERR) {
326
         if (!inc->active)
Hisham Muhammad's avatar
Hisham Muhammad committed
327
328
            sortTimeout--;
         if (prev == ch && !timeToRecalculate) {
Hisham Muhammad's avatar
Hisham Muhammad committed
329
            closeTimeout++;
330
            if (closeTimeout == 100) {
Hisham Muhammad's avatar
Hisham Muhammad committed
331
               break;
332
            }
Hisham Muhammad's avatar
Hisham Muhammad committed
333
334
         } else
            closeTimeout = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
335
         drawPanel = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
336
337
         continue;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
338
339
340
      drawPanel = true;

      Htop_Reaction reaction = HTOP_OK;
Hisham Muhammad's avatar
Hisham Muhammad committed
341
342
343
344
345

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

376
377
      if (inc->active) {
         doRefresh = IncSet_handleKey(inc, ch, panel, getMainPanelValue, NULL);
378
379
380
         if (!inc->active) {
            follow = true;
         }
381
382
383
384
385
386
         continue;
      }
      
      if (isdigit((char)ch)) {
         if (Panel_size(panel) == 0) continue;
         pid_t pid = ch-48 + acc;
387
         for (int i = 0; i < ProcessList_size(pl); i++) {
388
            Panel_setSelected(panel, i);
389
390
391
392
393
            Process* p = (Process*) Panel_getSelected(panel);
            if (p && p->pid == pid) {
               break;
            }
         }
394
395
396
397
398
399
400
401
         acc = pid * 10;
         if (acc > 10000000)
            acc = 0;
         continue;
      } else {
         acc = 0;
      }

Hisham Muhammad's avatar
Hisham Muhammad committed
402
      if(ch != ERR && keys[ch]) {
Hisham Muhammad's avatar
Hisham Muhammad committed
403
         reaction |= (keys[ch])(&state);
Hisham Muhammad's avatar
Hisham Muhammad committed
404
405
406
407
      } else {
         doRefresh = false;
         sortTimeout = resetSortTimeout;
         Panel_onKey(panel, ch);
Hisham Muhammad's avatar
Hisham Muhammad committed
408
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
409
410
      
      // Reaction handlers:
411

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

   /*   
Hisham Muhammad's avatar
Hisham Muhammad committed
450
   FunctionBar_delete((Object*)defaultBar);
Hisham Muhammad's avatar
Hisham Muhammad committed
451
   Panel_delete((Object*)panel);
Hisham Muhammad's avatar
Hisham Muhammad committed
452
453
454
   */
   
   ScreenManager_delete(scr);
Hisham Muhammad's avatar
Hisham Muhammad committed
455
   
Hisham Muhammad's avatar
Hisham Muhammad committed
456
457
   UsersTable_delete(ut);
   Settings_delete(settings);
Hisham Muhammad's avatar
Hisham Muhammad committed
458
   
Hisham Muhammad's avatar
Hisham Muhammad committed
459
460
   if(flags.pidWhiteList) {
      Hashtable_delete(flags.pidWhiteList);
461
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
462
463
   return 0;
}