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.
29 #include <sys/param.h>
31 #if defined(__DragonFly__)
33 #include <sys/resourcevar.h>
36 #if __FreeBSD_version > 500015
37 #include <sys/priority.h>
39 #include <sys/sysctl.h>
41 #include <sys/types.h>
46 #include "../../gui/SignalIDs.h"
48 #include "ProcessList.h"
50 #include "ksysguardd.h"
52 CONTAINER ProcessList
= 0;
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. */
69 /* the parent process ID */
72 /* the real user ID */
75 /* the real group ID */
78 /* a character description of the process status */
81 /* the number of the tty the process owns */
85 * The nice level. The range should be -20 to 20. I'm not sure
86 * whether this is true for all platforms.
91 * The scheduling priority.
96 * The total amount of memory the process uses. This includes shared and
102 * The amount of physical memory the process currently uses.
107 * The amount of memory (shared/swapped/etc) the process shares with
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
118 #if !defined(__DragonFly__)
119 unsigned int userTime
;
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
130 unsigned int sysTime
;
132 /* system time as multime of 100ms */
135 /* the current CPU load (in %) from user space */
138 /* the current CPU load (in %) from system space */
141 /* the name of the process */
144 /* the command used to start the process */
147 /* the login name of the user that owns this process */
151 static unsigned ProcessCount
;
154 processCmp(void* p1
, void* p2
)
156 return (((ProcessInfo
*) p1
)->pid
- ((ProcessInfo
*) p2
)->pid
);
160 findProcessInList(int pid
)
166 if ((index
= search_ctnr(ProcessList
, processCmp
, &key
)) < 0)
169 return (get_ctnr(ProcessList
, index
));
173 updateProcess(int pid
)
175 static char *statuses
[] = { "idle","run","sleep","stop","zombie" };
178 struct passwd
* pwent
;
186 if ((ps
= findProcessInList(pid
)) == 0)
188 ps
= (ProcessInfo
*) malloc(sizeof(ProcessInfo
));
191 push_ctnr(ProcessList
, ps
);
192 bsort_ctnr(ProcessList
, processCmp
);
199 mib
[2] = KERN_PROC_PID
;
203 if (sysctl(mib
, 4, &p
, &len
, NULL
, 0) == -1 || !len
)
206 #if __FreeBSD_version >= 500015
208 ps
->ppid
= p
.ki_ppid
;
211 ps
->priority
= p
.ki_pri
.pri_user
;
212 ps
->niceLevel
= p
.ki_nice
;
213 #elif defined(__DragonFly__) && __DragonFly_version >= 190000
215 ps
->ppid
= p
.kp_ppid
;
218 ps
->priority
= p
.kp_lwp
.kl_tdprio
;
219 ps
->niceLevel
= p
.kp_nice
;
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
;
228 ps
->priority
= p
.kp_proc
.p_priority
;
230 ps
->niceLevel
= p
.kp_proc
.p_nice
;
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
))
240 if (!getrusage(p
.kp_proc
.p_pid
, &pru
))
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;
249 ps
->userTime
= p
.kp_proc
.p_rtime
.tv_sec
*100+p
.kp_proc
.p_rtime
.tv_usec
/100;
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';
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
: "????",
275 strcpy(ps
->status
,(p
.kp_stat
>=1)&&(p
.kp_stat
<=5)? statuses
[p
.kp_stat
-1]:"????");
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
: "????",
284 strlcpy(ps
->name
,p
.kp_proc
.p_comm
? p
.kp_proc
.p_comm
: "????", sizeof(ps
->name
));
286 strcpy(ps
->status
,(p
.kp_proc
.p_stat
>=1)&&(p
.kp_proc
.p_stat
<=5)? statuses
[p
.kp_proc
.p_stat
-1]:"????");
289 /* process command line */
290 /* do a sysctl to get the command line args. */
294 mib
[2] = KERN_PROC_ARGS
;
297 if ((sysctl(mib
, 4, buf
, &buflen
, 0, 0) == -1) || !buflen
)
298 strcpy(ps
->cmdline
, "????");
300 strncpy(ps
->cmdline
, buf
, buflen
);
306 cleanupProcessList(void)
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
))
317 /* Process is still alive. Just clear flag. */
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 ==================================
335 initProcessList(struct SensorModul
* sm
)
338 ProcessList
= new_ctnr();
340 registerMonitor("ps", "table", printProcessList
, printProcessListInfo
, sm
);
341 registerMonitor("pscount", "integer", printProcessCount
, printProcessCountInfo
, sm
);
345 registerCommand("kill", killProcess
);
346 registerCommand("setpriority", setPriority
);
349 fscalelen
= sizeof(fscale
);
350 if (sysctlbyname("kern.fscale", &fscale
, &fscalelen
, NULL
, 0) == -1)
357 exitProcessList(void)
360 removeMonitor("pscount");
367 updateProcessList(void)
372 struct kinfo_proc
*p
;
377 mib
[2] = KERN_PROC_ALL
;
378 sysctl(mib
, 3, NULL
, &len
, NULL
, 0);
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'
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
);
395 updateProcess(p
[num
].kp_proc
.p_pid
);
398 cleanupProcessList();
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");
411 printProcessList(const char* cmd
)
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
);
427 printProcessCount(const char* cmd
)
429 fprintf(CurrentClient
, "%d\n", ProcessCount
);
433 printProcessCountInfo(const char* cmd
)
435 fprintf(CurrentClient
, "Number of Processes\t1\t65535\t\n");
439 killProcess(const char* cmd
)
443 sscanf(cmd
, "%*s %d %d", &pid
, &sig
);
446 case MENU_ID_SIGABRT
:
449 case MENU_ID_SIGALRM
:
452 case MENU_ID_SIGCHLD
:
455 case MENU_ID_SIGCONT
:
470 case MENU_ID_SIGKILL
:
473 case MENU_ID_SIGPIPE
:
476 case MENU_ID_SIGQUIT
:
479 case MENU_ID_SIGSEGV
:
482 case MENU_ID_SIGSTOP
:
485 case MENU_ID_SIGTERM
:
488 case MENU_ID_SIGTSTP
:
491 case MENU_ID_SIGTTIN
:
494 case MENU_ID_SIGTTOU
:
497 case MENU_ID_SIGUSR1
:
500 case MENU_ID_SIGUSR2
:
504 if (kill((pid_t
) pid
, sig
))
509 fprintf(CurrentClient
, "4\t%d\n", pid
);
512 fprintf(CurrentClient
, "3\t%d\n", pid
);
515 fprintf(CurrentClient
, "2\t%d\n", pid
);
518 fprintf(CurrentClient
, "1\t%d\n", pid
); /* unknown error */
524 fprintf(CurrentClient
, "0\t%d\n", pid
);
528 setPriority(const char* cmd
)
532 sscanf(cmd
, "%*s %d %d", &pid
, &prio
);
533 if (setpriority(PRIO_PROCESS
, pid
, prio
))
538 fprintf(CurrentClient
, "4\n");
541 fprintf(CurrentClient
, "3\n");
545 fprintf(CurrentClient
, "2\n");
548 fprintf(CurrentClient
, "1\n"); /* unknown error */
553 fprintf(CurrentClient
, "0\n");