forked from Stichting-MINIX-Research-Foundation/minix
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpid.c
More file actions
380 lines (311 loc) · 10.2 KB
/
Copy pathpid.c
File metadata and controls
380 lines (311 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
/* ProcFS - pid.c - by Alen Stojanov and David van Moolenbroek */
#include "inc.h"
#include <sys/mman.h>
#include <minix/vm.h>
#define S_FRAME_SIZE 4096 /* use malloc if larger than this */
static char s_frame[S_FRAME_SIZE]; /* static storage for process frame */
static char *frame; /* pointer to process frame buffer */
static void pid_psinfo(int slot);
static void pid_cmdline(int slot);
static void pid_environ(int slot);
static void pid_map(int slot);
/* The files that are dynamically created in each PID directory. The data field
* contains each file's read function. Subdirectories are not yet supported.
*/
struct file pid_files[] = {
{ "psinfo", REG_ALL_MODE, (data_t) pid_psinfo },
{ "cmdline", REG_ALL_MODE, (data_t) pid_cmdline },
{ "environ", REG_ALL_MODE, (data_t) pid_environ },
{ "map", REG_ALL_MODE, (data_t) pid_map },
{ NULL, 0, (data_t) NULL }
};
/*===========================================================================*
* is_zombie *
*===========================================================================*/
static int is_zombie(int slot)
{
/* Is the given slot a zombie process?
*/
return (slot >= NR_TASKS &&
(mproc[slot - NR_TASKS].mp_flags & (TRACE_ZOMBIE | ZOMBIE)));
}
/*===========================================================================*
* pid_psinfo *
*===========================================================================*/
static void pid_psinfo(int i)
{
/* Print information used by ps(1) and top(1).
*/
int pi, task, state, type, p_state, f_state;
char name[PROC_NAME_LEN+1], *p;
struct vm_usage_info vui;
pid_t ppid;
pi = i - NR_TASKS;
task = proc[i].p_nr < 0;
/* Get the name of the process. Spaces would mess up the format.. */
if (task || mproc[i].mp_name[0] == 0)
strncpy(name, proc[i].p_name, sizeof(name) - 1);
else
strncpy(name, mproc[pi].mp_name, sizeof(name) - 1);
name[sizeof(name) - 1] = 0;
if ((p = strchr(name, ' ')) != NULL)
p[0] = 0;
/* Get the type of the process. */
if (task)
type = TYPE_TASK;
else if (mproc[i].mp_flags & PRIV_PROC)
type = TYPE_SYSTEM;
else
type = TYPE_USER;
/* Get the state of the process. */
if (!task) {
if (is_zombie(i))
state = STATE_ZOMBIE; /* zombie */
else if (mproc[pi].mp_flags & TRACE_STOPPED)
state = STATE_STOP; /* stopped (traced) */
else if (proc[i].p_rts_flags == 0)
state = STATE_RUN; /* in run-queue */
else if (fp_is_blocked(&fproc[pi]) ||
(mproc[pi].mp_flags & (WAITING | SIGSUSPENDED)))
state = STATE_SLEEP; /* sleeping */
else
state = STATE_WAIT; /* waiting */
} else {
if (proc[i].p_rts_flags == 0)
state = STATE_RUN; /* in run-queue */
else
state = STATE_WAIT; /* other i.e. waiting */
}
/* We assume that even if a process has become a zombie, its kernel
* proc entry still contains the old (but valid) information. Currently
* this is true, but in the future we may have to filter some fields.
*/
buf_printf("%d %c %d %s %c %d %d %lu %lu %lu %lu",
PSINFO_VERSION, /* information version */
type, /* process type */
(int) proc[i].p_endpoint, /* process endpoint */
name, /* process name */
state, /* process state letter */
(int) P_BLOCKEDON(&proc[i]), /* endpt blocked on, or NONE */
(int) proc[i].p_priority, /* process priority */
(long) proc[i].p_user_time, /* user time */
(long) proc[i].p_sys_time, /* system time */
ex64hi(proc[i].p_cycles), /* execution cycles */
ex64lo(proc[i].p_cycles)
);
memset(&vui, 0, sizeof(vui));
if (!is_zombie(i)) {
/* We don't care if this fails. */
(void) vm_info_usage(proc[i].p_endpoint, &vui);
}
/* If the process is not a kernel task, we add some extra info. */
if (!task) {
if (mproc[pi].mp_flags & WAITING)
p_state = PSTATE_WAITING;
else if (mproc[pi].mp_flags & SIGSUSPENDED)
p_state = PSTATE_SIGSUSP;
else
p_state = '-';
if (mproc[pi].mp_parent == pi)
ppid = NO_PID;
else
ppid = mproc[mproc[pi].mp_parent].mp_pid;
switch (fproc[pi].fp_blocked_on) {
case FP_BLOCKED_ON_NONE: f_state = FSTATE_NONE; break;
case FP_BLOCKED_ON_PIPE: f_state = FSTATE_PIPE; break;
case FP_BLOCKED_ON_LOCK: f_state = FSTATE_LOCK; break;
case FP_BLOCKED_ON_POPEN: f_state = FSTATE_POPEN; break;
case FP_BLOCKED_ON_SELECT: f_state = FSTATE_SELECT; break;
case FP_BLOCKED_ON_OTHER: f_state = FSTATE_TASK; break;
default: f_state = FSTATE_UNKNOWN;
}
buf_printf(" %lu %lu %lu %c %d %u %u %u %d %c %d %u",
vui.vui_total, /* total memory */
vui.vui_common, /* common memory */
vui.vui_shared, /* shared memory */
p_state, /* sleep state */
ppid, /* parent PID */
mproc[pi].mp_realuid, /* real UID */
mproc[pi].mp_effuid, /* effective UID */
mproc[pi].mp_procgrp, /* process group */
mproc[pi].mp_nice, /* nice value */
f_state, /* VFS block state */
(int) (fproc[pi].fp_blocked_on == FP_BLOCKED_ON_OTHER)
? fproc[pi].fp_task : NONE, /* block proc */
fproc[pi].fp_tty /* controlling tty */
);
}
/* always add kernel cycles */
buf_printf(" %lu %lu %lu %lu",
ex64hi(proc[i].p_kipc_cycles),
ex64lo(proc[i].p_kipc_cycles),
ex64hi(proc[i].p_kcall_cycles),
ex64lo(proc[i].p_kcall_cycles));
/* add total memory for tasks at the end */
if(task) buf_printf(" %lu", vui.vui_total);
/* Newline at the end of the file. */
buf_printf("\n");
}
/*===========================================================================*
* put_frame *
*===========================================================================*/
static void put_frame(void)
{
/* If we allocated memory dynamically during a call to get_frame(),
* free it up here.
*/
if (frame != s_frame)
free(frame);
}
/*===========================================================================*
* get_frame *
*===========================================================================*/
static int get_frame(int slot, vir_bytes *basep, vir_bytes *sizep,
size_t *nargsp)
{
/* Get the execution frame from the top of the given process's stack.
* It may be very large, in which case we temporarily allocate memory
* for it (up to a certain size).
*/
vir_bytes base, size;
size_t nargs;
if (proc[slot].p_nr < 0 || is_zombie(slot))
return FALSE;
/* Get the frame base address and size. Limit the size to whatever we
* can handle. If our static buffer is not sufficiently large to store
* the entire frame, allocate memory dynamically. It is then later
* freed by put_frame().
*/
base = mproc[slot - NR_TASKS].mp_frame_addr;
size = mproc[slot - NR_TASKS].mp_frame_len;
if (size < sizeof(size_t)) return FALSE;
if (size > ARG_MAX) size = ARG_MAX;
if (size > sizeof(s_frame)) {
frame = malloc(size);
if (frame == NULL)
return FALSE;
}
else frame = s_frame;
/* Copy in the complete process frame. */
if (sys_datacopy(proc[slot].p_endpoint, base,
SELF, (vir_bytes) frame, (phys_bytes) size) != OK) {
put_frame();
return FALSE;
}
frame[size] = 0; /* terminate any last string */
nargs = * (size_t *) frame;
if (nargs < 1 || sizeof(size_t) + sizeof(char *) * (nargs + 1) > size) {
put_frame();
return FALSE;
}
*basep = base;
*sizep = size;
*nargsp = nargs;
/* The caller now has to called put_frame() to clean up. */
return TRUE;
}
/*===========================================================================*
* pid_cmdline *
*===========================================================================*/
static void pid_cmdline(int slot)
{
/* Dump the process's command line as it is contained in the process
* itself. Each argument is terminated with a null character.
*/
vir_bytes base, size, ptr;
size_t i, len, nargs;
char **argv;
if (!get_frame(slot, &base, &size, &nargs))
return;
argv = (char **) &frame[sizeof(size_t)];
for (i = 0; i < nargs; i++) {
ptr = (vir_bytes) argv[i] - base;
/* Check for bad pointers. */
if ((long) ptr < 0L || ptr >= size)
break;
len = strlen(&frame[ptr]) + 1;
buf_append(&frame[ptr], len);
}
put_frame();
}
/*===========================================================================*
* pid_environ *
*===========================================================================*/
static void pid_environ(int slot)
{
/* Dump the process's initial environment as it is contained in the
* process itself. Each entry is terminated with a null character.
*/
vir_bytes base, size, ptr;
size_t nargs, off, len;
char **envp;
if (!get_frame(slot, &base, &size, &nargs))
return;
off = sizeof(size_t) + sizeof(char *) * (nargs + 1);
envp = (char **) &frame[off];
for (;;) {
/* Make sure there is no buffer overrun. */
if (off + sizeof(char *) > size)
break;
ptr = (vir_bytes) *envp;
/* Stop at the terminating NULL pointer. */
if (ptr == 0L)
break;
ptr -= base;
/* Check for bad pointers. */
if ((long) ptr < 0L || ptr >= size)
break;
len = strlen(&frame[ptr]) + 1;
buf_append(&frame[ptr], len);
off += sizeof(char *);
envp++;
}
put_frame();
}
/*===========================================================================*
* dump_regions *
*===========================================================================*/
static int dump_regions(int slot)
{
/* Print the virtual memory regions of a process.
*/
struct vm_region_info vri[MAX_VRI_COUNT];
vir_bytes next;
int i, r, count;
count = 0;
next = 0;
do {
r = vm_info_region(proc[slot].p_endpoint, vri, MAX_VRI_COUNT,
&next);
if (r < 0)
return r;
if (r == 0)
break;
for (i = 0; i < r; i++) {
buf_printf("%08lx-%08lx %c%c%c\n",
vri[i].vri_addr, vri[i].vri_addr + vri[i].vri_length,
(vri[i].vri_prot & PROT_READ) ? 'r' : '-',
(vri[i].vri_prot & PROT_WRITE) ? 'w' : '-',
(vri[i].vri_prot & PROT_EXEC) ? 'x' : '-');
count++;
}
} while (r == MAX_VRI_COUNT);
return count;
}
/*===========================================================================*
* pid_map *
*===========================================================================*/
static void pid_map(int slot)
{
/* Print a memory map of the process. Obtain the information from VM if
* possible; otherwise fall back on segments from the kernel.
*/
/* Zombies have no memory. */
if (is_zombie(slot))
return;
/* Kernel tasks also have no memory. */
if (proc[slot].p_nr >= 0) {
if (dump_regions(slot) != 0)
return;
}
}