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