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 *
service_get_policies(struct policies * pol,index_t slot)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 = "lwip", .policy_str = "reset" },
129 /* servers */
130 { .label = "devman", .policy_str = "restart" },
131 { .label = "ds", .policy_str = "restart" },
132 { .label = "input", .policy_str = "reset" },
133 { .label = "ipc", .policy_str = "restart" },
134 { .label = "is", .policy_str = "restart" },
135 { .label = "mib", .policy_str = "restart" },
136 { .label = "pm", .policy_str = "restart" },
137 { .label = "rs", .policy_str = "restart" },
138 { .label = "sched", .policy_str = "restart" },
139 { .label = "vfs", .policy_str = "restart" },
140 { .label = "vm", .policy_str = "restart" },
141 //{ .label = "", .policy_str = "" },
142 };
143
144 /* Find the related policy, based on the file name of the service. */
145 ref_label = strrchr(rproc.pub[slot].proc_name, '/');
146 if (NULL == ref_label)
147 ref_label = rproc.pub[slot].proc_name;
148
149 memset(pol[slot].formatted, 0, MAX_POL_FORMAT_SZ);
150 for(pos = 0; pos < (sizeof(def_pol) / sizeof(def_pol[0])); pos++) {
151 if (0 == strcmp(ref_label, def_pol[pos].label)) {
152 (void)strncpy(pol[slot].formatted,
153 def_pol[pos].policy_str, MAX_POL_FORMAT_SZ);
154 pol[slot].formatted[MAX_POL_FORMAT_SZ-1] = '\0';
155 break;
156 }
157 }
158 #else
159 /* Should do something sensible, based on flags from RS/SEF. */
160 #endif
161
162 return pol[slot].formatted;
163 }
164
165 /* Returns a ASCIIZ string encoding RS flags. */
166 static const char *
service_get_flags(index_t slot)167 service_get_flags(index_t slot)
168 {
169 static char str[10];
170 int flags, sys_flags;
171
172 flags = rproc.proc[slot].r_flags;
173 sys_flags = rproc.pub[slot].sys_flags;
174
175 str[0] = (flags & RS_ACTIVE) ? 'A' : '-';
176 str[1] = (flags & RS_UPDATING) ? 'U' : '-';
177 str[2] = (flags & RS_EXITING) ? 'E' : '-';
178 str[3] = (flags & RS_NOPINGREPLY) ? 'N' : '-';
179 str[4] = (sys_flags & SF_USE_COPY) ? 'C' : '-';
180 str[5] = (sys_flags & SF_USE_REPL) ? 'R' : '-';
181 str[6] = (sys_flags & SF_NEED_COPY) ? 'c' : '-';
182 str[7] = (sys_flags & SF_NEED_REPL) ? 'r' : '-';
183 str[8] = (sys_flags & SF_CORE_SRV) ? 's' : '-';
184 str[9] = '\0';
185
186 return str;
187 }
188
189 /*
190 * Return whether a slot is in use and active. The purpose of this check is
191 * to ensure that after eliminating all slots that do not pass this check, we
192 * are left with a set of live services each with a unique label.
193 */
194 static int
service_active(index_t slot)195 service_active(index_t slot)
196 {
197
198 /*
199 * Init is in RS's process tables as the representation of user
200 * processes. It is not a system service.
201 */
202 return ((rproc.proc[slot].r_flags & (RS_IN_USE | RS_ACTIVE)) ==
203 (RS_IN_USE | RS_ACTIVE) &&
204 rproc.pub[slot].endpoint != INIT_PROC_NR);
205 }
206
207 /*
208 * Update the contents of the service directory, by first updating the RS
209 * tables and then updating the directory contents.
210 */
211 static void
service_update(void)212 service_update(void)
213 {
214 struct inode *node;
215 struct inode_stat stat;
216 index_t slot;
217 static int warned = FALSE;
218 int r;
219
220 /* There is not much we can do if this call fails. */
221 r = getsysinfo(RS_PROC_NR, SI_PROCALL_TAB, &rproc, sizeof(rproc));
222 if (r != OK && !warned) {
223 printf("PROCFS: unable to obtain RS tables (%d)\n", r);
224 warned = TRUE;
225 }
226
227 /*
228 * As with PIDs, we make two passes. Delete first, then add. This
229 * prevents problems in the hypothetical case that between updates, one
230 * slot ends up with the label name of a previous, different slot.
231 */
232 for (slot = 0; slot < NR_SYS_PROCS; slot++) {
233 if ((node = get_inode_by_index(service_node, slot)) == NULL)
234 continue;
235
236 /*
237 * If the slot is no longer in use, or the label name does not
238 * match, the node must be deleted.
239 */
240 if (!service_active(slot) ||
241 strcmp(get_inode_name(node), rproc.pub[slot].label))
242 delete_inode(node);
243 }
244
245 memset(&stat, 0, sizeof(stat));
246 stat.mode = REG_ALL_MODE;
247 stat.uid = SUPER_USER;
248 stat.gid = SUPER_USER;
249
250 for (slot = 0; slot < NR_SYS_PROCS; slot++) {
251 if (!service_active(slot) ||
252 get_inode_by_index(service_node, slot) != NULL)
253 continue;
254
255 node = add_inode(service_node, rproc.pub[slot].label, slot,
256 &stat, (index_t)0, (cbdata_t)slot);
257
258 if (node == NULL)
259 out_of_inodes();
260 }
261 }
262
263 /*
264 * Initialize the service directory.
265 */
266 void
service_init(void)267 service_init(void)
268 {
269 struct inode *root, *node;
270 struct inode_stat stat;
271
272 root = get_root_inode();
273
274 memset(&stat, 0, sizeof(stat));
275 stat.mode = DIR_ALL_MODE;
276 stat.uid = SUPER_USER;
277 stat.gid = SUPER_USER;
278
279 service_node = add_inode(root, "service", NO_INDEX, &stat,
280 NR_SYS_PROCS, NULL);
281
282 if (service_node == NULL)
283 panic("unable to create service node");
284 }
285
286 /*
287 * A lookup request is being performed. If it is in the service directory,
288 * update the tables. We do this lazily, to reduce overhead.
289 */
290 void
service_lookup(struct inode * parent,clock_t now)291 service_lookup(struct inode * parent, clock_t now)
292 {
293 static clock_t last_update = 0;
294
295 if (parent != service_node)
296 return;
297
298 if (last_update != now) {
299 service_update();
300
301 last_update = now;
302 }
303 }
304
305 /*
306 * A getdents request is being performed. If it is in the service directory,
307 * update the tables.
308 */
309 void
service_getdents(struct inode * node)310 service_getdents(struct inode * node)
311 {
312
313 if (node != service_node)
314 return;
315
316 service_update();
317 }
318
319 /*
320 * A read request is being performed. If it is on a file in the service
321 * directory, process the read request. We rely on the fact that any read
322 * call will have been preceded by a lookup, so its table entry has been
323 * updated very recently.
324 */
325 void
service_read(struct inode * node)326 service_read(struct inode * node)
327 {
328 struct inode *parent;
329 index_t slot;
330 struct rprocpub *rpub;
331 struct rproc *rp;
332
333 if (get_parent_inode(node) != service_node)
334 return;
335
336 slot = get_inode_index(node);
337 rpub = &rproc.pub[slot];
338 rp = &rproc.proc[slot];
339
340 /* TODO: add a large number of other fields! */
341 buf_printf("filename: %s\n", rpub->proc_name);
342 buf_printf("endpoint: %d\n", rpub->endpoint);
343 buf_printf("pid: %d\n", rp->r_pid);
344 buf_printf("restarts: %d\n", rp->r_restarts);
345 buf_printf("flags: %s\n", service_get_flags(slot));
346 buf_printf("policies: %s\n", service_get_policies(policies, slot));
347 buf_printf("ASRcount: %u\n", rp->r_asr_count);
348 }
349