Welcome to The Fiwix Project
A UNIX-like kernel for the i386 architecture
1 /* 2 * fiwix/fs/procfs/dir.c 3 * 4 * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved. 5 * Distributed under the terms of the Fiwix License. 6 */ 7 8 #include <fiwix/types.h> 9 #include <fiwix/errno.h> 10 #include <fiwix/fs.h> 11 #include <fiwix/filesystems.h> 12 #include <fiwix/fs_proc.h> 13 #include <fiwix/dirent.h> 14 #include <fiwix/stat.h> 15 #include <fiwix/mm.h> 16 #include <fiwix/stdio.h> 17 #include <fiwix/string.h> 18 19 struct fs_operations procfs_dir_fsop = { 20 0, 21 0, 22 23 procfs_dir_open, 24 procfs_dir_close, 25 procfs_dir_read, 26 NULL, /* write */ 27 NULL, /* ioctl */ 28 NULL, /* lseek */ 29 procfs_dir_readdir, 30 NULL, /* mmap */ 31 NULL, /* select */ 32 33 NULL, /* readlink */ 34 NULL, /* followlink */ 35 procfs_bmap, 36 procfs_lookup, 37 NULL, /* rmdir */ 38 NULL, /* link */ 39 NULL, /* unlink */ 40 NULL, /* symlink */ 41 NULL, /* mkdir */ 42 NULL, /* mknod */ 43 NULL, /* truncate */ 44 NULL, /* create */ 45 NULL, /* rename */ 46 47 NULL, /* read_block */ 48 NULL, /* write_block */ 49 50 NULL, /* read_inode */ 51 NULL, /* write_inode */ 52 NULL, /* ialloc */ 53 NULL, /* ifree */ 54 NULL, /* statfs */ 55 NULL, /* read_superblock */ 56 NULL, /* remount_fs */ 57 NULL, /* write_superblock */ 58 NULL /* release_superblock */ 59 }; 60 61 static int proc_listdir(char *buffer, int count) 62 { 63 int n; 64 struct proc *p; 65 struct procfs_dir_entry *pd; 66 struct procfs_dir_entry d; 67 int size; 68 69 size = 0; 70 pd = (struct procfs_dir_entry *)buffer; 71 72 FOR_EACH_PROCESS(p) { 73 d.inode = PROC_PID_INO + (p->pid << 12); 74 d.mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; 75 d.nlink = 1; 76 d.lev = -1; 77 d.name_len = 1; 78 n = p->pid; 79 while(n / 10) { 80 n /= 10; 81 d.name_len++; 82 } 83 d.name = p->pidstr; 84 d.data_fn = NULL; 85 86 if(size + sizeof(struct procfs_dir_entry) > (count - 1)) { 87 printk("WARNING: kmalloc() is limited to 4096 bytes.\n"); 88 break; 89 } 90 91 size += sizeof(struct procfs_dir_entry); 92 memcpy_b((void *)pd, (void *)&d, sizeof(struct procfs_dir_entry)); 93 pd++; 94 p = p->next; 95 } 96 return size; 97 } 98 99 /* 100 static int proc_listfd(struct inode *i, char *buffer, int count) 101 { 102 int n; 103 struct proc *p; 104 struct procfs_dir_entry *pd; 105 struct procfs_dir_entry d; 106 int size; 107 108 size = 0; 109 pd = (struct procfs_dir_entry *)buffer; 110 111 p = get_proc_by_pid((i->inode >> 12) & 0xFFFF); 112 for(n = 0; n < OPEN_MAX; n++) { 113 if(p->fd[n]) { 114 d.inode = PROC_PID_INO + (p->pid << 12) + n; 115 d.mode = S_IFREG | S_IRWXU; 116 d.nlink = 1; 117 d.lev = -1; 118 d.name_len = sprintk(d.name, "%d", n); 119 d.data_fn = NULL; 120 121 if(size + sizeof(struct procfs_dir_entry) > (count - 1)) { 122 printk("WARNING: kmalloc() is limited to 4096 bytes.\n"); 123 break; 124 } 125 126 size += sizeof(struct procfs_dir_entry); 127 memcpy_b((void *)pd, (void *)&d, sizeof(struct procfs_dir_entry)); 128 pd++; 129 } 130 } 131 memset_b((void *)pd + size, NULL, sizeof(struct procfs_dir_entry)); 132 return size; 133 } 134 */ 135 136 static int dir_read(struct inode *i, struct fd *fd_table, char *buffer, __size_t count) 137 { 138 __off_t total_read; 139 unsigned int bytes; 140 int len, lev; 141 char *buf; 142 143 if(!(buf = (void *)kmalloc())) { 144 return -ENOMEM; 145 } 146 147 /* create the list of directories for each process */ 148 len = 0; 149 if(i->inode == PROC_ROOT_INO) { 150 len = proc_listdir(buf, count); 151 } 152 153 /* TODO: create the list of fds used for each process 154 if((i->inode & 0xF0000FFF) == PROC_PID_FD) { 155 len = proc_listfd(i, buf, count); 156 } 157 */ 158 159 /* add the rest of static files in the main directory */ 160 lev = i->u.procfs.i_lev; 161 162 /* assigns the size of the level without the last entry (NULL) */ 163 bytes = sizeof(procfs_array[lev]) - sizeof(struct procfs_dir_entry); 164 165 if((len + bytes) > (count - 1)) { 166 printk("WARNING: %s(): len (%d) > count (%d).\n", __FUNCTION__, len, count); 167 kfree((unsigned int)buf); 168 return 0; 169 } 170 memcpy_b(buf + len, (char *)&procfs_array[lev], bytes); 171 len += bytes; 172 total_read = fd_table->offset = len; 173 memcpy_b(buffer, buf, len); 174 kfree((unsigned int)buf); 175 return total_read; 176 } 177 178 int procfs_dir_open(struct inode *i, struct fd *fd_table) 179 { 180 fd_table->offset = 0; 181 return 0; 182 } 183 184 int procfs_dir_close(struct inode *i, struct fd *fd_table) 185 { 186 return 0; 187 } 188 189 int procfs_dir_read(struct inode *i, struct fd *fd_table, char *buffer, __size_t count) 190 { 191 return -EISDIR; 192 } 193 194 int procfs_dir_readdir(struct inode *i, struct fd *fd_table, struct dirent *dirent, unsigned int count) 195 { 196 unsigned int offset, boffset, dirent_offset, doffset; 197 int dirent_len; 198 unsigned int total_read; 199 struct procfs_dir_entry *d; 200 int base_dirent_len; 201 char *buffer; 202 int lev; 203 204 if(!(buffer = (void *)kmalloc())) { 205 return -ENOMEM; 206 } 207 208 lev = i->u.procfs.i_lev; 209 base_dirent_len = sizeof(dirent->d_ino) + sizeof(dirent->d_off) + sizeof(dirent->d_reclen); 210 211 offset = fd_table->offset; 212 boffset = dirent_offset = doffset = 0; 213 214 boffset = offset % PAGE_SIZE; 215 216 total_read = dir_read(i, fd_table, buffer, PAGE_SIZE); 217 if((count = MIN(total_read, count)) == 0) { 218 kfree((unsigned int)buffer); 219 return dirent_offset; 220 } 221 222 while(boffset < fd_table->offset) { 223 d = (struct procfs_dir_entry *)(buffer + boffset); 224 if(!d->inode) { 225 break; 226 } 227 dirent_len = (base_dirent_len + (d->name_len + 1)) + 3; 228 dirent_len &= ~3; /* round up */ 229 if((doffset + dirent_len) <= count) { 230 boffset += sizeof(struct procfs_dir_entry); 231 offset += sizeof(struct procfs_dir_entry); 232 doffset += dirent_len; 233 dirent->d_ino = d->inode; 234 dirent->d_off = offset; 235 dirent->d_reclen = dirent_len; 236 memcpy_b(dirent->d_name, d->name, d->name_len); 237 dirent->d_name[d->name_len] = NULL; 238 dirent = (struct dirent *)((char *)dirent + dirent_len); 239 dirent_offset += dirent_len; 240 } else { 241 break; 242 } 243 } 244 fd_table->offset = boffset; 245 kfree((unsigned int)buffer); 246 return dirent_offset; 247 }