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");