~ubuntu-branches/ubuntu/warty/kdebase/warty

« back to all changes in this revision

Viewing changes to ksysguard/ksysguardd/FreeBSD/ProcessList.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2004-09-16 04:51:45 UTC
  • Revision ID: james.westby@ubuntu.com-20040916045145-9vr63kith3k1cpza
Tags: upstream-3.2.2
ImportĀ upstreamĀ versionĀ 3.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    KSysGuard, the KDE System Guard
 
3
 
 
4
        Copyright (c) 1999-2000 Hans Petter Bieker<bieker@kde.org>
 
5
        Copyright (c) 1999 Chris Schlaeger <cs@kde.org>
 
6
 
 
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.
 
11
 
 
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.
 
16
 
 
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
20
 
 
21
        $Id: ProcessList.c,v 1.17 2004/01/10 20:29:44 leimbach Exp $
 
22
*/
 
23
 
 
24
#include <config.h>
 
25
 
 
26
#include <ctype.h>
 
27
#include <dirent.h>
 
28
#include <pwd.h>
 
29
#include <stdio.h>
 
30
#include <stdlib.h>
 
31
#include <string.h>
 
32
#include <sys/param.h>
 
33
 
 
34
#if defined(__DragonFly__)
 
35
#include <sys/user.h>
 
36
#include <sys/resourcevar.h>
 
37
#endif
 
38
 
 
39
#if __FreeBSD_version > 500015
 
40
#include <sys/priority.h>
 
41
#endif
 
42
#include <sys/sysctl.h>
 
43
#include <sys/time.h>
 
44
#include <sys/types.h>
 
45
#include <sys/user.h>
 
46
#include <unistd.h>
 
47
#include <signal.h>
 
48
 
 
49
#include "../../gui/SignalIDs.h"
 
50
#include "Command.h"
 
51
#include "ProcessList.h"
 
52
#include "ccont.h"
 
53
#include "ksysguardd.h"
 
54
 
 
55
CONTAINER ProcessList = 0;
 
56
 
 
57
int fscale;
 
58
 
 
59
#define BUFSIZE 1024
 
60
 
 
61
typedef struct
 
62
{
 
63
        /* This flag is set for all found processes at the beginning of the
 
64
         * process list update. Processes that do not have this flag set will
 
65
         * be assumed dead and removed from the list. The flag is cleared after
 
66
         * each list update. */
 
67
        int alive;
 
68
 
 
69
        /* the process ID */
 
70
        pid_t pid;
 
71
 
 
72
        /* the parent process ID */
 
73
        pid_t ppid;
 
74
 
 
75
        /* the real user ID */
 
76
        uid_t uid;
 
77
 
 
78
        /* the real group ID */
 
79
        gid_t gid;
 
80
 
 
81
        /* a character description of the process status */
 
82
        char status[16];
 
83
 
 
84
        /* the number of the tty the process owns */
 
85
        int ttyNo;
 
86
 
 
87
        /*
 
88
         * The nice level. The range should be -20 to 20. I'm not sure
 
89
         * whether this is true for all platforms.
 
90
         */
 
91
        int niceLevel;
 
92
 
 
93
        /*
 
94
         * The scheduling priority.
 
95
         */
 
96
        int priority;
 
97
 
 
98
        /*
 
99
         * The total amount of memory the process uses. This includes shared and
 
100
         * swapped memory.
 
101
         */
 
102
        unsigned int vmSize;
 
103
 
 
104
        /*
 
105
         * The amount of physical memory the process currently uses.
 
106
         */
 
107
        unsigned int vmRss;
 
108
 
 
109
        /*
 
110
         * The amount of memory (shared/swapped/etc) the process shares with
 
111
         * other processes.
 
112
         */
 
113
        unsigned int vmLib;
 
114
 
 
115
        /*
 
116
         * The number of 1/100 of a second the process has spend in user space.
 
117
         * If a machine has an uptime of 1 1/2 years or longer this is not a
 
118
         * good idea. I never thought that the stability of UNIX could get me
 
119
         * into trouble! ;)
 
120
         */
 
121
#if !defined(__DragonFly__)
 
122
        unsigned int userTime;
 
123
#else
 
124
        long userTime;
 
125
#endif
 
126
 
 
127
        /*
 
128
         * The number of 1/100 of a second the process has spend in system space.
 
129
         * If a machine has an uptime of 1 1/2 years or longer this is not a
 
130
         * good idea. I never thought that the stability of UNIX could get me
 
131
         * into trouble! ;)
 
132
         */
 
133
        unsigned int sysTime;
 
134
 
 
135
        /* system time as multime of 100ms */
 
136
        int centStamp;
 
137
 
 
138
        /* the current CPU load (in %) from user space */
 
139
        double userLoad;
 
140
 
 
141
        /* the current CPU load (in %) from system space */
 
142
        double sysLoad;
 
143
 
 
144
        /* the name of the process */
 
145
        char name[64];
 
146
 
 
147
        /* the command used to start the process */
 
148
        char cmdline[256];
 
149
 
 
150
        /* the login name of the user that owns this process */
 
151
        char userName[32];
 
152
} ProcessInfo;
 
153
 
 
154
static unsigned ProcessCount;
 
155
 
 
156
static int
 
157
processCmp(void* p1, void* p2)
 
158
{
 
159
        return (((ProcessInfo*) p1)->pid - ((ProcessInfo*) p2)->pid);
 
160
}
 
161
 
 
162
static ProcessInfo*
 
163
findProcessInList(int pid)
 
164
{
 
165
        ProcessInfo key;
 
166
        long index;
 
167
 
 
168
        key.pid = pid;
 
169
        if ((index = search_ctnr(ProcessList, processCmp, &key)) < 0)
 
170
                return (0);
 
171
 
 
172
        return (get_ctnr(ProcessList, index));
 
173
}
 
174
 
 
175
static int
 
176
updateProcess(int pid)
 
177
{
 
178
        static char *statuses[] = { "idle","run","sleep","stop","zombie" };
 
179
        
 
180
        ProcessInfo* ps;
 
181
        struct passwd* pwent;
 
182
        int mib[4];
 
183
        struct kinfo_proc p;
 
184
        struct rusage pru;
 
185
        size_t len;
 
186
        size_t buflen = 256;
 
187
        char buf[256];
 
188
 
 
189
        if ((ps = findProcessInList(pid)) == 0)
 
190
        {
 
191
                ps = (ProcessInfo*) malloc(sizeof(ProcessInfo));
 
192
                ps->pid = pid;
 
193
                ps->centStamp = 0;
 
194
                push_ctnr(ProcessList, ps);
 
195
                bsort_ctnr(ProcessList, processCmp);
 
196
        }
 
197
 
 
198
        ps->alive = 1;
 
199
 
 
200
        mib[0] = CTL_KERN;
 
201
        mib[1] = KERN_PROC;
 
202
        mib[2] = KERN_PROC_PID;
 
203
        mib[3] = pid;
 
204
 
 
205
        len = sizeof (p);
 
206
        if (sysctl(mib, 4, &p, &len, NULL, 0) == -1 || !len)
 
207
                return -1;
 
208
 
 
209
#if __FreeBSD_version >= 500015
 
210
        ps->pid       = p.ki_pid;
 
211
        ps->ppid      = p.ki_ppid;
 
212
        ps->uid       = p.ki_uid;    
 
213
        ps->gid       = p.ki_pgid;
 
214
        ps->priority  = p.ki_pri.pri_user;
 
215
        ps->niceLevel = p.ki_nice;
 
216
#else
 
217
        ps->pid       = p.kp_proc.p_pid;
 
218
        ps->ppid      = p.kp_eproc.e_ppid;
 
219
        ps->uid       = p.kp_eproc.e_ucred.cr_uid;
 
220
        ps->gid       = p.kp_eproc.e_pgid;
 
221
        ps->priority  = p.kp_proc.p_priority;
 
222
        ps->niceLevel = p.kp_proc.p_nice;
 
223
#endif
 
224
 
 
225
        /* this isn't usertime -- it's total time (??) */
 
226
#if __FreeBSD_version >= 500015
 
227
        ps->userTime = p.ki_runtime / 10000;
 
228
#elif __FreeBSD_version >= 300000
 
229
#if defined(__DragonFly__)
 
230
        if (!getrusage(p.kp_proc.p_pid, &pru))
 
231
        {
 
232
                errx(1, "failed to get rusage info");
 
233
        }
 
234
        ps->userTime = pru.ru_utime.tv_usec / 1000; /*p_runtime / 1000*/ 
 
235
#else
 
236
        ps->userTime = p.kp_proc.p_runtime / 10000;
 
237
#endif
 
238
#else
 
239
        ps->userTime = p.kp_proc.p_rtime.tv_sec*100+p.kp_proc.p_rtime.tv_usec/100;
 
240
#endif
 
241
        ps->sysTime  = 0;
 
242
        ps->sysLoad  = 0;
 
243
 
 
244
        /* memory, process name, process uid */
 
245
        /* find out user name with process uid */
 
246
        pwent = getpwuid(ps->uid);
 
247
        strncpy(ps->userName,pwent&&pwent->pw_name? pwent->pw_name:"????",sizeof(ps->userName));
 
248
        ps->userName[sizeof(ps->userName)-1]='\0';
 
249
 
 
250
        if (fscale == 0)
 
251
                ps->userLoad = 0;
 
252
        else
 
253
#if __FreeBSD_version >= 500015
 
254
                ps->userLoad = 100.0 * (double) p.ki_pctcpu / fscale;
 
255
        ps->vmSize   = p.ki_size;
 
256
        ps->vmRss    = p.ki_rssize * getpagesize();
 
257
        strlcpy(ps->name,p.ki_comm? p.ki_comm:"????",sizeof(ps->name));
 
258
        strcpy(ps->status,(p.ki_stat>=1)&&(p.ki_stat<=5)? statuses[p.ki_stat-1]:"????");
 
259
#else
 
260
                ps->userLoad = 100.0 * (double) p.kp_proc.p_pctcpu / fscale;
 
261
        ps->vmSize   = p.kp_eproc.e_vm.vm_map.size;
 
262
        ps->vmRss    = p.kp_eproc.e_vm.vm_rssize * getpagesize();
 
263
#if defined (__DragonFly__)
 
264
        strlcpy(ps->name,p.kp_thread.td_comm ? p.kp_thread.td_comm : "????", 
 
265
                sizeof(ps->name));
 
266
#else
 
267
        strlcpy(ps->name,p.kp_proc.p_comm ? p.kp_proc.p_comm : "????", sizeof(ps->name));
 
268
#endif
 
269
        strcpy(ps->status,(p.kp_proc.p_stat>=1)&&(p.kp_proc.p_stat<=5)? statuses[p.kp_proc.p_stat-1]:"????");
 
270
#endif
 
271
 
 
272
        /* process command line */
 
273
        /* do a sysctl to get the command line args. */
 
274
 
 
275
        mib[0] = CTL_KERN;
 
276
        mib[1] = KERN_PROC;
 
277
        mib[2] = KERN_PROC_ARGS;
 
278
        mib[3] = pid;
 
279
 
 
280
        if ((sysctl(mib, 4, buf, &buflen, 0, 0) == -1) || !buflen)
 
281
                strcpy(ps->cmdline, "????");
 
282
        else
 
283
                strncpy(ps->cmdline, buf, buflen);
 
284
 
 
285
        return (0);
 
286
}
 
287
 
 
288
static void
 
289
cleanupProcessList(void)
 
290
{
 
291
        ProcessInfo* ps;
 
292
 
 
293
        ProcessCount = 0;
 
294
        /* All processes that do not have the active flag set are assumed dead
 
295
         * and will be removed from the list. The alive flag is cleared. */
 
296
        for (ps = first_ctnr(ProcessList); ps; ps = next_ctnr(ProcessList))
 
297
        {
 
298
                if (ps->alive)
 
299
                {
 
300
                        /* Process is still alive. Just clear flag. */
 
301
                        ps->alive = 0;
 
302
                        ProcessCount++;
 
303
                }
 
304
                else
 
305
                {
 
306
                        /* Process has probably died. We remove it from the list and
 
307
                         * destruct the data structure. i needs to be decremented so
 
308
                         * that after i++ the next list element will be inspected. */
 
309
                        free(remove_ctnr(ProcessList));
 
310
                }
 
311
        }
 
312
}
 
313
 
 
314
/*
 
315
================================ public part ==================================
 
316
*/
 
317
 
 
318
void
 
319
initProcessList(struct SensorModul* sm)
 
320
{
 
321
        size_t fscalelen;
 
322
        ProcessList = new_ctnr();
 
323
 
 
324
        registerMonitor("ps", "table", printProcessList, printProcessListInfo, sm);
 
325
        registerMonitor("pscount", "integer", printProcessCount, printProcessCountInfo, sm);
 
326
 
 
327
        if (!RunAsDaemon)
 
328
        {
 
329
                registerCommand("kill", killProcess);
 
330
                registerCommand("setpriority", setPriority);
 
331
        }
 
332
 
 
333
        fscalelen = sizeof(fscale);
 
334
        if (sysctlbyname("kern.fscale", &fscale, &fscalelen, NULL, 0) == -1)
 
335
                fscale = 0;
 
336
 
 
337
        updateProcessList();
 
338
}
 
339
 
 
340
void
 
341
exitProcessList(void)
 
342
{
 
343
        removeMonitor("ps");
 
344
        removeMonitor("pscount");
 
345
 
 
346
        if (ProcessList)
 
347
                free (ProcessList);
 
348
}
 
349
 
 
350
int
 
351
updateProcessList(void)
 
352
{
 
353
        int mib[3];
 
354
        size_t len;
 
355
        size_t num;
 
356
        struct kinfo_proc *p;
 
357
 
 
358
 
 
359
        mib[0] = CTL_KERN;
 
360
        mib[1] = KERN_PROC;
 
361
        mib[2] = KERN_PROC_ALL;
 
362
        sysctl(mib, 3, NULL, &len, NULL, 0);
 
363
        p = malloc(len);
 
364
        sysctl(mib, 3, p, &len, NULL, 0);
 
365
 
 
366
        for (num = 0; num < len / sizeof(struct kinfo_proc); num++)
 
367
#if __FreeBSD_version >= 500015
 
368
                updateProcess(p[num].ki_pid);
 
369
#else
 
370
                updateProcess(p[num].kp_proc.p_pid);
 
371
#endif
 
372
        free(p);
 
373
        cleanupProcessList();
 
374
 
 
375
        return (0);
 
376
}
 
377
 
 
378
void
 
379
printProcessListInfo(const char* cmd)
 
380
{
 
381
        fprintf(CurrentClient, "Name\tPID\tPPID\tUID\tGID\tStatus\tUser%%\tSystem%%\tNice\tVmSize\tVmRss\tLogin\tCommand\n");
 
382
        fprintf(CurrentClient, "s\td\td\td\td\tS\tf\tf\td\tD\tD\ts\ts\n");
 
383
}
 
384
 
 
385
void
 
386
printProcessList(const char* cmd)
 
387
{
 
388
        ProcessInfo* ps;
 
389
 
 
390
        ps = first_ctnr(ProcessList); /* skip 'kernel' entry */
 
391
        for (ps = next_ctnr(ProcessList); ps; ps = next_ctnr(ProcessList))
 
392
        {
 
393
                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",
 
394
                           ps->name, (long)ps->pid, (long)ps->ppid,
 
395
                           (long)ps->uid, (long)ps->gid, ps->status,
 
396
                           ps->userLoad, ps->sysLoad, ps->niceLevel,
 
397
                           ps->vmSize / 1024, ps->vmRss / 1024, ps->userName, ps->cmdline);
 
398
        }
 
399
}
 
400
 
 
401
void
 
402
printProcessCount(const char* cmd)
 
403
{
 
404
        fprintf(CurrentClient, "%d\n", ProcessCount);
 
405
}
 
406
 
 
407
void
 
408
printProcessCountInfo(const char* cmd)
 
409
{
 
410
        fprintf(CurrentClient, "Number of Processes\t1\t65535\t\n");
 
411
}
 
412
 
 
413
void
 
414
killProcess(const char* cmd)
 
415
{
 
416
        int sig, pid;
 
417
 
 
418
        sscanf(cmd, "%*s %d %d", &pid, &sig);
 
419
        switch(sig)
 
420
        {
 
421
        case MENU_ID_SIGABRT:
 
422
                sig = SIGABRT;
 
423
                break;
 
424
        case MENU_ID_SIGALRM:
 
425
                sig = SIGALRM;
 
426
                break;
 
427
        case MENU_ID_SIGCHLD:
 
428
                sig = SIGCHLD;
 
429
                break;
 
430
        case MENU_ID_SIGCONT:
 
431
                sig = SIGCONT;
 
432
                break;
 
433
        case MENU_ID_SIGFPE:
 
434
                sig = SIGFPE;
 
435
                break;
 
436
        case MENU_ID_SIGHUP:
 
437
                sig = SIGHUP;
 
438
                break;
 
439
        case MENU_ID_SIGILL:
 
440
                sig = SIGILL;
 
441
                break;
 
442
        case MENU_ID_SIGINT:
 
443
                sig = SIGINT;
 
444
                break;
 
445
        case MENU_ID_SIGKILL:
 
446
                sig = SIGKILL;
 
447
                break;
 
448
        case MENU_ID_SIGPIPE:
 
449
                sig = SIGPIPE;
 
450
                break;
 
451
        case MENU_ID_SIGQUIT:
 
452
                sig = SIGQUIT;
 
453
                break;
 
454
        case MENU_ID_SIGSEGV:
 
455
                sig = SIGSEGV;
 
456
                break;
 
457
        case MENU_ID_SIGSTOP:
 
458
                sig = SIGSTOP;
 
459
                break;
 
460
        case MENU_ID_SIGTERM:
 
461
                sig = SIGTERM;
 
462
                break;
 
463
        case MENU_ID_SIGTSTP:
 
464
                sig = SIGTSTP;
 
465
                break;
 
466
        case MENU_ID_SIGTTIN:
 
467
                sig = SIGTTIN;
 
468
                break;
 
469
        case MENU_ID_SIGTTOU:
 
470
                sig = SIGTTOU;
 
471
                break;
 
472
        case MENU_ID_SIGUSR1:
 
473
                sig = SIGUSR1;
 
474
                break;
 
475
        case MENU_ID_SIGUSR2:
 
476
                sig = SIGUSR2;
 
477
                break;
 
478
        }
 
479
        if (kill((pid_t) pid, sig))
 
480
        {
 
481
                switch(errno)
 
482
                {
 
483
                case EINVAL:
 
484
                        fprintf(CurrentClient, "4\t%d\n", pid);
 
485
                        break;
 
486
                case ESRCH:
 
487
                        fprintf(CurrentClient, "3\t%d\n", pid);
 
488
                        break;
 
489
                case EPERM:
 
490
                        fprintf(CurrentClient, "2\t%d\n", pid);
 
491
                        break;
 
492
                default:
 
493
                        fprintf(CurrentClient, "1\t%d\n", pid); /* unknown error */
 
494
                        break;
 
495
                }
 
496
 
 
497
        }
 
498
        else
 
499
                fprintf(CurrentClient, "0\t%d\n", pid);
 
500
}
 
501
 
 
502
void
 
503
setPriority(const char* cmd)
 
504
{
 
505
        int pid, prio;
 
506
 
 
507
        sscanf(cmd, "%*s %d %d", &pid, &prio);
 
508
        if (setpriority(PRIO_PROCESS, pid, prio))
 
509
        {
 
510
                switch(errno)
 
511
                {
 
512
                case EINVAL:
 
513
                        fprintf(CurrentClient, "4\n");
 
514
                        break;
 
515
                case ESRCH:
 
516
                        fprintf(CurrentClient, "3\n");
 
517
                        break;
 
518
                case EPERM:
 
519
                case EACCES:
 
520
                        fprintf(CurrentClient, "2\n");
 
521
                        break;
 
522
                default:
 
523
                        fprintf(CurrentClient, "1\n");  /* unknown error */
 
524
                        break;
 
525
                }
 
526
        }
 
527
        else
 
528
                fprintf(CurrentClient, "0\n");
 
529
}