OpenFilesScreen.c 6.84 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
#include "IncSet.h"
David Hunt's avatar
David Hunt committed
14
#include "StringUtils.h"
15
#include "FunctionBar.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
16
17

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
31
32
33
34
typedef struct OpenFiles_Data_ {
   char* data[256];
} OpenFiles_Data;

Hisham Muhammad's avatar
Hisham Muhammad committed
35
typedef struct OpenFiles_ProcessData_ {
Hisham Muhammad's avatar
Hisham Muhammad committed
36
   OpenFiles_Data data;
37
   int error;
Hisham Muhammad's avatar
Hisham Muhammad committed
38
   struct OpenFiles_FileData_* files;
Hisham Muhammad's avatar
Hisham Muhammad committed
39
40
41
} OpenFiles_ProcessData;

typedef struct OpenFiles_FileData_ {
Hisham Muhammad's avatar
Hisham Muhammad committed
42
   OpenFiles_Data data;
Hisham Muhammad's avatar
Hisham Muhammad committed
43
44
45
46
47
   struct OpenFiles_FileData_* next;
} OpenFiles_FileData;

typedef struct OpenFilesScreen_ {
   Process* process;
48
   pid_t pid;
Hisham Muhammad's avatar
Hisham Muhammad committed
49
50
51
52
53
   Panel* display;
} OpenFilesScreen;

}*/

54
static const char* OpenFilesScreenFunctions[] = {"Search ", "Filter ", "Refresh", "Done   ", NULL};
Hisham Muhammad's avatar
Hisham Muhammad committed
55

56
static const char* OpenFilesScreenKeys[] = {"F3", "F4", "F5", "Esc"};
Hisham Muhammad's avatar
Hisham Muhammad committed
57

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

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

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

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

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

125
126
127
128
129
130
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));
}

Hisham Muhammad's avatar
Hisham Muhammad committed
131
132
133
134
135
136
static inline void OpenFiles_Data_clear(OpenFiles_Data* data) {
   for (int i = 0; i < 255; i++)
      if (data->data[i])
         free(data->data[i]);
}

137
static void OpenFilesScreen_scan(OpenFilesScreen* this, Vector* lines, IncSet* inc) {
Hisham Muhammad's avatar
Hisham Muhammad committed
138
   Panel* panel = this->display;
139
   int idx = Panel_getSelectedIndex(panel);
Hisham Muhammad's avatar
Hisham Muhammad committed
140
   Panel_prune(panel);
141
142
143
144
145
   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
146
   } else {
147
148
      OpenFiles_FileData* fdata = pdata->files;
      while (fdata) {
Hisham Muhammad's avatar
Hisham Muhammad committed
149
         char entry[1024];
Hisham Muhammad's avatar
Hisham Muhammad committed
150
         char** data = fdata->data.data;
Hisham Muhammad's avatar
Hisham Muhammad committed
151
         sprintf(entry, "%5s %4s %10s %10s %10s %s",
Hisham Muhammad's avatar
Hisham Muhammad committed
152
153
154
155
156
157
            data['f'] ? data['f'] : "",
            data['t'] ? data['t'] : "",
            data['D'] ? data['D'] : "",
            data['s'] ? data['s'] : "",
            data['i'] ? data['i'] : "",
            data['n'] ? data['n'] : "");
158
         addLine(entry, lines, panel, IncSet_filter(inc));
Hisham Muhammad's avatar
Hisham Muhammad committed
159
         OpenFiles_Data_clear(&fdata->data);
160
161
         OpenFiles_FileData* old = fdata;
         fdata = fdata->next;
Hisham Muhammad's avatar
Hisham Muhammad committed
162
163
         free(old);
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
164
      OpenFiles_Data_clear(&pdata->data);
Hisham Muhammad's avatar
Hisham Muhammad committed
165
   }
166
167
   free(pdata);
   Vector_insertionSort(lines);
168
   Vector_insertionSort(panel->items);
Hisham Muhammad's avatar
Hisham Muhammad committed
169
   Panel_setSelected(panel, idx);
Hisham Muhammad's avatar
Hisham Muhammad committed
170
171
172
173
174
}

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

176
   FunctionBar* bar = panel->defaultBar;
177
178
   IncSet* inc = IncSet_new(bar);
   
179
   Vector* lines = Vector_new(panel->items->type, true, DEFAULT_SIZE);
180
181
182

   OpenFilesScreen_scan(this, lines, inc);
   OpenFilesScreen_draw(this, inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
183
184
185
   
   bool looping = true;
   while (looping) {
186
   
Hisham Muhammad's avatar
Hisham Muhammad committed
187
      Panel_draw(panel, true);
188
189
190
      
      if (inc->active)
         move(LINES-1, CRT_cursorX);
Hisham Muhammad's avatar
Hisham Muhammad committed
191
      int ch = getch();
192
      
Hisham Muhammad's avatar
Hisham Muhammad committed
193
194
195
196
197
198
199
200
      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)
201
               ch = IncSet_synthesizeEvent(inc, mevent.x);
Hisham Muhammad's avatar
Hisham Muhammad committed
202
      }
203
204
205
206
207
208

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

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

243
   Vector_delete(lines);
244
   IncSet_delete(inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
245
}