Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / ksysguard / ksysguardd / Irix / ProcessList.c
blob654d439d005b36fe60489bde4a9e113518dfcd88
1 /*
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.
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <signal.h>
30 #include <sys/types.h>
31 #include <dirent.h>
32 #include <pwd.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>
39 #include "ccont.h"
40 #include "../../gui/SignalIDs.h"
41 #include "ksysguardd.h"
43 #include "Command.h"
44 #include "ProcessList.h"
46 #define BUFSIZE 1024
47 #define KDEINITLEN strlen("kdeinit: ")
49 typedef struct {
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 */
66 } ProcessInfo;
68 static CONTAINER ProcessList = 0;
69 static unsigned ProcessCount = 0; /* # of processes */
70 static DIR *procdir; /* handle for /proc */
71 static int pagesz;
73 #define KBYTES 1024
76 * lwpStateName() -- return string representation of process state
78 char *lwpStateName( prpsinfo_t lwpinfo ) {
80 static char result[8];
82 switch( lwpinfo.pr_sname ) {
83 case 'S':
84 sprintf( result, "%s", "sleep" );
85 break;
86 case 'R':
87 sprintf( result, "%s", "run" );
88 break;
89 case 'Z':
90 sprintf( result, "%s", "zombie" );
91 break;
92 case 'T':
93 sprintf( result, "%s", "stop" );
94 break;
95 case 'I':
96 sprintf( result, "%s", "start" );
97 break;
98 case 'X':
99 sprintf( result, "%s", "wmem" );
100 case '0':
101 sprintf( result, "%s/%d", "cpu", (int) lwpinfo.pr_sonproc );
102 break;
103 default:
104 sprintf( result, "%s", "???" );
105 break;
108 return( result );
111 static void validateStr( char *string ) {
113 char *ptr = string;
116 * remove all chars that might screw up communication
118 while( *ptr != '\0' ) {
119 if( *ptr == '\t' || *ptr == '\n' || *ptr == '\r' )
120 *ptr = ' ';
121 ptr++;
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 ) {
137 ProcessInfo key;
138 long index;
140 key.pid = pid;
141 if( (index = search_ctnr( ProcessList, processCmp, &key )) < 0 )
142 return( NULL );
144 return( get_ctnr( ProcessList, index ));
147 static int updateProcess( pid_t pid ) {
148 ProcessInfo *ps;
149 int fd;
150 char buf[BUFSIZE];
151 prpsinfo_t psinfo;
152 struct passwd *pw;
153 register double newCentStamp,timeDiff, usDiff,usTime;
154 struct timeval tv;
156 if( (ps = findProcessInList( pid )) == NULL ) {
157 if( (ps = (ProcessInfo *) malloc( sizeof( ProcessInfo )))
158 == NULL ) {
159 print_error( "cannot malloc()\n" );
160 return( -1 );
162 ps->pid = pid;
163 ps->userName = NULL;
164 ps->alive = 0;
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 */
176 return( -1 );
181 if( ioctl(fd,PIOCPSINFO,&psinfo) < 0) {
182 print_error( "cannot read psinfo from \"%s\"\n", buf );
183 close( fd );
184 return( -1 );
186 close( fd );
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);
198 ps->State[7]='\0';
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;
217 else
218 ps->Load = 0.0;
220 ps->centStamp = newCentStamp;
221 ps->Time = usTime;
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 );
235 ps->alive = 1;
236 return( 0 );
239 static void cleanupProcessList( void ) {
241 ProcessInfo *ps;
243 ProcessCount = 0;
244 for( ps = first_ctnr( ProcessList ); ps; ps = next_ctnr( ProcessList )) {
245 if( ps->alive ) {
246 /* Process is still alive. Just clear flag. */
247 ps->alive = 0;
248 ProcessCount++;
249 } else {
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 );
261 return;
263 pagesz=getpagesize();
264 ProcessList = new_ctnr();
265 updateProcessList();
268 * register the supported monitors & commands
270 registerMonitor( "pscount", "integer",
271 printProcessCount, printProcessCountInfo, sm );
272 registerMonitor( "ps", "table",
273 printProcessList, printProcessListInfo, sm );
275 if (!RunAsDaemon)
277 registerCommand("kill", killProcess);
278 registerCommand("setpriority", setPriority);
282 void exitProcessList( void ) {
284 removeMonitor("ps");
285 removeMonitor("pscount");
287 if (!RunAsDaemon)
289 removeCommand("kill");
290 removeCommand("setpriority");
293 destr_ctnr( ProcessList, free );
296 int updateProcessList( void ) {
298 struct dirent *de;
299 struct statfs sf;
301 statfs("/proc/pinfo",&sf,sizeof(sf),0);
302 ProcessCount = sf.f_files;
304 rewinddir( procdir );
305 while( (de = readdir( procdir )) != NULL ) {
307 * skip '.' and '..'
309 if( de->d_name[0] == '.' )
310 continue;
313 * fetch the process info and insert it into the info table
315 updateProcess( (pid_t) atol( de->d_name ));
317 cleanupProcessList();
319 return( 0 );
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 ) {
330 ProcessInfo *ps;
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",
335 ps->Command,
336 (long) ps->pid,
337 (long) ps->ppid,
338 (long) ps->gid,
339 ps->State,
340 ps->userName,
341 ps->Size,
342 ps->RSSize,
343 ps->Load,
344 ps->Prio,
345 ps->CmdLine);
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 ) {
361 int sig, pid;
363 sscanf( cmd, "%*s %d %d", &pid, &sig );
365 switch( sig ) {
366 case MENU_ID_SIGABRT:
367 sig = SIGABRT;
368 break;
369 case MENU_ID_SIGALRM:
370 sig = SIGALRM;
371 break;
372 case MENU_ID_SIGCHLD:
373 sig = SIGCHLD;
374 break;
375 case MENU_ID_SIGCONT:
376 sig = SIGCONT;
377 break;
378 case MENU_ID_SIGFPE:
379 sig = SIGFPE;
380 break;
381 case MENU_ID_SIGHUP:
382 sig = SIGHUP;
383 break;
384 case MENU_ID_SIGILL:
385 sig = SIGILL;
386 break;
387 case MENU_ID_SIGINT:
388 sig = SIGINT;
389 break;
390 case MENU_ID_SIGKILL:
391 sig = SIGKILL;
392 break;
393 case MENU_ID_SIGPIPE:
394 sig = SIGPIPE;
395 break;
396 case MENU_ID_SIGQUIT:
397 sig = SIGQUIT;
398 break;
399 case MENU_ID_SIGSEGV:
400 sig = SIGSEGV;
401 break;
402 case MENU_ID_SIGSTOP:
403 sig = SIGSTOP;
404 break;
405 case MENU_ID_SIGTERM:
406 sig = SIGTERM;
407 break;
408 case MENU_ID_SIGTSTP:
409 sig = SIGTSTP;
410 break;
411 case MENU_ID_SIGTTIN:
412 sig = SIGTTIN;
413 break;
414 case MENU_ID_SIGTTOU:
415 sig = SIGTTOU;
416 break;
417 case MENU_ID_SIGUSR1:
418 sig = SIGUSR1;
419 break;
420 case MENU_ID_SIGUSR2:
421 sig = SIGUSR2;
422 break;
424 if( kill( (pid_t) pid, sig )) {
425 switch( errno ) {
426 case EINVAL:
427 fprintf(CurrentClient, "4\n" );
428 break;
429 case ESRCH:
430 fprintf(CurrentClient, "3\n" );
431 break;
432 case EPERM:
433 fprintf(CurrentClient, "2\n" );
434 break;
435 default:
436 fprintf(CurrentClient, "1\n" ); /* unknown error */
437 break;
439 } else
440 fprintf(CurrentClient, "0\n");
443 void setPriority( const char *cmd ) {
444 int pid, prio;
446 sscanf( cmd, "%*s %d %d", &pid, &prio );
447 if( setpriority( PRIO_PROCESS, pid, prio )) {
448 switch( errno ) {
449 case EINVAL:
450 fprintf(CurrentClient, "4\n" );
451 break;
452 case ESRCH:
453 fprintf(CurrentClient, "3\n" );
454 break;
455 case EPERM:
456 case EACCES:
457 fprintf(CurrentClient, "2\n" );
458 break;
459 default:
460 fprintf(CurrentClient, "1\n" ); /* unknown error */
461 break;
463 } else
464 fprintf(CurrentClient, "0\n");