1 /* ProcFS - pid.c - generators for PID-specific files */
2
3 #include "inc.h"
4
5 #include <sys/mman.h>
6 #include <minix/vm.h>
7
8 static void pid_psinfo(int slot);
9 static void pid_cmdline(int slot);
10 static void pid_environ(int slot);
11 static void pid_map(int slot);
12
13 /*
14 * The files that are dynamically created in each PID directory. The data
15 * field contains each file's read function. Subdirectories are not yet
16 * supported.
17 */
18 struct file pid_files[] = {
19 { "psinfo", REG_ALL_MODE, (data_t) pid_psinfo },
20 { "cmdline", REG_ALL_MODE, (data_t) pid_cmdline },
21 { "environ", REG_ALL_MODE, (data_t) pid_environ },
22 { "map", REG_ALL_MODE, (data_t) pid_map },
23 { NULL, 0, (data_t) NULL }
24 };
25
26 /*
27 * Is the given slot a zombie process?
28 */
29 static int
is_zombie(int slot)30 is_zombie(int slot)
31 {
32
33 return (slot >= NR_TASKS &&
34 (proc_list[slot - NR_TASKS].mpl_flags & MPLF_ZOMBIE));
35 }
36
37 /*
38 * Get MINIX3-specific process data for the process identified by the given
39 * kernel slot. Return OK or a negative error code.
40 */
41 int
get_proc_data(pid_t pid,struct minix_proc_data * mpd)42 get_proc_data(pid_t pid, struct minix_proc_data * mpd)
43 {
44 int mib[4] = { CTL_MINIX, MINIX_PROC, PROC_DATA, pid };
45 size_t oldlen;
46
47 oldlen = sizeof(*mpd);
48 if (__sysctl(mib, __arraycount(mib), mpd, &oldlen, NULL, 0) != 0)
49 return -errno;
50
51 return OK;
52 }
53
54 /*
55 * Print process information. This feature is now used only by mtop(1), and as
56 * a result, we only provide information that mtop(1) actually uses. In the
57 * future, this file may be extended with additional fields again.
58 */
59 static void
pid_psinfo(int slot)60 pid_psinfo(int slot)
61 {
62 struct minix_proc_data mpd;
63 struct vm_usage_info vui;
64 pid_t pid;
65 uid_t uid;
66 char *p;
67 int task, type, state;
68
69 if ((pid = pid_from_slot(slot)) == 0)
70 return;
71
72 if (get_proc_data(pid, &mpd) != OK)
73 return;
74
75 task = (slot < NR_TASKS);
76
77 /* Get the type of the process. */
78 if (task)
79 type = TYPE_TASK;
80 else if (mpd.mpd_flags & MPDF_SYSTEM)
81 type = TYPE_SYSTEM;
82 else
83 type = TYPE_USER;
84
85 /*
86 * Get the (rudimentary) state of the process. The zombie flag is also
87 * in the proc_list entry but it just may be set since we obtained that
88 * entry, in which case we'd end up with the wrong state here.
89 */
90 if (mpd.mpd_flags & MPDF_ZOMBIE)
91 state = STATE_ZOMBIE;
92 else if (mpd.mpd_flags & MPDF_RUNNABLE)
93 state = STATE_RUN;
94 else if (mpd.mpd_flags & MPDF_STOPPED)
95 state = STATE_STOP;
96 else
97 state = STATE_SLEEP;
98
99 /* Get the process's effective user ID. */
100 if (!task)
101 uid = proc_list[slot - NR_TASKS].mpl_uid;
102 else
103 uid = 0;
104
105 /* Get memory usage. We do not care if this fails. */
106 memset(&vui, 0, sizeof(vui));
107 if (!(mpd.mpd_flags & MPDF_ZOMBIE))
108 (void)vm_info_usage(mpd.mpd_endpoint, &vui);
109
110 /* Spaces in the process name would mess up the output format. */
111 if ((p = strchr(mpd.mpd_name, ' ')) != NULL)
112 *p = '\0';
113
114 /* Print all the information. */
115 buf_printf("%d %c %d %s %c %d %d %u %u "
116 "%"PRIu64" %"PRIu64" %"PRIu64" %lu %d %u\n",
117 PSINFO_VERSION, /* information version */
118 type, /* process type */
119 mpd.mpd_endpoint, /* process endpoint */
120 mpd.mpd_name, /* process name */
121 state, /* process state letter */
122 mpd.mpd_blocked_on, /* endpt blocked on, or NONE */
123 mpd.mpd_priority, /* process priority */
124 mpd.mpd_user_time, /* user time */
125 mpd.mpd_sys_time, /* system time */
126 mpd.mpd_cycles, /* execution cycles */
127 mpd.mpd_kipc_cycles, /* kernel IPC cycles */
128 mpd.mpd_kcall_cycles, /* kernel call cycles */
129 vui.vui_total, /* total memory */
130 mpd.mpd_nice, /* nice value */
131 uid /* effective user ID */
132 );
133 }
134
135 /*
136 * Dump the process's command line as it is contained in the process itself.
137 * Each argument is terminated with a null character.
138 */
139 static void
pid_cmdline(int slot)140 pid_cmdline(int slot)
141 {
142 char buf[BUF_SIZE];
143 int mib[] = { CTL_KERN, KERN_PROC_ARGS, 0, KERN_PROC_ARGV };
144 size_t oldlen;
145 pid_t pid;
146
147 /* Kernel tasks and zombies have no memory. */
148 if ((pid = pid_from_slot(slot)) <= 0 || is_zombie(slot))
149 return;
150
151 mib[2] = proc_list[slot - NR_TASKS].mpl_pid;
152
153 /* TODO: zero-copy into the main output buffer */
154 oldlen = sizeof(buf);
155
156 if (__sysctl(mib, __arraycount(mib), buf, &oldlen, NULL, 0) != 0)
157 return;
158
159 buf_append(buf, oldlen);
160 }
161
162 /*
163 * Dump the process's initial environment as it is contained in the process
164 * itself. Each entry is terminated with a null character.
165 */
166 static void
pid_environ(int slot)167 pid_environ(int slot)
168 {
169 char buf[BUF_SIZE];
170 int mib[] = { CTL_KERN, KERN_PROC_ARGS, 0, KERN_PROC_ENV };
171 size_t oldlen;
172 pid_t pid;
173
174 /* Kernel tasks and zombies have no memory. */
175 if ((pid = pid_from_slot(slot)) <= 0 || is_zombie(slot))
176 return;
177
178 mib[2] = proc_list[slot - NR_TASKS].mpl_pid;
179
180 /* TODO: zero-copy into the main output buffer */
181 oldlen = sizeof(buf);
182
183 if (__sysctl(mib, __arraycount(mib), buf, &oldlen, NULL, 0) != 0)
184 return;
185
186 buf_append(buf, oldlen);
187 }
188
189 /*
190 * Print the virtual memory regions of a process.
191 */
192 static void
pid_map(int slot)193 pid_map(int slot)
194 {
195 struct minix_proc_data mpd;
196 struct vm_region_info vri[MAX_VRI_COUNT];
197 vir_bytes next;
198 pid_t pid;
199 int i, r, count;
200
201 /* Kernel tasks and zombies have no memory. */
202 if ((pid = pid_from_slot(slot)) <= 0 || is_zombie(slot))
203 return;
204
205 /* Get the process endpoint. */
206 if (get_proc_data(pid, &mpd) != OK)
207 return;
208
209 count = 0;
210 next = 0;
211
212 do {
213 r = vm_info_region(mpd.mpd_endpoint, vri, MAX_VRI_COUNT,
214 &next);
215
216 if (r <= 0)
217 break;
218
219 for (i = 0; i < r; i++) {
220 buf_printf("%08lx-%08lx %c%c%c\n",
221 vri[i].vri_addr,
222 vri[i].vri_addr + vri[i].vri_length,
223 (vri[i].vri_prot & PROT_READ) ? 'r' : '-',
224 (vri[i].vri_prot & PROT_WRITE) ? 'w' : '-',
225 (vri[i].vri_prot & PROT_EXEC) ? 'x' : '-');
226
227 count++;
228 }
229 } while (r == MAX_VRI_COUNT);
230 }
231