~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

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