TraceScreen.c 4.89 KB
Newer Older
Hisham Muhammad's avatar
Hisham Muhammad committed
1
2
/*
htop - TraceScreen.c
Hisham Muhammad's avatar
Hisham Muhammad committed
3
(C) 2005-2006 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
9
10
#include "TraceScreen.h"

#include "CRT.h"
11
#include "InfoScreen.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
12
13
#include "ProcessList.h"
#include "ListItem.h"
14
#include "IncSet.h"
David Hunt's avatar
David Hunt committed
15
#include "StringUtils.h"
16
#include "FunctionBar.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
17

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

Hisham Muhammad's avatar
Hisham Muhammad committed
30
/*{
31
#include "InfoScreen.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
32
33

typedef struct TraceScreen_ {
34
   InfoScreen super;
Hisham Muhammad's avatar
Hisham Muhammad committed
35
   bool tracing;
36
37
38
39
40
41
   int fdpair[2];
   int child;
   FILE* strace;
   int fd_strace;
   bool contLine;
   bool follow;
Hisham Muhammad's avatar
Hisham Muhammad committed
42
43
44
45
} TraceScreen;

}*/

Richard's avatar
Richard committed
46
static const char* const TraceScreenFunctions[] = {"Search ", "Filter ", "AutoScroll ", "Stop Tracing   ", "Done   ", NULL};
Hisham Muhammad's avatar
Hisham Muhammad committed
47

Richard's avatar
Richard committed
48
static const char* const TraceScreenKeys[] = {"F3", "F4", "F8", "F9", "Esc"};
Hisham Muhammad's avatar
Hisham Muhammad committed
49

50
static int TraceScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(8), KEY_F(9), 27};
Hisham Muhammad's avatar
Hisham Muhammad committed
51

52
53
54
55
56
57
58
59
60
61
InfoScreenClass TraceScreen_class = {
   .super = {
      .extends = Class(Object),
      .delete = TraceScreen_delete
   },
   .draw = TraceScreen_draw,
   .onErr = TraceScreen_updateTrace,
   .onKey = TraceScreen_onKey,
};

Hisham Muhammad's avatar
Hisham Muhammad committed
62
TraceScreen* TraceScreen_new(Process* process) {
Hisham's avatar
Hisham committed
63
   TraceScreen* this = xMalloc(sizeof(TraceScreen));
64
   Object_setClass(this, Class(TraceScreen));
Hisham Muhammad's avatar
Hisham Muhammad committed
65
   this->tracing = true;
66
67
68
69
70
   this->contLine = false;
   this->follow = false;
   FunctionBar* fuBar = FunctionBar_new(TraceScreenFunctions, TraceScreenKeys, TraceScreenEvents);
   CRT_disableDelay();
   return (TraceScreen*) InfoScreen_init(&this->super, process, fuBar, LINES-2, "");
Hisham Muhammad's avatar
Hisham Muhammad committed
71
72
}

73
74
75
76
77
78
79
80
81
void TraceScreen_delete(Object* cast) {
   TraceScreen* this = (TraceScreen*) cast;
   if (this->child > 0) {
      kill(this->child, SIGTERM);
      waitpid(this->child, NULL, 0);
      fclose(this->strace);
   }
   CRT_enableDelay();
   free(InfoScreen_done((InfoScreen*)cast));
Hisham Muhammad's avatar
Hisham Muhammad committed
82
83
}

84
void TraceScreen_draw(InfoScreen* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
85
86
87
88
   attrset(CRT_colors[PANEL_HEADER_FOCUS]);
   mvhline(0, 0, ' ', COLS);
   mvprintw(0, 0, "Trace of process %d - %s", this->process->pid, this->process->comm);
   attrset(CRT_colors[DEFAULT_COLOR]);
89
   IncSet_drawBar(this->inc);
90
91
}

92
bool TraceScreen_forkTracer(TraceScreen* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
93
   char buffer[1001];
94
95
96
97
98
   int err = pipe(this->fdpair);
   if (err == -1) return false;
   this->child = fork();
   if (this->child == -1) return false;
   if (this->child == 0) {
99
      CRT_dropPrivileges();
100
101
      dup2(this->fdpair[1], STDERR_FILENO);
      int ok = fcntl(this->fdpair[1], F_SETFL, O_NONBLOCK);
102
      if (ok != -1) {
103
         snprintf(buffer, sizeof(buffer), "%d", this->super.process->pid);
104
105
         execlp("strace", "strace", "-p", buffer, NULL);
      }
106
      const char* message = "Could not execute 'strace'. Please make sure it is available in your $PATH.";
107
      ssize_t written = write(this->fdpair[1], message, strlen(message));
Christian Hesse's avatar
Christian Hesse committed
108
      (void) written;
Hisham Muhammad's avatar
Hisham Muhammad committed
109
110
      exit(1);
   }
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
   fcntl(this->fdpair[0], F_SETFL, O_NONBLOCK);
   this->strace = fdopen(this->fdpair[0], "r");
   this->fd_strace = fileno(this->strace);
   return true;
}

void TraceScreen_updateTrace(InfoScreen* super) {
   TraceScreen* this = (TraceScreen*) super;
   char buffer[1001];
   fd_set fds;
   FD_ZERO(&fds);
// FD_SET(STDIN_FILENO, &fds);
   FD_SET(this->fd_strace, &fds);
   struct timeval tv;
   tv.tv_sec = 0; tv.tv_usec = 500;
   int ready = select(this->fd_strace+1, &fds, NULL, NULL, &tv);
   int nread = 0;
   if (ready > 0 && FD_ISSET(this->fd_strace, &fds))
      nread = fread(buffer, 1, 1000, this->strace);
   if (nread && this->tracing) {
      char* line = buffer;
      buffer[nread] = '\0';
      for (int i = 0; i < nread; i++) {
         if (buffer[i] == '\n') {
            buffer[i] = '\0';
            if (this->contLine) {
               InfoScreen_appendLine(&this->super, line);
               this->contLine = false;
            } else {
               InfoScreen_addLine(&this->super, line);
141
            }
142
            line = buffer+i+1;
Hisham Muhammad's avatar
Hisham Muhammad committed
143
144
         }
      }
145
146
147
148
      if (line < buffer+nread) {
         InfoScreen_addLine(&this->super, line);
         buffer[nread] = '\0';
         this->contLine = true;
149
      }
150
151
152
153
154
155
156
157
      if (this->follow)
         Panel_setSelected(this->super.display, Panel_size(this->super.display)-1);
   }
}

bool TraceScreen_onKey(InfoScreen* super, int ch) {
   TraceScreen* this = (TraceScreen*) super;
   switch(ch) {
158
159
      case 'f':
      case KEY_F(8):
160
161
162
163
         this->follow = !(this->follow);
         if (this->follow)
            Panel_setSelected(super->display, Panel_size(super->display)-1);
         return true;
164
165
166
      case 't':
      case KEY_F(9):
         this->tracing = !this->tracing;
167
168
169
         FunctionBar_setLabel(super->display->defaultBar, KEY_F(9), this->tracing?"Stop Tracing   ":"Resume Tracing ");
         InfoScreen_draw(this);
         return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
170
   }
171
172
   this->follow = false;
   return false;
Hisham Muhammad's avatar
Hisham Muhammad committed
173
}