FreeBSDProcessList.c 8.47 KB
Newer Older
Hisham Muhammad's avatar
Hisham Muhammad committed
1
/*
Hisham Muhammad's avatar
Hisham Muhammad committed
2
htop - FreeBSDProcessList.c
Hisham Muhammad's avatar
Hisham Muhammad committed
3
4
5
6
7
8
(C) 2014 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/

#include "ProcessList.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
9
#include "FreeBSDProcessList.h"
10
#include "FreeBSDProcess.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
11

Hisham Muhammad's avatar
Hisham Muhammad committed
12
#include <unistd.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
13
#include <stdlib.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
14
#include <sys/types.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
15
#include <sys/sysctl.h>
16
#include <sys/user.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
17
#include <fcntl.h>
18
#include <string.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
19
20
21

/*{

Hisham Muhammad's avatar
Hisham Muhammad committed
22
#include <kvm.h>
23
24
25
26
27
28
#include <sys/param.h>
#include <sys/jail.h>
#include <sys/uio.h>

#define JAIL_ERRMSGLEN	1024
char jail_errmsg[JAIL_ERRMSGLEN];
Hisham Muhammad's avatar
Hisham Muhammad committed
29

30
31
32
33
34
typedef struct CPUData_ {
   unsigned long long int totalTime;
   unsigned long long int totalPeriod;
} CPUData;

Hisham Muhammad's avatar
Hisham Muhammad committed
35
36
37
typedef struct FreeBSDProcessList_ {
   ProcessList super;
   kvm_t* kd;
38
39
40

   CPUData* cpus;

Hisham Muhammad's avatar
Hisham Muhammad committed
41
42
} FreeBSDProcessList;

Hisham Muhammad's avatar
Hisham Muhammad committed
43
44
}*/

Hisham Muhammad's avatar
Hisham Muhammad committed
45
static int MIB_vm_stats_vm_v_wire_count[4];
Hisham Muhammad's avatar
Hisham Muhammad committed
46
static int MIB_vm_stats_vm_v_cache_count[4];
Hisham Muhammad's avatar
Hisham Muhammad committed
47
48
static int MIB_hw_physmem[2];

Hisham Muhammad's avatar
Hisham Muhammad committed
49
50
static int pageSizeKb;

51
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
Hisham Muhammad's avatar
Hisham Muhammad committed
52
53
   FreeBSDProcessList* fpl = calloc(1, sizeof(FreeBSDProcessList));
   ProcessList* pl = (ProcessList*) fpl;
54
   ProcessList_init(pl, Class(FreeBSDProcess), usersTable, pidWhiteList, userId);
Hisham Muhammad's avatar
Hisham Muhammad committed
55
56
57
58
59

   int cpus = 1;
   size_t sizeof_cpus = sizeof(cpus);
   int err = sysctlbyname("hw.ncpu", &cpus, &sizeof_cpus, NULL, 0);
   if (err) cpus = 1;
Hisham Muhammad's avatar
Hisham Muhammad committed
60
   pl->cpuCount = MAX(cpus, 1);
61
   fpl->cpus = realloc(fpl->cpus, cpus * sizeof(CPUData));
Hisham Muhammad's avatar
Hisham Muhammad committed
62
63

   for (int i = 0; i < cpus; i++) {
64
65
      fpl->cpus[i].totalTime = 1;
      fpl->cpus[i].totalPeriod = 1;
Hisham Muhammad's avatar
Hisham Muhammad committed
66
   }
67

Hisham Muhammad's avatar
Hisham Muhammad committed
68
69
70
71
   size_t len;
   len = 4; sysctlnametomib("vm.stats.vm.v_wire_count",  MIB_vm_stats_vm_v_wire_count, &len);
   len = 4; sysctlnametomib("vm.stats.vm.v_cache_count", MIB_vm_stats_vm_v_cache_count, &len);
   len = 2; sysctlnametomib("hw.physmem",                MIB_hw_physmem, &len);
72
73
   pageSizeKb = PAGE_SIZE_KB;

Hisham Muhammad's avatar
Hisham Muhammad committed
74
75
76
77
78
   fpl->kd = kvm_open(NULL, "/dev/null", NULL, 0, NULL);
   assert(fpl->kd);

   return pl;
}
Hisham Muhammad's avatar
Hisham Muhammad committed
79

Hisham Muhammad's avatar
Hisham Muhammad committed
80
81
82
void ProcessList_delete(ProcessList* this) {
   const FreeBSDProcessList* fpl = (FreeBSDProcessList*) this;
   if (fpl->kd) kvm_close(fpl->kd);
83

Hisham Muhammad's avatar
Hisham Muhammad committed
84
85
   ProcessList_done(this);
   free(this);
Hisham Muhammad's avatar
Hisham Muhammad committed
86
87
88
89
}

static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) {
   const FreeBSDProcessList* fpl = (FreeBSDProcessList*) pl;
90

Hisham Muhammad's avatar
Hisham Muhammad committed
91
92
93
94
   size_t len = sizeof(pl->totalMem);
   sysctl(MIB_hw_physmem, 2, &(pl->totalMem), &len, NULL, 0);
   pl->totalMem /= 1024;
   sysctl(MIB_vm_stats_vm_v_wire_count, 4, &(pl->usedMem), &len, NULL, 0);
Hisham Muhammad's avatar
Hisham Muhammad committed
95
   pl->usedMem *= pageSizeKb;
Hisham Muhammad's avatar
Hisham Muhammad committed
96
   pl->freeMem = pl->totalMem - pl->usedMem;
Hisham Muhammad's avatar
Hisham Muhammad committed
97
98
   sysctl(MIB_vm_stats_vm_v_cache_count, 4, &(pl->cachedMem), &len, NULL, 0);
   pl->cachedMem *= pageSizeKb;
99

Hisham Muhammad's avatar
Hisham Muhammad committed
100
101
   struct kvm_swap swap[16];
   int nswap = kvm_getswapinfo(fpl->kd, swap, sizeof(swap)/sizeof(swap[0]), 0);
Hisham Muhammad's avatar
Hisham Muhammad committed
102
   pl->totalSwap = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
103
104
105
106
107
108
109
   pl->usedSwap = 0;
   for (int i = 0; i < nswap; i++) {
      pl->totalSwap += swap[i].ksw_total;
      pl->usedSwap += swap[i].ksw_used;
   }
   pl->totalSwap *= pageSizeKb;
   pl->usedSwap *= pageSizeKb;
110

Hisham Muhammad's avatar
Hisham Muhammad committed
111
112
   pl->sharedMem = 0;  // currently unused
   pl->buffersMem = 0; // not exposed to userspace
Hisham Muhammad's avatar
Hisham Muhammad committed
113
114
}

115
116
117
118
119
120
121
122
123
char* FreeBSDProcessList_readProcessName(kvm_t* kd, struct kinfo_proc* kproc, int* basenameEnd) {
   char** argv = kvm_getargv(kd, kproc, 0);
   if (!argv) {
      return strdup(kproc->ki_comm);
   }
   int len = 0;
   for (int i = 0; argv[i]; i++) {
      len += strlen(argv[i]) + 1;
   }
124
   char* comm = malloc(len);
125
126
127
128
129
130
131
132
133
134
135
136
137
138
   char* at = comm;
   *basenameEnd = 0;
   for (int i = 0; argv[i]; i++) {
      at = stpcpy(at, argv[i]);
      if (!*basenameEnd) {
         *basenameEnd = at - comm;
      }
      *at = ' ';
      at++;
   }
   at--;
   *at = '\0';
   return comm;
}
Hisham Muhammad's avatar
Hisham Muhammad committed
139

140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
char* FreeBSDProcessList_readJailName(struct kinfo_proc* kproc) {
   int    jid;
   struct iovec jiov[6];
   char*  jname;
   char   jnamebuf[MAXHOSTNAMELEN];

   if (kproc->ki_jid != 0 ){
      memset(jnamebuf, 0, sizeof(jnamebuf));
      *(const void **)&jiov[0].iov_base = "jid";
      jiov[0].iov_len = sizeof("jid");
      jiov[1].iov_base = &kproc->ki_jid;
      jiov[1].iov_len = sizeof(kproc->ki_jid);
      *(const void **)&jiov[2].iov_base = "name";
      jiov[2].iov_len = sizeof("name");
      jiov[3].iov_base = jnamebuf;
      jiov[3].iov_len = sizeof(jnamebuf);
      *(const void **)&jiov[4].iov_base = "errmsg";
      jiov[4].iov_len = sizeof("errmsg");
      jiov[5].iov_base = jail_errmsg;
      jiov[5].iov_len = JAIL_ERRMSGLEN;
      jail_errmsg[0] = 0;
      jid = jail_get(jiov, 6, 0);
      if (jid < 0) {
         if (!jail_errmsg[0])
            snprintf(jail_errmsg, JAIL_ERRMSGLEN, "jail_get: %s", strerror(errno));
            return NULL;
      } else if (jid == kproc->ki_jid) {
         jname = strdup(jnamebuf);
         if (jname == NULL)
            strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
         return jname;
      } else {
         return NULL;
      }
   } else {
      jnamebuf[0]='-';
      jnamebuf[1]='\0';
      jname = strdup(jnamebuf);
   }
   return jname;
}

182
183
184
185
186
void ProcessList_goThroughEntries(ProcessList* this) {
   FreeBSDProcessList* fpl = (FreeBSDProcessList*) this;
   Settings* settings = this->settings;
   bool hideKernelThreads = settings->hideKernelThreads;
   bool hideUserlandThreads = settings->hideUserlandThreads;
187

Hisham Muhammad's avatar
Hisham Muhammad committed
188
   FreeBSDProcessList_scanMemoryInfo(this);
189

190
191
   int count = 0;
   struct kinfo_proc* kprocs = kvm_getprocs(fpl->kd, KERN_PROC_ALL, 0, &count);
192

193
194
   for (int i = 0; i < count; i++) {
      struct kinfo_proc* kproc = &kprocs[i];
195

196
      bool preExisting = false;
197
      Process* proc = ProcessList_getProcess(this, kproc->ki_pid, &preExisting, (Process_New) FreeBSDProcess_new);
198
199
      FreeBSDProcess* fp = (FreeBSDProcess*) proc;

200
201
      proc->show = ! ((hideKernelThreads && Process_isKernelThread(fp)) || (hideUserlandThreads && Process_isUserlandThread(proc)));

202

203
      if (!preExisting) {
204
205
206
207
208
209
         fp->jid = kproc->ki_jid;
         proc->pid = kproc->ki_pid;
         if ( ! ((kproc->ki_pid == 0) || (kproc->ki_pid == 1) ) && kproc->ki_flag & P_SYSTEM)
           fp->kernel = 1;
         else
           fp->kernel = 0;
210
211
212
213
214
215
216
217
218
219
         proc->tpgid = kproc->ki_tpgid;
         proc->tgid = kproc->ki_pid;
         proc->session = kproc->ki_sid;
         proc->tty_nr = kproc->ki_tdev;
         proc->pgrp = kproc->ki_pgid;
         proc->st_uid = kproc->ki_uid;
         proc->starttime_ctime = kproc->ki_start.tv_sec;
         proc->user = UsersTable_getRef(this->usersTable, proc->st_uid);
         ProcessList_add((ProcessList*)this, proc);
         proc->comm = FreeBSDProcessList_readProcessName(fpl->kd, kproc, &proc->basenameOffset);
220
         fp->jname = FreeBSDProcessList_readJailName(kproc);
221
      } else {
222
223
224
225
226
         if(fp->jid != kproc->ki_jid) {
            fp->jid = kproc->ki_jid;
            free(fp->jname);
            fp->jname = FreeBSDProcessList_readJailName(kproc);
         }
227
228
229
230
         if(proc->st_uid != kproc->ki_uid) {
            proc->st_uid = kproc->ki_uid;
            proc->user = UsersTable_getRef(this->usersTable, proc->st_uid);
         }
231
232
233
234
235
236
         if (settings->updateProcessNames) {
            free(proc->comm);
            proc->comm = FreeBSDProcessList_readProcessName(fpl->kd, kproc, &proc->basenameOffset);
         }
      }

237
238
      proc->ppid = kproc->ki_ppid;

239
240
241
242
      proc->m_size = kproc->ki_size / pageSizeKb / 1000;
      proc->m_resident = kproc->ki_rssize; // * pageSizeKb;
      proc->nlwp = kproc->ki_numthreads;
      proc->time = (kproc->ki_runtime + 5000) / 10000;
243

244
      proc->priority = kproc->ki_pri.pri_level - PZERO;
245
246
247
248

      if (strcmp("intr", kproc->ki_comm) == 0 && kproc->ki_flag & P_SYSTEM) {
         proc->nice = 0; //@etosan: freebsd intr kernel process (not thread) has weird nice value
      } else if (kproc->ki_pri.pri_class == PRI_TIMESHARE) {
249
250
251
252
253
254
255
         proc->nice = kproc->ki_nice - NZERO;
      } else if (PRI_IS_REALTIME(kproc->ki_pri.pri_class)) {
         proc->nice = PRIO_MIN - 1 - (PRI_MAX_REALTIME - kproc->ki_pri.pri_level);
      } else {
         proc->nice = PRIO_MAX + 1 + kproc->ki_pri.pri_level - PRI_MIN_IDLE;
      }

256

257
258
259
260
261
262
263
264
265
266
267
      switch (kproc->ki_stat) {
      case SIDL:   proc->state = 'I'; break;
      case SRUN:   proc->state = 'R'; break;
      case SSLEEP: proc->state = 'S'; break;
      case SSTOP:  proc->state = 'T'; break;
      case SZOMB:  proc->state = 'Z'; break;
      case SWAIT:  proc->state = 'D'; break;
      case SLOCK:  proc->state = 'L'; break;
      default:     proc->state = '?';
      }

268
      if (Process_isKernelThread(fp)) {
269
270
         this->kernelThreads++;
      }
271

272
273
274
275
276
      this->totalTasks++;
      if (proc->state == 'R')
         this->runningTasks++;
      proc->updated = true;
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
277
}