OpenFilesScreen.c 6.76 KB
Newer Older
Hisham Muhammad's avatar
Hisham Muhammad committed
1
2
3
4
5
6
7
/*
htop - OpenFilesScreen.c
(C) 2005-2006 Hisham H. Muhammad
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
9
10
11
12
#include "OpenFilesScreen.h"

#include "CRT.h"
#include "ProcessList.h"
#include "ListItem.h"
13
14
#include "IncSet.h"
#include "String.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
15
16

#include <string.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
17
18
19
20
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
#include <unistd.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
21
#include <stdlib.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
22
23
24
25
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>

Hisham Muhammad's avatar
Hisham Muhammad committed
26
/*{
Hisham Muhammad's avatar
Hisham Muhammad committed
27
28
29
30
31
32
33
#include "Process.h"
#include "Panel.h"
#include "FunctionBar.h"

typedef struct OpenFiles_ProcessData_ {
   char* data[256];
   struct OpenFiles_FileData_* files;
34
   int error;
Hisham Muhammad's avatar
Hisham Muhammad committed
35
36
37
38
39
40
41
42
43
} OpenFiles_ProcessData;

typedef struct OpenFiles_FileData_ {
   char* data[256];
   struct OpenFiles_FileData_* next;
} OpenFiles_FileData;

typedef struct OpenFilesScreen_ {
   Process* process;
44
   pid_t pid;
Hisham Muhammad's avatar
Hisham Muhammad committed
45
46
47
48
49
50
   Panel* display;
   FunctionBar* bar;
} OpenFilesScreen;

}*/

51
static const char* ofsFunctions[] = {"Search ", "Filter ", "Refresh", "Done   ", NULL};
Hisham Muhammad's avatar
Hisham Muhammad committed
52

53
static const char* ofsKeys[] = {"F3", "F4", "F5", "Esc"};
Hisham Muhammad's avatar
Hisham Muhammad committed
54

55
static int ofsEvents[] = {KEY_F(3), KEY_F(4), KEY_F(5), 27};
Hisham Muhammad's avatar
Hisham Muhammad committed
56
57
58
59

OpenFilesScreen* OpenFilesScreen_new(Process* process) {
   OpenFilesScreen* this = (OpenFilesScreen*) malloc(sizeof(OpenFilesScreen));
   this->process = process;
60
   this->display = Panel_new(0, 1, COLS, LINES-3, false, Class(ListItem));
61
62
63
64
   if (Process_isThread(process))
      this->pid = process->tgid;
   else
      this->pid = process->pid;
Hisham Muhammad's avatar
Hisham Muhammad committed
65
66
67
68
69
70
71
72
   return this;
}

void OpenFilesScreen_delete(OpenFilesScreen* this) {
   Panel_delete((Object*)this->display);
   free(this);
}

73
static void OpenFilesScreen_draw(OpenFilesScreen* this, IncSet* inc) {
Hisham Muhammad's avatar
Hisham Muhammad committed
74
75
   attrset(CRT_colors[METER_TEXT]);
   mvhline(0, 0, ' ', COLS);
76
   mvprintw(0, 0, "Snapshot of files open in process %d - %s", this->pid, this->process->comm);
Hisham Muhammad's avatar
Hisham Muhammad committed
77
78
   attrset(CRT_colors[DEFAULT_COLOR]);
   Panel_draw(this->display, true);
79
   IncSet_drawBar(inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
80
81
}

82
static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
Hisham Muhammad's avatar
Hisham Muhammad committed
83
   char command[1025];
Hisham Muhammad's avatar
Hisham Muhammad committed
84
   snprintf(command, 1024, "lsof -P -p %d -F 2> /dev/null", pid);
Hisham Muhammad's avatar
Hisham Muhammad committed
85
   FILE* fd = popen(command, "r");
86
87
88
   OpenFiles_ProcessData* pdata = calloc(sizeof(OpenFiles_ProcessData), 1);
   OpenFiles_FileData* fdata = NULL;
   OpenFiles_ProcessData* item = pdata;
Hisham Muhammad's avatar
Hisham Muhammad committed
89
   bool anyRead = false;
90
   if (!fd) {
91
92
      pdata->error = 127;
      return pdata;
93
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
94
95
   while (!feof(fd)) {
      int cmd = fgetc(fd);
96
      if (cmd == EOF && !anyRead)
Hisham Muhammad's avatar
Hisham Muhammad committed
97
98
99
         break;
      anyRead = true;
      char* entry = malloc(1024);
Hisham Muhammad's avatar
Hisham Muhammad committed
100
101
102
103
      if (!fgets(entry, 1024, fd)) {
         free(entry);
         break;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
104
105
106
107
      char* newline = strrchr(entry, '\n');
      *newline = '\0';
      if (cmd == 'f') {
         OpenFiles_FileData* nextFile = calloc(sizeof(OpenFiles_ProcessData), 1);
108
109
         if (fdata == NULL) {
            pdata->files = nextFile;
Hisham Muhammad's avatar
Hisham Muhammad committed
110
         } else {
111
            fdata->next = nextFile;
Hisham Muhammad's avatar
Hisham Muhammad committed
112
         }
113
114
         fdata = nextFile;
         item = (OpenFiles_ProcessData*) fdata;
Hisham Muhammad's avatar
Hisham Muhammad committed
115
116
117
      }
      item->data[cmd] = entry;
   }
118
119
   pdata->error = pclose(fd);
   return pdata;
Hisham Muhammad's avatar
Hisham Muhammad committed
120
121
}

122
123
124
125
126
127
128
static inline void addLine(const char* line, Vector* lines, Panel* panel, const char* incFilter) {
   Vector_add(lines, (Object*) ListItem_new(line, 0));
   if (!incFilter || String_contains_i(line, incFilter))
      Panel_add(panel, (Object*)Vector_get(lines, Vector_size(lines)-1));
}

static void OpenFilesScreen_scan(OpenFilesScreen* this, Vector* lines, IncSet* inc) {
Hisham Muhammad's avatar
Hisham Muhammad committed
129
   Panel* panel = this->display;
130
   int idx = Panel_getSelectedIndex(panel);
Hisham Muhammad's avatar
Hisham Muhammad committed
131
   Panel_prune(panel);
132
133
134
135
136
   OpenFiles_ProcessData* pdata = OpenFilesScreen_getProcessData(this->pid);
   if (pdata->error == 127) {
      addLine("Could not execute 'lsof'. Please make sure it is available in your $PATH.", lines, panel, IncSet_filter(inc));
   } else if (pdata->error == 1) {
      addLine("Failed listing open files.", lines, panel, IncSet_filter(inc));
Hisham Muhammad's avatar
Hisham Muhammad committed
137
   } else {
138
139
      OpenFiles_FileData* fdata = pdata->files;
      while (fdata) {
Hisham Muhammad's avatar
Hisham Muhammad committed
140
141
         char entry[1024];
         sprintf(entry, "%5s %4s %10s %10s %10s %s",
142
143
144
145
146
147
148
            fdata->data['f'] ? fdata->data['f'] : "",
            fdata->data['t'] ? fdata->data['t'] : "",
            fdata->data['D'] ? fdata->data['D'] : "",
            fdata->data['s'] ? fdata->data['s'] : "",
            fdata->data['i'] ? fdata->data['i'] : "",
            fdata->data['n'] ? fdata->data['n'] : "");
         addLine(entry, lines, panel, IncSet_filter(inc));
Hisham Muhammad's avatar
Hisham Muhammad committed
149
         for (int i = 0; i < 255; i++)
150
151
152
153
            if (fdata->data[i])
               free(fdata->data[i]);
         OpenFiles_FileData* old = fdata;
         fdata = fdata->next;
Hisham Muhammad's avatar
Hisham Muhammad committed
154
155
156
         free(old);
      }
      for (int i = 0; i < 255; i++)
157
158
         if (pdata->data[i])
            free(pdata->data[i]);
Hisham Muhammad's avatar
Hisham Muhammad committed
159
   }
160
161
   free(pdata);
   Vector_insertionSort(lines);
162
   Vector_insertionSort(panel->items);
Hisham Muhammad's avatar
Hisham Muhammad committed
163
   Panel_setSelected(panel, idx);
Hisham Muhammad's avatar
Hisham Muhammad committed
164
165
166
167
168
}

void OpenFilesScreen_run(OpenFilesScreen* this) {
   Panel* panel = this->display;
   Panel_setHeader(panel, "   FD TYPE     DEVICE       SIZE       NODE NAME");
169
170
171
172

   FunctionBar* bar = FunctionBar_new(ofsFunctions, ofsKeys, ofsEvents);
   IncSet* inc = IncSet_new(bar);
   
173
   Vector* lines = Vector_new(panel->items->type, true, DEFAULT_SIZE);
174
175
176

   OpenFilesScreen_scan(this, lines, inc);
   OpenFilesScreen_draw(this, inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
177
178
179
   
   bool looping = true;
   while (looping) {
180
   
Hisham Muhammad's avatar
Hisham Muhammad committed
181
      Panel_draw(panel, true);
182
183
184
      
      if (inc->active)
         move(LINES-1, CRT_cursorX);
Hisham Muhammad's avatar
Hisham Muhammad committed
185
      int ch = getch();
186
      
Hisham Muhammad's avatar
Hisham Muhammad committed
187
188
189
190
191
192
193
194
      if (ch == KEY_MOUSE) {
         MEVENT mevent;
         int ok = getmouse(&mevent);
         if (ok == OK)
            if (mevent.y >= panel->y && mevent.y < LINES - 1) {
               Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV);
               ch = 0;
            } if (mevent.y == LINES - 1)
195
               ch = FunctionBar_synthesizeEvent(inc->bar, mevent.x);
Hisham Muhammad's avatar
Hisham Muhammad committed
196
      }
197
198
199
200
201
202

      if (inc->active) {
         IncSet_handleKey(inc, ch, panel, IncSet_getListItemValue, lines);
         continue;
      }

Hisham Muhammad's avatar
Hisham Muhammad committed
203
204
205
      switch(ch) {
      case ERR:
         continue;
206
207
208
209
210
211
212
213
      case KEY_F(3):
      case '/':
         IncSet_activate(inc, INC_SEARCH);
         break;
      case KEY_F(4):
      case '\\':
         IncSet_activate(inc, INC_FILTER);
         break;
Hisham Muhammad's avatar
Hisham Muhammad committed
214
215
      case KEY_F(5):
         clear();
216
217
         OpenFilesScreen_scan(this, lines, inc);
         OpenFilesScreen_draw(this, inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
218
219
220
         break;
      case '\014': // Ctrl+L
         clear();
221
         OpenFilesScreen_draw(this, inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
222
223
224
         break;
      case 'q':
      case 27:
225
      case KEY_F(10):
Hisham Muhammad's avatar
Hisham Muhammad committed
226
227
228
229
         looping = false;
         break;
      case KEY_RESIZE:
         Panel_resize(panel, COLS, LINES-2);
230
         OpenFilesScreen_draw(this, inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
231
232
233
234
235
         break;
      default:
         Panel_onKey(panel, ch);
      }
   }
236

237
   Vector_delete(lines);
238
239
   FunctionBar_delete((Object*)bar);
   IncSet_delete(inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
240
}