xref: /minix3/minix/fs/procfs/service.c (revision 77e79d33746fa2b709086b9caa51b1415d66c801)
1 /* ProcFS - service.c - the service subdirectory */
2 
3 #include "inc.h"
4 
5 #include <minix/rs.h>
6 #include "rs/const.h"
7 #include "rs/type.h"
8 
9 enum policy {
10 	POL_NONE	= 0x00,	/*     user	| endpoint	*/
11 	POL_RESET	= 0x01,	/* visible	|  change	*/
12 	POL_RESTART	= 0x02,	/* transparent	| preserved	*/
13 	POL_LIVE_UPDATE	= 0x04	/* transparent	| preserved	*/
14 };
15 
16 struct policies {
17 	#define MAX_POL_FORMAT_SZ 20
18 	char formatted[MAX_POL_FORMAT_SZ];
19 	enum policy supported;
20 };
21 
22 typedef struct {
23 	struct rproc proc[NR_SYS_PROCS];
24 	struct rprocpub pub[NR_SYS_PROCS];
25 } ixfer_rproc_t;
26 static ixfer_rproc_t rproc;
27 
28 static struct policies policies[NR_SYS_PROCS];
29 
30 static struct inode *service_node;
31 
32 /* Updates the policies state from RS. Always returns an ASCIIZ string.  */
33 static const char *
34 service_get_policies(struct policies * pol, index_t slot)
35 {
36 #if 1 /* The following should be retrieved from RS and formated instead. */
37 	int pos;
38 	char *ref_label;
39 	static const struct {
40 		const char *label;
41 		const char *policy_str;
42 	} def_pol[] = {
43 		/* audio */
44 		{ .label = "als4000", .policy_str = "reset" },
45 		{ .label = "cmi8738", .policy_str = "reset" },
46 		{ .label = "cs4281", .policy_str = "reset" },
47 		{ .label = "es1370", .policy_str = "reset" },
48 		{ .label = "es1371", .policy_str = "reset" },
49 		{ .label = "sb16", .policy_str = "reset" },
50 		{ .label = "trident", .policy_str = "reset" },
51 		/* bus */
52 		{ .label = "i2c", .policy_str = "restart" },
53 		{ .label = "pci", .policy_str = "restart" },
54 		{ .label = "ti1225", .policy_str = "restart" },
55 		/* clock */
56 		{ .label = "readclock.drv", .policy_str = "restart" },
57 		/* eeprom */
58 		{ .label = "cat24c256", .policy_str = "restart" },
59 		/* examples */
60 		{ .label = "hello", .policy_str = "restart" },
61 		/* hid */
62 		{ .label = "pckbd", .policy_str = "reset" },
63 		/* iommu */
64 		{ .label = "amddev", .policy_str = "" },
65 		/* net */
66 		{ .label = "3c90x", .policy_str = "reset" },
67 		{ .label = "atl2", .policy_str = "reset" },
68 		{ .label = "dec21140A", .policy_str = "reset" },
69 		{ .label = "dp8390", .policy_str = "reset" },
70 		{ .label = "dpeth", .policy_str = "reset" },
71 		{ .label = "e1000", .policy_str = "reset" },
72 		{ .label = "fxp", .policy_str = "reset" },
73 		{ .label = "ip1000", .policy_str = "reset" },
74 		{ .label = "lance", .policy_str = "reset" },
75 		{ .label = "lan8710a", .policy_str = "reset" },
76 		{ .label = "orinoco", .policy_str = "reset" },
77 		{ .label = "rtl8139", .policy_str = "reset" },
78 		{ .label = "rtl8169", .policy_str = "reset" },
79 		{ .label = "uds", .policy_str = "reset" },
80 		{ .label = "virtio_net", .policy_str = "reset" },
81 		{ .label = "vt6105", .policy_str = "reset" },
82 		/* power */
83 		{ .label = "acpi", .policy_str = "" },
84 		{ .label = "tps65217", .policy_str = "" },
85 		{ .label = "tps65590", .policy_str = "" },
86 		/* printer */
87 		{ .label = "printer", .policy_str = "restart" },
88 		/* sensors */
89 		{ .label = "bmp085", .policy_str = "" },
90 		{ .label = "sht21", .policy_str = "restart" },
91 		{ .label = "tsl2550", .policy_str = "restart" },
92 		/* storage */
93 		{ .label = "ahci", .policy_str = "reset" },
94 		{ .label = "at_wini", .policy_str = "reset" },
95 		{ .label = "fbd", .policy_str = "reset" },
96 		{ .label = "filter", .policy_str = "reset" },
97 		{ .label = "floppy", .policy_str = "reset" },
98 		{ .label = "memory", .policy_str = "restart" },
99 		{ .label = "mmc", .policy_str = "reset" },
100 		{ .label = "virtio_blk", .policy_str = "reset" },
101 		{ .label = "vnd", .policy_str = "reset" },
102 		/* system */
103 		{ .label = "gpio", .policy_str = "restart" },
104 		{ .label = "log", .policy_str = "reset" },
105 		{ .label = "random", .policy_str = "restart" },
106 		/* tty */
107 		{ .label = "pty", .policy_str = "restart" },
108 		{ .label = "tty", .policy_str = "restart" },
109 		/* usb */
110 		{ .label = "usbd", .policy_str = "" },
111 		{ .label = "usb_hub", .policy_str = "" },
112 		{ .label = "usb_storage", .policy_str = "" },
113 		/* video */
114 		{ .label = "fb", .policy_str = "" },
115 		{ .label = "tda19988", .policy_str = "" },
116 		/* vmm_guest */
117 		{ .label = "vbox", .policy_str = "" },
118 		/* fs */
119 		{ .label = "ext2", .policy_str = "" },
120 		{ .label = "hgfs", .policy_str = "" },
121 		{ .label = "isofs", .policy_str = "" },
122 		{ .label = "mfs", .policy_str = "restart" },
123 		{ .label = "pfs", .policy_str = "restart" },
124 		{ .label = "procfs", .policy_str = "restart" },
125 		{ .label = "ptyfs", .policy_str = "" },
126 		{ .label = "vbfs", .policy_str = "" },
127 		/* net */
128 		{ .label = "inet", .policy_str = "reset" },
129 		{ .label = "lwip", .policy_str = "" },
130 		/* servers */
131 		{ .label = "devman", .policy_str = "restart" },
132 		{ .label = "ds", .policy_str = "restart" },
133 		{ .label = "input", .policy_str = "reset" },
134 		{ .label = "ipc", .policy_str = "restart" },
135 		{ .label = "is", .policy_str = "restart" },
136 		{ .label = "mib", .policy_str = "restart" },
137 		{ .label = "pm", .policy_str = "restart" },
138 		{ .label = "rs", .policy_str = "restart" },
139 		{ .label = "sched", .policy_str = "restart" },
140 		{ .label = "vfs", .policy_str = "restart" },
141 		{ .label = "vm", .policy_str = "restart" },
142 		//{ .label = "", .policy_str = "" },
143 	};
144 
145 	/* Find the related policy, based on the file name of the service. */
146 	ref_label = strrchr(rproc.pub[slot].proc_name, '/');
147 	if (NULL == ref_label)
148 		ref_label = rproc.pub[slot].proc_name;
149 
150 	memset(pol[slot].formatted, 0, MAX_POL_FORMAT_SZ);
151 	for(pos = 0; pos < (sizeof(def_pol) / sizeof(def_pol[0])); pos++) {
152 		if (0 == strcmp(ref_label, def_pol[pos].label)) {
153 			(void)strncpy(pol[slot].formatted,
154 			    def_pol[pos].policy_str, MAX_POL_FORMAT_SZ);
155 			pol[slot].formatted[MAX_POL_FORMAT_SZ-1] = '\0';
156 			break;
157 		}
158 	}
159 #else
160 	/* Should do something sensible, based on flags from RS/SEF. */
161 #endif
162 
163 	return pol[slot].formatted;
164 }
165 
166 /* Returns a ASCIIZ string encoding RS flags.  */
167 static const char *
168 service_get_flags(index_t slot)
169 {
170 	static char str[10];
171 	int flags, sys_flags;
172 
173 	flags = rproc.proc[slot].r_flags;
174 	sys_flags = rproc.pub[slot].sys_flags;
175 
176 	str[0] = (flags & RS_ACTIVE)        ? 'A' : '-';
177 	str[1] = (flags & RS_UPDATING)      ? 'U' : '-';
178 	str[2] = (flags & RS_EXITING)       ? 'E' : '-';
179 	str[3] = (flags & RS_NOPINGREPLY)   ? 'N' : '-';
180 	str[4] = (sys_flags & SF_USE_COPY)  ? 'C' : '-';
181 	str[5] = (sys_flags & SF_USE_REPL)  ? 'R' : '-';
182 	str[6] = (sys_flags & SF_NEED_COPY) ? 'c' : '-';
183 	str[7] = (sys_flags & SF_NEED_REPL) ? 'r' : '-';
184 	str[8] = (sys_flags & SF_CORE_SRV)  ? 's' : '-';
185 	str[9] = '\0';
186 
187 	return str;
188 }
189 
190 /*
191  * Return whether a slot is in use and active.  The purpose of this check is
192  * to ensure that after eliminating all slots that do not pass this check, we
193  * are left with a set of live services each with a unique label.
194  */
195 static int
196 service_active(index_t slot)
197 {
198 
199 	/*
200 	 * Init is in RS's process tables as the representation of user
201 	 * processes.  It is not a system service.
202 	 */
203 	return ((rproc.proc[slot].r_flags & (RS_IN_USE | RS_ACTIVE)) ==
204 	    (RS_IN_USE | RS_ACTIVE) &&
205 	   rproc.pub[slot].endpoint != INIT_PROC_NR);
206 }
207 
208 /*
209  * Update the contents of the service directory, by first updating the RS
210  * tables and then updating the directory contents.
211  */
212 static void
213 service_update(void)
214 {
215 	struct inode *node;
216 	struct inode_stat stat;
217 	index_t slot;
218 	static int warned = FALSE;
219 	int r;
220 
221 	/* There is not much we can do if this call fails. */
222 	r = getsysinfo(RS_PROC_NR, SI_PROCALL_TAB, &rproc, sizeof(rproc));
223 	if (r != OK && !warned) {
224 		printf("PROCFS: unable to obtain RS tables (%d)\n", r);
225 		warned = TRUE;
226 	}
227 
228 	/*
229 	 * As with PIDs, we make two passes.  Delete first, then add.  This
230 	 * prevents problems in the hypothetical case that between updates, one
231 	 * slot ends up with the label name of a previous, different slot.
232 	 */
233 	for (slot = 0; slot < NR_SYS_PROCS; slot++) {
234 		if ((node = get_inode_by_index(service_node, slot)) == NULL)
235 			continue;
236 
237 		/*
238 		 * If the slot is no longer in use, or the label name does not
239 		 * match, the node must be deleted.
240 		 */
241 		if (!service_active(slot) ||
242 		    strcmp(get_inode_name(node), rproc.pub[slot].label))
243 			delete_inode(node);
244 	}
245 
246 	memset(&stat, 0, sizeof(stat));
247 	stat.mode = REG_ALL_MODE;
248 	stat.uid = SUPER_USER;
249 	stat.gid = SUPER_USER;
250 
251 	for (slot = 0; slot < NR_SYS_PROCS; slot++) {
252 		if (!service_active(slot) ||
253 		    get_inode_by_index(service_node, slot) != NULL)
254 			continue;
255 
256 		node = add_inode(service_node, rproc.pub[slot].label, slot,
257 		    &stat, (index_t)0, (cbdata_t)slot);
258 
259 		if (node == NULL)
260 			out_of_inodes();
261 	}
262 }
263 
264 /*
265  * Initialize the service directory.
266  */
267 void
268 service_init(void)
269 {
270 	struct inode *root, *node;
271 	struct inode_stat stat;
272 
273 	root = get_root_inode();
274 
275 	memset(&stat, 0, sizeof(stat));
276 	stat.mode = DIR_ALL_MODE;
277 	stat.uid = SUPER_USER;
278 	stat.gid = SUPER_USER;
279 
280 	service_node = add_inode(root, "service", NO_INDEX, &stat,
281 	    NR_SYS_PROCS, NULL);
282 
283 	if (service_node == NULL)
284 		panic("unable to create service node");
285 }
286 
287 /*
288  * A lookup request is being performed.  If it is in the service directory,
289  * update the tables.  We do this lazily, to reduce overhead.
290  */
291 void
292 service_lookup(struct inode * parent, clock_t now)
293 {
294 	static clock_t last_update = 0;
295 
296 	if (parent != service_node)
297 		return;
298 
299 	if (last_update != now) {
300 		service_update();
301 
302 		last_update = now;
303 	}
304 }
305 
306 /*
307  * A getdents request is being performed.  If it is in the service directory,
308  * update the tables.
309  */
310 void
311 service_getdents(struct inode * node)
312 {
313 
314 	if (node != service_node)
315 		return;
316 
317 	service_update();
318 }
319 
320 /*
321  * A read request is being performed.  If it is on a file in the service
322  * directory, process the read request.  We rely on the fact that any read
323  * call will have been preceded by a lookup, so its table entry has been
324  * updated very recently.
325  */
326 void
327 service_read(struct inode * node)
328 {
329 	struct inode *parent;
330 	index_t slot;
331 	struct rprocpub *rpub;
332 	struct rproc *rp;
333 
334 	if (get_parent_inode(node) != service_node)
335 		return;
336 
337 	slot = get_inode_index(node);
338 	rpub = &rproc.pub[slot];
339 	rp = &rproc.proc[slot];
340 
341 	/* TODO: add a large number of other fields! */
342 	buf_printf("filename: %s\n", rpub->proc_name);
343 	buf_printf("endpoint: %d\n", rpub->endpoint);
344 	buf_printf("pid:      %d\n", rp->r_pid);
345 	buf_printf("restarts: %d\n", rp->r_restarts);
346 	buf_printf("flags:    %s\n", service_get_flags(slot));
347 	buf_printf("policies: %s\n", service_get_policies(policies, slot));
348 	buf_printf("ASRcount: %u\n", rp->r_asr_count);
349 }
350