/* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md * Copyright (C) 2014-2018 K. Lange */ #include #include #include #include #include #include #include #include #include #include #define PROCFS_STANDARD_ENTRIES (sizeof(std_entries) / sizeof(struct procfs_entry)) #define PROCFS_PROCDIR_ENTRIES (sizeof(procdir_entries) / sizeof(struct procfs_entry)) struct procfs_entry { int id; char * name; read_type_t func; }; static fs_node_t * procfs_generic_create(char * name, read_type_t read_func) { fs_node_t * fnode = malloc(sizeof(fs_node_t)); memset(fnode, 0x00, sizeof(fs_node_t)); fnode->inode = 0; strcpy(fnode->name, name); fnode->uid = 0; fnode->gid = 0; fnode->mask = 0444; fnode->flags = FS_FILE; fnode->read = read_func; fnode->write = NULL; fnode->open = NULL; fnode->close = NULL; fnode->readdir = NULL; fnode->finddir = NULL; fnode->ctime = now(); fnode->mtime = now(); fnode->atime = now(); return fnode; } static uint32_t proc_cmdline_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { char buf[1024]; process_t * proc = process_from_pid(node->inode); if (!proc) { /* wat */ return 0; } if (!proc->cmdline) { sprintf(buf, "%s", proc->name); size_t _bsize = strlen(buf); if (offset > _bsize) return 0; if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); return size; } buf[0] = '\0'; char * _buf = buf; char ** args = proc->cmdline; while (*args) { strcpy(_buf, *args); _buf += strlen(_buf); if (*(args+1)) { strcpy(_buf, "\036"); _buf += strlen(_buf); } args++; } size_t _bsize = strlen(buf); if (offset > _bsize) return 0; if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); return size; } static size_t calculate_memory_usage(page_directory_t * src) { size_t pages = 0; for (uint32_t i = 0; i < 1024; ++i) { if (!src->tables[i] || (uintptr_t)src->tables[i] == (uintptr_t)0xFFFFFFFF) { continue; } if (kernel_directory->tables[i] == src->tables[i]) { continue; } /* For each table */ if (i * 0x1000 * 1024 < SHM_START) { /* Ignore shared memory for now */ for (int j = 0; j < 1024; ++j) { /* For each frame in the table... */ if (!src->tables[i]->pages[j].frame) { continue; } pages++; } } } return pages; } static size_t calculate_shm_resident(page_directory_t * src) { size_t pages = 0; for (uint32_t i = 0; i < 1024; ++i) { if (!src->tables[i] || (uintptr_t)src->tables[i] == (uintptr_t)0xFFFFFFFF) { continue; } if (kernel_directory->tables[i] == src->tables[i]) { continue; } if (i * 0x1000 * 1024 < SHM_START) { continue; } for (int j = 0; j < 1024; ++j) { /* For each frame in the table... */ if (!src->tables[i]->pages[j].frame) { continue; } pages++; } } return pages; } static uint32_t proc_status_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { char buf[2048]; process_t * proc = process_from_pid(node->inode); process_t * parent = process_get_parent(proc); if (!proc) { /* wat */ return 0; } char state = proc->finished ? 'Z' : (process_is_ready(proc) ? 'R' : 'S'); char * name = proc->name + strlen(proc->name) - 1; while (1) { if (*name == '/') { name++; break; } if (name == proc->name) break; name--; } /* Calculate process memory usage */ int mem_usage = calculate_memory_usage(proc->thread.page_directory) * 4; int shm_usage = calculate_shm_resident(proc->thread.page_directory) * 4; int mem_permille = 1000 * (mem_usage + shm_usage) / memory_total(); sprintf(buf, "Name:\t%s\n" /* name */ "State:\t%c\n" /* yeah, do this at some point */ "Tgid:\t%d\n" /* group ? group : pid */ "Pid:\t%d\n" /* pid */ "PPid:\t%d\n" /* parent pid */ "Uid:\t%d\n" "Ueip:\t0x%x\n" "SCid:\t%d\n" "SC0:\t0x%x\n" "SC1:\t0x%x\n" "SC2:\t0x%x\n" "SC3:\t0x%x\n" "SC4:\t0x%x\n" "UserStack:\t0x%x\n" "Path:\t%s\n" "VmSize:\t %d kB\n" "RssShmem:\t %d kB\n" "MemPermille:\t %d\n" , name, state, proc->group ? proc->group : proc->id, proc->id, parent ? parent->id : 0, proc->user, proc->syscall_registers ? proc->syscall_registers->eip : 0, proc->syscall_registers ? proc->syscall_registers->eax : 0, proc->syscall_registers ? proc->syscall_registers->ebx : 0, proc->syscall_registers ? proc->syscall_registers->ecx : 0, proc->syscall_registers ? proc->syscall_registers->edx : 0, proc->syscall_registers ? proc->syscall_registers->esi : 0, proc->syscall_registers ? proc->syscall_registers->edi : 0, proc->syscall_registers ? proc->syscall_registers->useresp : 0, proc->cmdline ? proc->cmdline[0] : "(none)", mem_usage, shm_usage, mem_permille ); size_t _bsize = strlen(buf); if (offset > _bsize) return 0; if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); return size; } static struct procfs_entry procdir_entries[] = { {1, "cmdline", proc_cmdline_func}, {2, "status", proc_status_func}, }; static struct dirent * readdir_procfs_procdir(fs_node_t *node, uint32_t index) { if (index == 0) { struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); out->ino = 0; strcpy(out->name, "."); return out; } if (index == 1) { struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); out->ino = 0; strcpy(out->name, ".."); return out; } index -= 2; if (index < PROCFS_PROCDIR_ENTRIES) { struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); out->ino = procdir_entries[index].id; strcpy(out->name, procdir_entries[index].name); return out; } return NULL; } static fs_node_t * finddir_procfs_procdir(fs_node_t * node, char * name) { if (!name) return NULL; for (unsigned int i = 0; i < PROCFS_PROCDIR_ENTRIES; ++i) { if (!strcmp(name, procdir_entries[i].name)) { fs_node_t * out = procfs_generic_create(procdir_entries[i].name, procdir_entries[i].func); out->inode = node->inode; return out; } } return NULL; } static fs_node_t * procfs_procdir_create(process_t * process) { pid_t pid = process->id; fs_node_t * fnode = malloc(sizeof(fs_node_t)); memset(fnode, 0x00, sizeof(fs_node_t)); fnode->inode = pid; sprintf(fnode->name, "%d", pid); fnode->uid = 0; fnode->gid = 0; fnode->mask = 0555; fnode->flags = FS_DIRECTORY; fnode->read = NULL; fnode->write = NULL; fnode->open = NULL; fnode->close = NULL; fnode->readdir = readdir_procfs_procdir; fnode->finddir = finddir_procfs_procdir; fnode->nlink = 1; fnode->ctime = process->start.tv_sec; fnode->mtime = process->start.tv_sec; fnode->atime = process->start.tv_sec; return fnode; } #define cpuid(in,a,b,c,d) do { asm volatile ("cpuid" : "=a"(a),"=b"(b),"=c"(c),"=d"(d) : "a"(in)); } while(0) static uint32_t cpuinfo_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { char buf[1024]; unsigned long a, b, unused;; cpuid(0,unused,b,unused,unused); char * _manu = "Unknown"; int _model = 0, _family = 0; if (b == 0x756e6547) { cpuid(1, a, b, unused, unused); _manu = "Intel"; _model = (a >> 4) & 0x0F; _family = (a >> 8) & 0x0F; } else if (b == 0x68747541) { cpuid(1, a, unused, unused, unused); _manu = "AMD"; _model = (a >> 4) & 0x0F; _family = (a >> 8) & 0x0F; } sprintf(buf, "Manufacturer: %s\n" "Family: %d\n" "Model: %d\n" , _manu, _family, _model); size_t _bsize = strlen(buf); if (offset > _bsize) return 0; if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); return size; } extern uintptr_t heap_end; extern uintptr_t kernel_heap_alloc_point; static uint32_t meminfo_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { char buf[1024]; unsigned int total = memory_total(); unsigned int free = total - memory_use(); unsigned int kheap = (heap_end - kernel_heap_alloc_point) / 1024; sprintf(buf, "MemTotal: %d kB\n" "MemFree: %d kB\n" "KHeapUse: %d kB\n" , total, free, kheap); size_t _bsize = strlen(buf); if (offset > _bsize) return 0; if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); return size; } static uint32_t pat_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { char buf[1024]; uint64_t pat_values; asm volatile ( "rdmsr" : "=A" (pat_values) : "c" (0x277) ); char * pat_names[] = { "uncacheable (UC)", "write combining (WC)", "Reserved", "Reserved", "write through (WT)", "write protected (WP)", "write back (WB)", "uncached (UC-)" }; int pa_0 = (pat_values >> 0) & 0x7; int pa_1 = (pat_values >> 8) & 0x7; int pa_2 = (pat_values >> 16) & 0x7; int pa_3 = (pat_values >> 24) & 0x7; int pa_4 = (pat_values >> 32) & 0x7; int pa_5 = (pat_values >> 40) & 0x7; int pa_6 = (pat_values >> 48) & 0x7; int pa_7 = (pat_values >> 56) & 0x7; sprintf(buf, "PA0: %d %s\n" "PA1: %d %s\n" "PA2: %d %s\n" "PA3: %d %s\n" "PA4: %d %s\n" "PA5: %d %s\n" "PA6: %d %s\n" "PA7: %d %s\n", pa_0, pat_names[pa_0], pa_1, pat_names[pa_1], pa_2, pat_names[pa_2], pa_3, pat_names[pa_3], pa_4, pat_names[pa_4], pa_5, pat_names[pa_5], pa_6, pat_names[pa_6], pa_7, pat_names[pa_7] ); size_t _bsize = strlen(buf); if (offset > _bsize) return 0; if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); return size; } static uint32_t uptime_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { char buf[1024]; sprintf(buf, "%d.%3d\n", timer_ticks, timer_subticks); size_t _bsize = strlen(buf); if (offset > _bsize) return 0; if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); return size; } static uint32_t cmdline_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { char buf[1024]; extern char * cmdline; sprintf(buf, "%s\n", cmdline ? cmdline : ""); size_t _bsize = strlen(buf); if (offset > _bsize) return 0; if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); return size; } static uint32_t version_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { char buf[1024]; char version_number[512]; sprintf(version_number, __kernel_version_format, __kernel_version_major, __kernel_version_minor, __kernel_version_lower, __kernel_version_suffix); sprintf(buf, "%s %s %s %s %s %s\n", __kernel_name, version_number, __kernel_version_codename, __kernel_build_date, __kernel_build_time, __kernel_arch); size_t _bsize = strlen(buf); if (offset > _bsize) return 0; if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); return size; } static uint32_t compiler_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { char buf[1024]; sprintf(buf, "%s\n", __kernel_compiler_version); size_t _bsize = strlen(buf); if (offset > _bsize) return 0; if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); return size; } extern tree_t * fs_tree; /* kernel/fs/vfs.c */ static void mount_recurse(char * buf, tree_node_t * node, size_t height) { /* End recursion on a blank entry */ if (!node) return; char * tmp = malloc(512); memset(tmp, 0, 512); char * c = tmp; /* Indent output */ for (uint32_t i = 0; i < height; ++i) { c += sprintf(c, " "); } /* Get the current process */ struct vfs_entry * fnode = (struct vfs_entry *)node->value; /* Print the process name */ if (fnode->file) { c += sprintf(c, "%s → %s 0x%x (%s, %s)", fnode->name, fnode->device, fnode->file, fnode->fs_type, fnode->file->name); } else { c += sprintf(c, "%s → (empty)", fnode->name); } /* Linefeed */ sprintf(buf+strlen(buf),"%s\n",tmp); free(tmp); foreach(child, node->children) { /* Recursively print the children */ mount_recurse(buf+strlen(buf),child->value, height + 1); } } static uint32_t mounts_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { char * buf = malloc(4096); buf[0] = '\0'; mount_recurse(buf, fs_tree->root, 0); size_t _bsize = strlen(buf); if (offset > _bsize) { free(buf); return 0; } if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); free(buf); return size; } static uint32_t netif_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { char * buf = malloc(4096); /* In order to not directly depend on the network module, we dynamically locate the symbols we need. */ void (*ip_ntoa)(uint32_t, char *) = (void (*)(uint32_t,char*))(uintptr_t)hashmap_get(modules_get_symbols(),"ip_ntoa"); struct netif * (*get_netif)(void) = (struct netif *(*)(void))(uintptr_t)hashmap_get(modules_get_symbols(),"get_default_network_interface"); uint32_t (*get_dns)(void) = (uint32_t (*)(void))(uintptr_t)hashmap_get(modules_get_symbols(),"get_primary_dns"); if (get_netif) { struct netif * netif = get_netif(); char ip[16]; ip_ntoa(netif->source, ip); char dns[16]; ip_ntoa(get_dns(), dns); char gw[16]; ip_ntoa(netif->gateway, gw); if (netif->hwaddr[0] == 0 && netif->hwaddr[1] == 0 && netif->hwaddr[2] == 0 && netif->hwaddr[3] == 0 && netif->hwaddr[4] == 0 && netif->hwaddr[5] == 0) { sprintf(buf, "no network\n"); } else { sprintf(buf, "ip:\t%s\n" "mac:\t%2x:%2x:%2x:%2x:%2x:%2x\n" "device:\t%s\n" "dns:\t%s\n" "gateway:\t%s\n" , ip, netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5], netif->driver, dns, gw ); } } else { sprintf(buf, "no network\n"); } size_t _bsize = strlen(buf); if (offset > _bsize) { free(buf); return 0; } if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); free(buf); return size; } static uint32_t modules_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { list_t * hash_keys = hashmap_keys(modules_get_list()); char * buf = malloc(hash_keys->length * 512); unsigned int soffset = 0; foreach(_key, hash_keys) { char * key = (char *)_key->value; module_data_t * mod_info = hashmap_get(modules_get_list(), key); soffset += sprintf(&buf[soffset], "0x%x {.init=0x%x, .fini=0x%x} %s", mod_info->bin_data, mod_info->mod_info->initialize, mod_info->mod_info->finalize, mod_info->mod_info->name); if (mod_info->deps) { unsigned int i = 0; soffset += sprintf(&buf[soffset], " Deps: "); while (i < mod_info->deps_length) { /* Skip padding bytes */ if (strlen(&mod_info->deps[i])) { soffset += sprintf(&buf[soffset], "%s ", &mod_info->deps[i]); } i += strlen(&mod_info->deps[i]) + 1; } } soffset += sprintf(&buf[soffset], "\n"); } free(hash_keys); size_t _bsize = strlen(buf); if (offset > _bsize) { free(buf); return 0; } if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); free(buf); return size; } extern hashmap_t * fs_types; /* from kernel/fs/vfs.c */ static uint32_t filesystems_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { list_t * hash_keys = hashmap_keys(fs_types); char * buf = malloc(hash_keys->length * 512); unsigned int soffset = 0; foreach(_key, hash_keys) { char * key = (char *)_key->value; soffset += sprintf(&buf[soffset], "%s\n", key); } free(hash_keys); size_t _bsize = strlen(buf); if (offset > _bsize) { free(buf); return 0; } if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); free(buf); return size; } static uint32_t loader_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { char * buf = malloc(512); if (mboot_ptr->flags & MULTIBOOT_FLAG_LOADER) { sprintf(buf, "%s\n", mboot_ptr->boot_loader_name); } else { buf[0] = '\n'; buf[1] = '\0'; } size_t _bsize = strlen(buf); if (offset > _bsize) { free(buf); return 0; } if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); free(buf); return size; } extern char * get_irq_handler(int irq, int chain); static uint32_t irq_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { char * buf = malloc(4096); unsigned int soffset = 0; for (int i = 0; i < 16; ++i) { soffset += sprintf(&buf[soffset], "irq %d: ", i); for (int j = 0; j < 4; ++j) { char * t = get_irq_handler(i, j); if (!t) break; soffset += sprintf(&buf[soffset], "%s%s", j ? "," : "", t); } soffset += sprintf(&buf[soffset], "\n"); } size_t _bsize = strlen(buf); if (offset > _bsize) { free(buf); return 0; } if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, buf + offset, size); free(buf); return size; } /** * Basically the same as the kdebug `pci` command. */ struct _pci_buf { size_t offset; char *buffer; }; static void scan_hit_list(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { struct _pci_buf * b = extra; b->offset += sprintf(b->buffer + b->offset, "%2x:%2x.%d (%4x, %4x:%4x) %s %s\n", (int)pci_extract_bus(device), (int)pci_extract_slot(device), (int)pci_extract_func(device), (int)pci_find_type(device), vendorid, deviceid, pci_vendor_lookup(vendorid), pci_device_lookup(vendorid,deviceid)); b->offset += sprintf(b->buffer + b->offset, " BAR0: 0x%8x", pci_read_field(device, PCI_BAR0, 4)); b->offset += sprintf(b->buffer + b->offset, " BAR1: 0x%8x", pci_read_field(device, PCI_BAR1, 4)); b->offset += sprintf(b->buffer + b->offset, " BAR2: 0x%8x", pci_read_field(device, PCI_BAR2, 4)); b->offset += sprintf(b->buffer + b->offset, " BAR3: 0x%8x", pci_read_field(device, PCI_BAR3, 4)); b->offset += sprintf(b->buffer + b->offset, " BAR4: 0x%8x", pci_read_field(device, PCI_BAR4, 4)); b->offset += sprintf(b->buffer + b->offset, " BAR6: 0x%8x\n", pci_read_field(device, PCI_BAR5, 4)); b->offset += sprintf(b->buffer + b->offset, " IRQ Line: %d", pci_read_field(device, 0x3C, 1)); b->offset += sprintf(b->buffer + b->offset, " IRQ Pin: %d", pci_read_field(device, 0x3D, 1)); b->offset += sprintf(b->buffer + b->offset, " Interrupt: %d", pci_get_interrupt(device)); b->offset += sprintf(b->buffer + b->offset, " Status: 0x%4x\n", pci_read_field(device, PCI_STATUS, 2)); } static void scan_count(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { size_t * count = extra; (*count)++; } static uint32_t pci_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { size_t count = 0; pci_scan(&scan_count, -1, &count); struct _pci_buf b = {0,NULL}; b.buffer = malloc(count * 1024); pci_scan(&scan_hit_list, -1, &b); size_t _bsize = b.offset; if (offset > _bsize) { free(b.buffer); return 0; } if (size > _bsize - offset) size = _bsize - offset; memcpy(buffer, b.buffer + offset, size); free(b.buffer); return size; } static struct procfs_entry std_entries[] = { {-1, "cpuinfo", cpuinfo_func}, {-2, "meminfo", meminfo_func}, {-3, "uptime", uptime_func}, {-4, "cmdline", cmdline_func}, {-5, "version", version_func}, {-6, "compiler", compiler_func}, {-7, "mounts", mounts_func}, {-8, "netif", netif_func}, {-9, "modules", modules_func}, {-10,"filesystems", filesystems_func}, {-11,"loader", loader_func}, {-12,"irq", irq_func}, {-13,"pat", pat_func}, {-14,"pci", pci_func}, }; static struct dirent * readdir_procfs_root(fs_node_t *node, uint32_t index) { if (index == 0) { struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); out->ino = 0; strcpy(out->name, "."); return out; } if (index == 1) { struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); out->ino = 0; strcpy(out->name, ".."); return out; } if (index == 2) { struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); out->ino = 0; strcpy(out->name, "self"); return out; } index -= 3; if (index < PROCFS_STANDARD_ENTRIES) { struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); out->ino = std_entries[index].id; strcpy(out->name, std_entries[index].name); return out; } int i = index - PROCFS_STANDARD_ENTRIES + 1; debug_print(WARNING, "%d %d %d", i, index, PROCFS_STANDARD_ENTRIES); pid_t pid = 0; foreach(lnode, process_list) { i--; if (i == 0) { process_t * proc = (process_t *)lnode->value; pid = proc->id; break; } } if (pid == 0) { return NULL; } struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); out->ino = pid; sprintf(out->name, "%d", pid); return out; } static fs_node_t * finddir_procfs_root(fs_node_t * node, char * name) { if (!name) return NULL; if (strlen(name) < 1) return NULL; if (name[0] >= '0' && name[0] <= '9') { /* XXX process entries */ pid_t pid = atoi(name); process_t * proc = process_from_pid(pid); if (!proc) { return NULL; } fs_node_t * out = procfs_procdir_create(proc); return out; } if (!strcmp(name,"self")) { return procfs_procdir_create((process_t *)current_process); } for (unsigned int i = 0; i < PROCFS_STANDARD_ENTRIES; ++i) { if (!strcmp(name, std_entries[i].name)) { fs_node_t * out = procfs_generic_create(std_entries[i].name, std_entries[i].func); return out; } } return NULL; } static fs_node_t * procfs_create(void) { fs_node_t * fnode = malloc(sizeof(fs_node_t)); memset(fnode, 0x00, sizeof(fs_node_t)); fnode->inode = 0; strcpy(fnode->name, "proc"); fnode->mask = 0555; fnode->uid = 0; fnode->gid = 0; fnode->flags = FS_DIRECTORY; fnode->read = NULL; fnode->write = NULL; fnode->open = NULL; fnode->close = NULL; fnode->readdir = readdir_procfs_root; fnode->finddir = finddir_procfs_root; fnode->nlink = 1; fnode->ctime = now(); fnode->mtime = now(); fnode->atime = now(); return fnode; } int procfs_initialize(void) { /* TODO Move this to some sort of config */ vfs_mount("/proc", procfs_create()); debug_print_vfs_tree(); return 0; } int procfs_finalize(void) { return 0; } MODULE_DEF(procfs, procfs_initialize, procfs_finalize);