xref: /minix/minix/fs/procfs/pid.c (revision e1cdaee1)
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
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
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
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
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
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
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