2 KSysGuard, the KDE System Guard
4 Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org>
6 Irix support by Carsten Kroll <ckroll@pinnaclesys.com>
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of version 2 of the GNU General Public
10 License as published by the Free Software Foundation.
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.
30 #include <sys/types.h>
33 #include <sys/resource.h>
34 #include <sys/procfs.h>
35 #include <sys/statfs.h>
36 #include <sys/sysmp.h>
37 #include <sys/sysinfo.h>
40 #include "../../gui/SignalIDs.h"
41 #include "ksysguardd.h"
44 #include "ProcessList.h"
47 #define KDEINITLEN strlen("kdeinit: ")
50 int alive
; /* for "garbage collection" */
51 pid_t pid
; /* process ID */
52 pid_t ppid
; /* parent process ID */
53 uid_t uid
; /* process owner (real UID) */
54 gid_t gid
; /* process group (real GID) */
55 char *userName
; /* process owner (name) */
56 int nThreads
; /* # of threads in this process */
57 int Prio
; /* scheduling priority */
58 size_t Size
; /* total size of process image */
59 size_t RSSize
; /* resident set size */
60 char State
[8]; /* process state */
61 double Time
; /* CPU time for the process in 100ms */
62 double Load
; /* CPU load in % */
63 char Command
[PRCOMSIZ
];/* command name */
64 char CmdLine
[PRARGSZ
];/* command line */
65 double centStamp
; /* timestamp for CPU load */
68 static CONTAINER ProcessList
= 0;
69 static unsigned ProcessCount
= 0; /* # of processes */
70 static DIR *procdir
; /* handle for /proc */
76 * lwpStateName() -- return string representation of process state
78 char *lwpStateName( prpsinfo_t lwpinfo
) {
80 static char result
[8];
82 switch( lwpinfo
.pr_sname
) {
84 sprintf( result
, "%s", "sleep" );
87 sprintf( result
, "%s", "run" );
90 sprintf( result
, "%s", "zombie" );
93 sprintf( result
, "%s", "stop" );
96 sprintf( result
, "%s", "start" );
99 sprintf( result
, "%s", "wmem" );
101 sprintf( result
, "%s/%d", "cpu", (int) lwpinfo
.pr_sonproc
);
104 sprintf( result
, "%s", "???" );
111 static void validateStr( char *string
) {
116 * remove all chars that might screw up communication
118 while( *ptr
!= '\0' ) {
119 if( *ptr
== '\t' || *ptr
== '\n' || *ptr
== '\r' )
124 * make sure there's at least one char
126 if( string
[0] == '\0' )
127 strcpy( string
, " " );
130 static int processCmp( void *p1
, void *p2
) {
132 return( ((ProcessInfo
*) p1
)->pid
- ((ProcessInfo
*) p2
)->pid
);
135 static ProcessInfo
*findProcessInList( pid_t pid
) {
141 if( (index
= search_ctnr( ProcessList
, processCmp
, &key
)) < 0 )
144 return( get_ctnr( ProcessList
, index
));
147 static int updateProcess( pid_t pid
) {
153 register double newCentStamp
,timeDiff
, usDiff
,usTime
;
156 if( (ps
= findProcessInList( pid
)) == NULL
) {
157 if( (ps
= (ProcessInfo
*) malloc( sizeof( ProcessInfo
)))
159 print_error( "cannot malloc()\n" );
166 gettimeofday(&tv
, 0);
167 ps
->centStamp
= (double)tv
.tv_sec
* 100.0 + (double)tv
.tv_usec
/ 10000.0;
169 push_ctnr( ProcessList
, ps
);
170 bsort_ctnr( ProcessList
, processCmp
);
173 sprintf( buf
, "%s/pinfo/%ld", PROCDIR
, pid
);
174 if( (fd
= open( buf
, O_RDONLY
)) < 0 ) {
175 /* process terminated */
181 if( ioctl(fd
,PIOCPSINFO
,&psinfo
) < 0) {
182 print_error( "cannot read psinfo from \"%s\"\n", buf
);
188 ps
->ppid
= psinfo
.pr_ppid
;
189 ps
->uid
= psinfo
.pr_uid
;
190 ps
->gid
= psinfo
.pr_gid
;
192 pw
= getpwuid( psinfo
.pr_uid
);
193 if( ps
->userName
!= NULL
)
194 free( ps
->userName
);
195 ps
->userName
= strdup( pw
->pw_name
);
197 strncpy (ps
->State
,lwpStateName( psinfo
),8);
201 ps
->Prio
= psinfo
.pr_pri
;
203 gettimeofday(&tv
, 0);
204 newCentStamp
= (double)tv
.tv_sec
* 100.0 + (double) tv
.tv_usec
/ 10000.0;
205 usTime
= (double) psinfo
.pr_time
.tv_sec
* 100.0 + (double)psinfo
.pr_time
.tv_nsec
/ 10000000.0;
207 timeDiff
= newCentStamp
- ps
->centStamp
;
208 usDiff
= usTime
- ps
->Time
;
210 if ((timeDiff
> 0.0) && (usDiff
>= 0.0))
212 ps
->Load
= (usDiff
/ timeDiff
) * 100.0;
213 /* During startup we get bigger loads since the time diff
214 * cannot be correct. So we force it to 0. */
215 ps
->Load
= (ps
->Load
> 100.0) ? 0.0 : ps
->Load
;
220 ps
->centStamp
= newCentStamp
;
223 ps
->Size
= (psinfo
.pr_size
* pagesz
)/KBYTES
;
224 ps
->RSSize
= (psinfo
.pr_rssize
* pagesz
)/KBYTES
;
226 strncpy(ps
->Command
,psinfo
.pr_fname
,PRCOMSIZ
);
227 ps
->Command
[PRCOMSIZ
-1]='\0';
229 strncpy(ps
->CmdLine
,psinfo
.pr_psargs
,PRARGSZ
);
230 ps
->CmdLine
[PRARGSZ
-1]='\0';
232 validateStr( ps
->Command
);
233 validateStr( ps
->CmdLine
);
239 static void cleanupProcessList( void ) {
244 for( ps
= first_ctnr( ProcessList
); ps
; ps
= next_ctnr( ProcessList
)) {
246 /* Process is still alive. Just clear flag. */
250 /* Process has probably died. We remove it from the list and
251 * destruct the data structure. */
252 free( remove_ctnr( ProcessList
));
257 void initProcessList( struct SensorModul
* sm
) {
259 if( (procdir
= opendir( PROCDIR
)) == NULL
) {
260 print_error( "cannot open \"%s\" for reading\n", PROCDIR
);
263 pagesz
=getpagesize();
264 ProcessList
= new_ctnr();
268 * register the supported monitors & commands
270 registerMonitor( "pscount", "integer",
271 printProcessCount
, printProcessCountInfo
, sm
);
272 registerMonitor( "ps", "table",
273 printProcessList
, printProcessListInfo
, sm
);
277 registerCommand("kill", killProcess
);
278 registerCommand("setpriority", setPriority
);
282 void exitProcessList( void ) {
285 removeMonitor("pscount");
289 removeCommand("kill");
290 removeCommand("setpriority");
293 destr_ctnr( ProcessList
, free
);
296 int updateProcessList( void ) {
301 statfs("/proc/pinfo",&sf
,sizeof(sf
),0);
302 ProcessCount
= sf
.f_files
;
304 rewinddir( procdir
);
305 while( (de
= readdir( procdir
)) != NULL
) {
309 if( de
->d_name
[0] == '.' )
313 * fetch the process info and insert it into the info table
315 updateProcess( (pid_t
) atol( de
->d_name
));
317 cleanupProcessList();
322 void printProcessListInfo( const char *cmd
) {
323 fprintf(CurrentClient
, "Name\tPID\tPPID\tGID\tStatus\tUser"
324 "\tSize\tResident\t%% CPU\tPriority\tCommand\n" );
325 fprintf(CurrentClient
, "s\td\td\td\ts\ts\tD\tD\tf\td\ts\n" );
328 void printProcessList( const char *cmd
) {
332 for( ps
= first_ctnr( ProcessList
); ps
; ps
= next_ctnr( ProcessList
)) {
333 fprintf(CurrentClient
,
334 "%s\t%ld\t%ld\t%ld\t%s\t%s\t%d\t%d\t%.2f\t%d\t%s\n",
348 fprintf(CurrentClient
, "\n");
351 void printProcessCount( const char *cmd
) {
352 fprintf(CurrentClient
, "%d\n", ProcessCount
);
355 void printProcessCountInfo( const char *cmd
) {
356 fprintf(CurrentClient
, "Number of Processes\t0\t0\t\n" );
359 void killProcess( const char *cmd
) {
363 sscanf( cmd
, "%*s %d %d", &pid
, &sig
);
366 case MENU_ID_SIGABRT
:
369 case MENU_ID_SIGALRM
:
372 case MENU_ID_SIGCHLD
:
375 case MENU_ID_SIGCONT
:
390 case MENU_ID_SIGKILL
:
393 case MENU_ID_SIGPIPE
:
396 case MENU_ID_SIGQUIT
:
399 case MENU_ID_SIGSEGV
:
402 case MENU_ID_SIGSTOP
:
405 case MENU_ID_SIGTERM
:
408 case MENU_ID_SIGTSTP
:
411 case MENU_ID_SIGTTIN
:
414 case MENU_ID_SIGTTOU
:
417 case MENU_ID_SIGUSR1
:
420 case MENU_ID_SIGUSR2
:
424 if( kill( (pid_t
) pid
, sig
)) {
427 fprintf(CurrentClient
, "4\n" );
430 fprintf(CurrentClient
, "3\n" );
433 fprintf(CurrentClient
, "2\n" );
436 fprintf(CurrentClient
, "1\n" ); /* unknown error */
440 fprintf(CurrentClient
, "0\n");
443 void setPriority( const char *cmd
) {
446 sscanf( cmd
, "%*s %d %d", &pid
, &prio
);
447 if( setpriority( PRIO_PROCESS
, pid
, prio
)) {
450 fprintf(CurrentClient
, "4\n" );
453 fprintf(CurrentClient
, "3\n" );
457 fprintf(CurrentClient
, "2\n" );
460 fprintf(CurrentClient
, "1\n" ); /* unknown error */
464 fprintf(CurrentClient
, "0\n");