2
KSysGuard, the KDE System Guard
4
Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org>
6
Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE>
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
/* Stop <sys/procfs.h> from crapping out on 32-bit architectures. */
25
#if !defined(_LP64) && _FILE_OFFSET_BITS == 64
26
# undef _FILE_OFFSET_BITS
27
# define _FILE_OFFSET_BITS 32
37
#include <sys/types.h>
42
#include <sys/resource.h>
45
#include "../../gui/SignalIDs.h"
46
#include "ksysguardd.h"
49
#include "ProcessList.h"
54
int alive; /* for "garbage collection" */
55
pid_t pid; /* process ID */
56
pid_t ppid; /* parent process ID */
57
uid_t uid; /* process owner (real UID) */
58
gid_t gid; /* process group (real GID) */
59
char *userName; /* process owner (name) */
60
int nThreads; /* # of threads in this process */
61
int Prio; /* scheduling priority */
62
size_t Size; /* total size of process image */
63
size_t RSSize; /* resident set size */
64
char *State; /* process state */
65
int Time; /* CPU time for the process */
66
double Load; /* CPU load in % */
67
char *Command; /* command name */
68
char *CmdLine; /* command line */
71
static CONTAINER ProcessList = 0;
72
static unsigned ProcessCount = 0; /* # of processes */
73
static DIR *procdir; /* handle for /proc */
76
* lwpStateName() -- return string representation of process state
78
char *lwpStateName( lwpsinfo_t lwpinfo ) {
83
switch( (int) lwpinfo.pr_state ) {
85
sprintf( result, "%s", "sleep" );
88
sprintf( result, "%s", "run" );
91
sprintf( result, "%s", "zombie" );
94
sprintf( result, "%s", "stop" );
97
sprintf( result, "%s", "start" );
100
processor = (int) lwpinfo.pr_onpro;
101
sprintf( result, "%s/%d", "cpu", processor );
104
sprintf( result, "%s", "???" );
108
return( strdup( result ));
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 ) {
155
if( (ps = findProcessInList( pid )) == NULL ) {
156
if( (ps = (ProcessInfo *) malloc( sizeof( ProcessInfo )))
158
print_error( "cannot malloc()\n" );
168
push_ctnr( ProcessList, ps );
169
bsort_ctnr( ProcessList, processCmp );
172
snprintf( buf, BUFSIZE - 1, "%s/%ld/psinfo", PROCDIR, pid );
173
if( (fd = open( buf, O_RDONLY )) < 0 ) {
177
if( read( fd, &psinfo, sizeof( psinfo_t )) != sizeof( psinfo_t )) {
183
ps->ppid = psinfo.pr_ppid;
184
ps->uid = psinfo.pr_uid;
185
ps->gid = psinfo.pr_gid;
187
pw = getpwuid( psinfo.pr_uid );
188
if( ps->userName != NULL )
189
free( ps->userName );
190
ps->userName = strdup( pw->pw_name );
192
if( ps->State != NULL )
194
ps->State = lwpStateName( psinfo.pr_lwp );
197
* the following data is invalid for zombies, so...
199
if( (ps->nThreads = psinfo.pr_nlwp ) != 0 ) {
200
ps->Prio = psinfo.pr_lwp.pr_pri;
201
ps->Time = psinfo.pr_lwp.pr_time.tv_sec * 100
202
+ psinfo.pr_lwp.pr_time.tv_nsec * 10000000;
203
ps->Load = (double) psinfo.pr_lwp.pr_pctcpu
204
/ (double) 0x8000 * 100.0;
211
ps->Size = psinfo.pr_size;
212
ps->RSSize = psinfo.pr_rssize;
214
if( ps->Command != NULL )
216
ps->Command = strdup( psinfo.pr_fname );
217
if( ps->CmdLine != NULL )
219
ps->CmdLine = strdup( psinfo.pr_psargs );
221
validateStr( ps->Command );
222
validateStr( ps->CmdLine );
229
static void cleanupProcessList( void ) {
234
for( ps = first_ctnr( ProcessList ); ps; ps = next_ctnr( ProcessList )) {
236
/* Process is still alive. Just clear flag. */
240
/* Process has probably died. We remove it from the list and
241
* destruct the data structure. */
242
free( remove_ctnr( ProcessList ));
247
void initProcessList( struct SensorModul* sm ) {
249
if( (procdir = opendir( PROCDIR )) == NULL ) {
250
print_error( "cannot open \"%s\" for reading\n", PROCDIR );
254
ProcessList = new_ctnr();
257
* register the supported monitors & commands
259
registerMonitor( "pscount", "integer",
260
printProcessCount, printProcessCountInfo, sm );
261
registerMonitor( "ps", "table",
262
printProcessList, printProcessListInfo, sm );
264
registerCommand( "kill", killProcess );
265
registerCommand( "setpriority", setPriority );
268
void exitProcessList( void ) {
270
destr_ctnr( ProcessList, free );
273
int updateProcessList( void ) {
277
rewinddir( procdir );
278
while( (de = readdir( procdir )) != NULL ) {
282
if( de->d_name[0] == '.' )
286
* fetch the process info and insert it into the info table
288
updateProcess( (pid_t) atol( de->d_name ));
290
cleanupProcessList();
295
void printProcessListInfo( const char *cmd ) {
296
fprintf(CurrentClient, "Name\tPID\tPPID\tGID\tStatus\tUser\tThreads"
297
"\tSize\tResident\t%% CPU\tPriority\tCommand\n" );
298
fprintf(CurrentClient, "s\td\td\td\ts\ts\td\tD\tD\tf\td\ts\n" );
301
void printProcessList( const char *cmd ) {
305
for( ps = first_ctnr( ProcessList ); ps; ps = next_ctnr( ProcessList )) {
306
fprintf(CurrentClient,
307
"%s\t%ld\t%ld\t%ld\t%s\t%s\t%d\t%d\t%d\t%.2f\t%d\t%s\n",
322
fprintf(CurrentClient, "\n");
325
void printProcessCount( const char *cmd ) {
326
fprintf(CurrentClient, "%d\n", ProcessCount );
329
void printProcessCountInfo( const char *cmd ) {
330
fprintf(CurrentClient, "Number of Processes\t0\t0\t\n" );
333
void killProcess( const char *cmd ) {
337
sscanf( cmd, "%*s %d %d", &pid, &sig );
340
case MENU_ID_SIGABRT:
343
case MENU_ID_SIGALRM:
346
case MENU_ID_SIGCHLD:
349
case MENU_ID_SIGCONT:
364
case MENU_ID_SIGKILL:
367
case MENU_ID_SIGPIPE:
370
case MENU_ID_SIGQUIT:
373
case MENU_ID_SIGSEGV:
376
case MENU_ID_SIGSTOP:
379
case MENU_ID_SIGTERM:
382
case MENU_ID_SIGTSTP:
385
case MENU_ID_SIGTTIN:
388
case MENU_ID_SIGTTOU:
391
case MENU_ID_SIGUSR1:
394
case MENU_ID_SIGUSR2:
398
if( kill( (pid_t) pid, sig )) {
401
fprintf(CurrentClient, "4\n" );
404
fprintf(CurrentClient, "3\n" );
407
fprintf(CurrentClient, "2\n" );
410
fprintf(CurrentClient, "1\n" ); /* unknown error */
414
fprintf(CurrentClient, "0\n");
417
void setPriority( const char *cmd ) {
420
sscanf( cmd, "%*s %d %d", &pid, &prio );
421
if( setpriority( PRIO_PROCESS, pid, prio )) {
424
fprintf(CurrentClient, "4\n" );
427
fprintf(CurrentClient, "3\n" );
431
fprintf(CurrentClient, "2\n" );
434
fprintf(CurrentClient, "1\n" ); /* unknown error */
438
fprintf(CurrentClient, "0\n");