Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / ksysguard / ksysguardd / FreeBSD / ProcessList.c
blob3185bf9a6b4bc4771a800ae7bc7757efc1d1e04f
1 /*
2 KSysGuard, the KDE System Guard
4 Copyright (c) 1999-2000 Hans Petter Bieker<bieker@kde.org>
5 Copyright (c) 1999 Chris Schlaeger <cs@kde.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <ctype.h>
24 #include <dirent.h>
25 #include <pwd.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/param.h>
31 #if defined(__DragonFly__)
32 #include <sys/user.h>
33 #include <sys/resourcevar.h>
34 #endif
36 #if __FreeBSD_version > 500015
37 #include <sys/priority.h>
38 #endif
39 #include <sys/sysctl.h>
40 #include <sys/time.h>
41 #include <sys/types.h>
42 #include <sys/user.h>
43 #include <unistd.h>
44 #include <signal.h>
46 #include "../../gui/SignalIDs.h"
47 #include "Command.h"
48 #include "ProcessList.h"
49 #include "ccont.h"
50 #include "ksysguardd.h"
52 CONTAINER ProcessList = 0;
54 int fscale;
56 #define BUFSIZE 1024
58 typedef struct
60 /* This flag is set for all found processes at the beginning of the
61 * process list update. Processes that do not have this flag set will
62 * be assumed dead and removed from the list. The flag is cleared after
63 * each list update. */
64 int alive;
66 /* the process ID */
67 pid_t pid;
69 /* the parent process ID */
70 pid_t ppid;
72 /* the real user ID */
73 uid_t uid;
75 /* the real group ID */
76 gid_t gid;
78 /* a character description of the process status */
79 char status[16];
81 /* the number of the tty the process owns */
82 int ttyNo;
85 * The nice level. The range should be -20 to 20. I'm not sure
86 * whether this is true for all platforms.
88 int niceLevel;
91 * The scheduling priority.
93 int priority;
96 * The total amount of memory the process uses. This includes shared and
97 * swapped memory.
99 unsigned int vmSize;
102 * The amount of physical memory the process currently uses.
104 unsigned int vmRss;
107 * The amount of memory (shared/swapped/etc) the process shares with
108 * other processes.
110 unsigned int vmLib;
113 * The number of 1/100 of a second the process has spend in user space.
114 * If a machine has an uptime of 1 1/2 years or longer this is not a
115 * good idea. I never thought that the stability of UNIX could get me
116 * into trouble! ;)
118 #if !defined(__DragonFly__)
119 unsigned int userTime;
120 #else
121 long userTime;
122 #endif
125 * The number of 1/100 of a second the process has spend in system space.
126 * If a machine has an uptime of 1 1/2 years or longer this is not a
127 * good idea. I never thought that the stability of UNIX could get me
128 * into trouble! ;)
130 unsigned int sysTime;
132 /* system time as multime of 100ms */
133 int centStamp;
135 /* the current CPU load (in %) from user space */
136 double userLoad;
138 /* the current CPU load (in %) from system space */
139 double sysLoad;
141 /* the name of the process */
142 char name[64];
144 /* the command used to start the process */
145 char cmdline[256];
147 /* the login name of the user that owns this process */
148 char userName[32];
149 } ProcessInfo;
151 static unsigned ProcessCount;
153 static int
154 processCmp(void* p1, void* p2)
156 return (((ProcessInfo*) p1)->pid - ((ProcessInfo*) p2)->pid);
159 static ProcessInfo*
160 findProcessInList(int pid)
162 ProcessInfo key;
163 long index;
165 key.pid = pid;
166 if ((index = search_ctnr(ProcessList, processCmp, &key)) < 0)
167 return (0);
169 return (get_ctnr(ProcessList, index));
172 static int
173 updateProcess(int pid)
175 static char *statuses[] = { "idle","run","sleep","stop","zombie" };
177 ProcessInfo* ps;
178 struct passwd* pwent;
179 int mib[4];
180 struct kinfo_proc p;
181 struct rusage pru;
182 size_t len;
183 size_t buflen = 256;
184 char buf[256];
186 if ((ps = findProcessInList(pid)) == 0)
188 ps = (ProcessInfo*) malloc(sizeof(ProcessInfo));
189 ps->pid = pid;
190 ps->centStamp = 0;
191 push_ctnr(ProcessList, ps);
192 bsort_ctnr(ProcessList, processCmp);
195 ps->alive = 1;
197 mib[0] = CTL_KERN;
198 mib[1] = KERN_PROC;
199 mib[2] = KERN_PROC_PID;
200 mib[3] = pid;
202 len = sizeof (p);
203 if (sysctl(mib, 4, &p, &len, NULL, 0) == -1 || !len)
204 return -1;
206 #if __FreeBSD_version >= 500015
207 ps->pid = p.ki_pid;
208 ps->ppid = p.ki_ppid;
209 ps->uid = p.ki_uid;
210 ps->gid = p.ki_pgid;
211 ps->priority = p.ki_pri.pri_user;
212 ps->niceLevel = p.ki_nice;
213 #elif defined(__DragonFly__) && __DragonFly_version >= 190000
214 ps->pid = p.kp_pid;
215 ps->ppid = p.kp_ppid;
216 ps->uid = p.kp_uid;
217 ps->gid = p.kp_pgid;
218 ps->priority = p.kp_lwp.kl_tdprio;
219 ps->niceLevel = p.kp_nice;
220 #else
221 ps->pid = p.kp_proc.p_pid;
222 ps->ppid = p.kp_eproc.e_ppid;
223 ps->uid = p.kp_eproc.e_ucred.cr_uid;
224 ps->gid = p.kp_eproc.e_pgid;
225 #if defined(__DragonFly__)
226 ps->priority = p.kp_thread.td_pri;
227 #else
228 ps->priority = p.kp_proc.p_priority;
229 #endif
230 ps->niceLevel = p.kp_proc.p_nice;
231 #endif
233 /* this isn't usertime -- it's total time (??) */
234 #if __FreeBSD_version >= 500015
235 ps->userTime = p.ki_runtime / 10000;
236 #elif defined(__DragonFly__)
237 #if __DragonFly_version >= 190000
238 if (!getrusage(p.kp_pid, &pru))
239 #else
240 if (!getrusage(p.kp_proc.p_pid, &pru))
241 #endif
243 errx(1, "failed to get rusage info");
245 ps->userTime = pru.ru_utime.tv_usec / 1000; /*p_runtime / 1000*/
246 #elif __FreeBSD_version >= 300000
247 ps->userTime = p.kp_proc.p_runtime / 10000;
248 #else
249 ps->userTime = p.kp_proc.p_rtime.tv_sec*100+p.kp_proc.p_rtime.tv_usec/100;
250 #endif
251 ps->sysTime = 0;
252 ps->sysLoad = 0;
254 /* memory, process name, process uid */
255 /* find out user name with process uid */
256 pwent = getpwuid(ps->uid);
257 strncpy(ps->userName,pwent&&pwent->pw_name? pwent->pw_name:"????",sizeof(ps->userName));
258 ps->userName[sizeof(ps->userName)-1]='\0';
260 if (fscale == 0)
261 ps->userLoad = 0;
262 else
263 #if __FreeBSD_version >= 500015
264 ps->userLoad = 100.0 * (double) p.ki_pctcpu / fscale;
265 ps->vmSize = p.ki_size;
266 ps->vmRss = p.ki_rssize * getpagesize();
267 strlcpy(ps->name,p.ki_comm? p.ki_comm:"????",sizeof(ps->name));
268 strcpy(ps->status,(p.ki_stat>=1)&&(p.ki_stat<=5)? statuses[p.ki_stat-1]:"????");
269 #elif defined (__DragonFly__) && __DragonFly_version >= 190000
270 ps->userLoad = 100.0 * (double) p.kp_lwp.kl_pctcpu / fscale;
271 ps->vmSize = p.kp_vm_map_size;
272 ps->vmRss = p.kp_vm_rssize * getpagesize();
273 strlcpy(ps->name,p.kp_comm ? p.kp_comm : "????",
274 sizeof(ps->name));
275 strcpy(ps->status,(p.kp_stat>=1)&&(p.kp_stat<=5)? statuses[p.kp_stat-1]:"????");
276 #else
277 ps->userLoad = 100.0 * (double) p.kp_proc.p_pctcpu / fscale;
278 ps->vmSize = p.kp_eproc.e_vm.vm_map.size;
279 ps->vmRss = p.kp_eproc.e_vm.vm_rssize * getpagesize();
280 #if defined (__DragonFly__)
281 strlcpy(ps->name,p.kp_thread.td_comm ? p.kp_thread.td_comm : "????",
282 sizeof(ps->name));
283 #else
284 strlcpy(ps->name,p.kp_proc.p_comm ? p.kp_proc.p_comm : "????", sizeof(ps->name));
285 #endif
286 strcpy(ps->status,(p.kp_proc.p_stat>=1)&&(p.kp_proc.p_stat<=5)? statuses[p.kp_proc.p_stat-1]:"????");
287 #endif
289 /* process command line */
290 /* do a sysctl to get the command line args. */
292 mib[0] = CTL_KERN;
293 mib[1] = KERN_PROC;
294 mib[2] = KERN_PROC_ARGS;
295 mib[3] = pid;
297 if ((sysctl(mib, 4, buf, &buflen, 0, 0) == -1) || !buflen)
298 strcpy(ps->cmdline, "????");
299 else
300 strncpy(ps->cmdline, buf, buflen);
302 return (0);
305 static void
306 cleanupProcessList(void)
308 ProcessInfo* ps;
310 ProcessCount = 0;
311 /* All processes that do not have the active flag set are assumed dead
312 * and will be removed from the list. The alive flag is cleared. */
313 for (ps = first_ctnr(ProcessList); ps; ps = next_ctnr(ProcessList))
315 if (ps->alive)
317 /* Process is still alive. Just clear flag. */
318 ps->alive = 0;
319 ProcessCount++;
321 else
323 /* Process has probably died. We remove it from the list and
324 * destruct the data structure. */
325 free(remove_ctnr(ProcessList));
331 ================================ public part ==================================
334 void
335 initProcessList(struct SensorModul* sm)
337 size_t fscalelen;
338 ProcessList = new_ctnr();
340 registerMonitor("ps", "table", printProcessList, printProcessListInfo, sm);
341 registerMonitor("pscount", "integer", printProcessCount, printProcessCountInfo, sm);
343 if (!RunAsDaemon)
345 registerCommand("kill", killProcess);
346 registerCommand("setpriority", setPriority);
349 fscalelen = sizeof(fscale);
350 if (sysctlbyname("kern.fscale", &fscale, &fscalelen, NULL, 0) == -1)
351 fscale = 0;
353 updateProcessList();
356 void
357 exitProcessList(void)
359 removeMonitor("ps");
360 removeMonitor("pscount");
362 if (ProcessList)
363 free (ProcessList);
367 updateProcessList(void)
369 int mib[3];
370 size_t len;
371 size_t num;
372 struct kinfo_proc *p;
375 mib[0] = CTL_KERN;
376 mib[1] = KERN_PROC;
377 mib[2] = KERN_PROC_ALL;
378 sysctl(mib, 3, NULL, &len, NULL, 0);
379 p = malloc(len);
380 sysctl(mib, 3, p, &len, NULL, 0);
382 for (num = 0; num < len / sizeof(struct kinfo_proc); num++)
383 #if __FreeBSD_version >= 500015
384 updateProcess(p[num].ki_pid);
385 #elif __DragonFly_version >= 190000
386 /* Skip kernel threads with pid -1. Swapper with pid 0 also
387 * causing problems is skipped in printProcessList() as 'kernel'
388 * entry. */
389 if (p[num].kp_pid >= 0)
390 updateProcess(p[num].kp_pid);
391 #elif defined(__DragonFly__)
392 if (p[num].kp_proc.p_pid >= 0)
393 updateProcess(p[num].kp_proc.p_pid);
394 #else
395 updateProcess(p[num].kp_proc.p_pid);
396 #endif
397 free(p);
398 cleanupProcessList();
400 return (0);
403 void
404 printProcessListInfo(const char* cmd)
406 fprintf(CurrentClient, "Name\tPID\tPPID\tUID\tGID\tStatus\tUser%%\tSystem%%\tNice\tVmSize\tVmRss\tLogin\tCommand\n");
407 fprintf(CurrentClient, "s\td\td\td\td\tS\tf\tf\td\tD\tD\ts\ts\n");
410 void
411 printProcessList(const char* cmd)
413 ProcessInfo* ps;
415 ps = first_ctnr(ProcessList); /* skip 'kernel' entry */
416 for (ps = next_ctnr(ProcessList); ps; ps = next_ctnr(ProcessList))
418 fprintf(CurrentClient, "%s\t%ld\t%ld\t%ld\t%ld\t%s\t%.2f\t%.2f\t%d\t%d\t%d\t%s\t%s\n",
419 ps->name, (long)ps->pid, (long)ps->ppid,
420 (long)ps->uid, (long)ps->gid, ps->status,
421 ps->userLoad, ps->sysLoad, ps->niceLevel,
422 ps->vmSize / 1024, ps->vmRss / 1024, ps->userName, ps->cmdline);
426 void
427 printProcessCount(const char* cmd)
429 fprintf(CurrentClient, "%d\n", ProcessCount);
432 void
433 printProcessCountInfo(const char* cmd)
435 fprintf(CurrentClient, "Number of Processes\t1\t65535\t\n");
438 void
439 killProcess(const char* cmd)
441 int sig, pid;
443 sscanf(cmd, "%*s %d %d", &pid, &sig);
444 switch(sig)
446 case MENU_ID_SIGABRT:
447 sig = SIGABRT;
448 break;
449 case MENU_ID_SIGALRM:
450 sig = SIGALRM;
451 break;
452 case MENU_ID_SIGCHLD:
453 sig = SIGCHLD;
454 break;
455 case MENU_ID_SIGCONT:
456 sig = SIGCONT;
457 break;
458 case MENU_ID_SIGFPE:
459 sig = SIGFPE;
460 break;
461 case MENU_ID_SIGHUP:
462 sig = SIGHUP;
463 break;
464 case MENU_ID_SIGILL:
465 sig = SIGILL;
466 break;
467 case MENU_ID_SIGINT:
468 sig = SIGINT;
469 break;
470 case MENU_ID_SIGKILL:
471 sig = SIGKILL;
472 break;
473 case MENU_ID_SIGPIPE:
474 sig = SIGPIPE;
475 break;
476 case MENU_ID_SIGQUIT:
477 sig = SIGQUIT;
478 break;
479 case MENU_ID_SIGSEGV:
480 sig = SIGSEGV;
481 break;
482 case MENU_ID_SIGSTOP:
483 sig = SIGSTOP;
484 break;
485 case MENU_ID_SIGTERM:
486 sig = SIGTERM;
487 break;
488 case MENU_ID_SIGTSTP:
489 sig = SIGTSTP;
490 break;
491 case MENU_ID_SIGTTIN:
492 sig = SIGTTIN;
493 break;
494 case MENU_ID_SIGTTOU:
495 sig = SIGTTOU;
496 break;
497 case MENU_ID_SIGUSR1:
498 sig = SIGUSR1;
499 break;
500 case MENU_ID_SIGUSR2:
501 sig = SIGUSR2;
502 break;
504 if (kill((pid_t) pid, sig))
506 switch(errno)
508 case EINVAL:
509 fprintf(CurrentClient, "4\t%d\n", pid);
510 break;
511 case ESRCH:
512 fprintf(CurrentClient, "3\t%d\n", pid);
513 break;
514 case EPERM:
515 fprintf(CurrentClient, "2\t%d\n", pid);
516 break;
517 default:
518 fprintf(CurrentClient, "1\t%d\n", pid); /* unknown error */
519 break;
523 else
524 fprintf(CurrentClient, "0\t%d\n", pid);
527 void
528 setPriority(const char* cmd)
530 int pid, prio;
532 sscanf(cmd, "%*s %d %d", &pid, &prio);
533 if (setpriority(PRIO_PROCESS, pid, prio))
535 switch(errno)
537 case EINVAL:
538 fprintf(CurrentClient, "4\n");
539 break;
540 case ESRCH:
541 fprintf(CurrentClient, "3\n");
542 break;
543 case EPERM:
544 case EACCES:
545 fprintf(CurrentClient, "2\n");
546 break;
547 default:
548 fprintf(CurrentClient, "1\n"); /* unknown error */
549 break;
552 else
553 fprintf(CurrentClient, "0\n");