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