1 /* PFS - Pipe File Server */ 2 3 #include <minix/drivers.h> 4 #include <minix/fsdriver.h> 5 #include <minix/vfsif.h> 6 #include <assert.h> 7 8 /* 9 * The following constant defines the number of inodes in PFS, which is 10 * therefore the maximum number of open pipes and cloned devices that can be 11 * used in the entire system. If anything, it should be kept somewhat in sync 12 * with VFS's maximum number of inodes. In the future, inodes could be 13 * allocated dynamically, but this will require extra infrastructure. 14 */ 15 #define PFS_NR_INODES 512 /* maximum number of inodes in PFS */ 16 17 /* The following bits can be combined in the inode's i_update field. */ 18 #define ATIME 0x1 /* update access time later */ 19 #define MTIME 0x2 /* update modification time later */ 20 #define CTIME 0x4 /* update change time later */ 21 22 static struct inode { 23 ino_t i_num; /* inode number */ 24 25 mode_t i_mode; /* file mode and permissions */ 26 uid_t i_uid; /* user ID of the file's owner */ 27 gid_t i_gid; /* group ID of the file's owner */ 28 size_t i_size; /* current file size in bytes */ 29 dev_t i_rdev; /* device number for device nodes */ 30 time_t i_atime; /* file access time */ 31 time_t i_mtime; /* file modification time */ 32 time_t i_ctime; /* file change time */ 33 34 char *i_data; /* data buffer, for pipes only */ 35 size_t i_start; /* start of data into data buffer */ 36 37 unsigned char i_update; /* which file times to update? */ 38 unsigned char i_free; /* sanity check: is the inode free? */ 39 40 LIST_ENTRY(inode) i_next; /* next element in free list */ 41 } inode[PFS_NR_INODES]; 42 43 static LIST_HEAD(, inode) free_inodes; /* list of free inodes */ 44 45 /* 46 * Mount the pipe file server. 47 */ 48 static int 49 pfs_mount(dev_t __unused dev, unsigned int __unused flags, 50 struct fsdriver_node * node, unsigned int * res_flags) 51 { 52 struct inode *rip; 53 unsigned int i; 54 55 LIST_INIT(&free_inodes); /* initialize the free list */ 56 57 /* 58 * Initialize the inode table. We walk backwards so that the lowest 59 * inode numbers end up being used first. Silly? Sure, but aesthetics 60 * are worth something, too.. 61 */ 62 for (i = PFS_NR_INODES; i > 0; i--) { 63 rip = &inode[i - 1]; 64 65 /* Inode number 0 is reserved. See also pfs_findnode. */ 66 rip->i_num = i; 67 rip->i_free = TRUE; 68 69 LIST_INSERT_HEAD(&free_inodes, rip, i_next); 70 } 71 72 /* 73 * PFS has no root node, and VFS will ignore the returned node details 74 * anyway. The whole idea is to provide symmetry with other file 75 * systems, thus keeping libfsdriver simple and free of special cases. 76 */ 77 memset(node, 0, sizeof(*node)); 78 *res_flags = RES_64BIT; 79 80 return OK; 81 } 82 83 /* 84 * Unmount the pipe file server. 85 */ 86 static void 87 pfs_unmount(void) 88 { 89 unsigned int i; 90 91 /* Warn about in-use inodes. There's nothing else we can do. */ 92 for (i = 0; i < PFS_NR_INODES; i++) 93 if (inode[i].i_free == FALSE) 94 break; 95 96 if (i < PFS_NR_INODES) 97 printf("PFS: unmounting while busy!\n"); 98 } 99 100 /* 101 * Find the node with the corresponding inode number. It must be in use. 102 */ 103 static struct inode * 104 pfs_findnode(ino_t ino_nr) 105 { 106 struct inode *rip; 107 108 /* Inode numbers are 1-based, because inode number 0 is reserved. */ 109 if (ino_nr < 1 || ino_nr > PFS_NR_INODES) 110 return NULL; 111 112 rip = &inode[ino_nr - 1]; 113 assert(rip->i_num == ino_nr); 114 115 if (rip->i_free == TRUE) 116 return NULL; 117 118 return rip; 119 } 120 121 /* 122 * Create a new, unlinked node. It must be either a pipe or a device file. 123 */ 124 static int 125 pfs_newnode(mode_t mode, uid_t uid, gid_t gid, dev_t dev, 126 struct fsdriver_node * node) 127 { 128 struct inode *rip; 129 char *data; 130 int isfifo, isdev; 131 132 /* Check the file type. Do we support it at all? */ 133 isfifo = S_ISFIFO(mode); 134 isdev = S_ISBLK(mode) || S_ISCHR(mode); 135 136 if (!isfifo && !isdev) 137 return EINVAL; /* this means VFS is misbehaving.. */ 138 139 /* Is there a free inode? */ 140 if (LIST_EMPTY(&free_inodes)) 141 return ENFILE; 142 143 /* For pipes, we need a buffer. Try to allocate one. */ 144 data = NULL; 145 if (isfifo && (data = malloc(PIPE_BUF)) == NULL) 146 return ENOSPC; 147 148 /* Nothing can go wrong now. Take an inode off the free list. */ 149 rip = LIST_FIRST(&free_inodes); 150 LIST_REMOVE(rip, i_next); 151 152 assert(rip->i_free == TRUE); 153 rip->i_free = FALSE; /* this is for sanity checks only */ 154 155 /* Initialize the inode's fields. */ 156 rip->i_mode = mode; 157 rip->i_uid = uid; 158 rip->i_gid = gid; 159 rip->i_size = 0; 160 rip->i_update = ATIME | MTIME | CTIME; 161 if (isdev) 162 rip->i_rdev = dev; 163 else 164 rip->i_rdev = NO_DEV; 165 rip->i_data = data; 166 rip->i_start = 0; 167 168 /* Fill in the fields of the response message. */ 169 node->fn_ino_nr = rip->i_num; 170 node->fn_mode = rip->i_mode; 171 node->fn_size = rip->i_size; 172 node->fn_uid = rip->i_uid; 173 node->fn_gid = rip->i_gid; 174 node->fn_dev = rip->i_rdev; 175 176 return OK; 177 } 178 179 /* 180 * Close a node. 181 */ 182 static int 183 pfs_putnode(ino_t ino_nr, unsigned int count) 184 { 185 struct inode *rip; 186 187 if ((rip = pfs_findnode(ino_nr)) == NULL) 188 return EINVAL; 189 190 /* 191 * Since the new-node call is the only way to open an inode, and there 192 * is no way to increase the use count of an already-opened inode, we 193 * can safely assume that the reference count will only ever be one. 194 * That also means we are always freeing up the target inode here. 195 */ 196 if (count != 1) 197 return EINVAL; 198 199 /* For pipes, free the inode data buffer. */ 200 if (rip->i_data != NULL) 201 free(rip->i_data); 202 203 /* Return the inode to the free list. */ 204 rip->i_free = TRUE; 205 206 LIST_INSERT_HEAD(&free_inodes, rip, i_next); 207 208 return OK; 209 } 210 211 /* 212 * Read from a pipe. 213 */ 214 static ssize_t 215 pfs_read(ino_t ino_nr, struct fsdriver_data * data, size_t bytes, 216 off_t __unused pos, int __unused call) 217 { 218 struct inode *rip; 219 int r; 220 221 /* The target node must be a pipe. */ 222 if ((rip = pfs_findnode(ino_nr)) == NULL || !S_ISFIFO(rip->i_mode)) 223 return EINVAL; 224 225 /* We can't read beyond the maximum file position. */ 226 if (bytes > PIPE_BUF) 227 return EFBIG; 228 229 /* Limit the request to how much is in the pipe. */ 230 if (bytes > rip->i_size) 231 bytes = rip->i_size; 232 233 /* Copy the data to user space. */ 234 if ((r = fsdriver_copyout(data, 0, rip->i_data + rip->i_start, 235 bytes)) != OK) 236 return r; 237 238 /* Update file size and access time. */ 239 rip->i_size -= bytes; 240 rip->i_start += bytes; 241 rip->i_update |= ATIME; 242 243 /* Return the number of bytes transferred. */ 244 return bytes; 245 } 246 247 /* 248 * Write to a pipe. 249 */ 250 static ssize_t 251 pfs_write(ino_t ino_nr, struct fsdriver_data * data, size_t bytes, 252 off_t __unused pos, int __unused call) 253 { 254 struct inode *rip; 255 int r; 256 257 /* The target node must be a pipe. */ 258 if ((rip = pfs_findnode(ino_nr)) == NULL || !S_ISFIFO(rip->i_mode)) 259 return EINVAL; 260 261 /* Check in advance to see if file will grow too big. */ 262 if (rip->i_size + bytes > PIPE_BUF) 263 return EFBIG; 264 265 /* 266 * Move any previously remaining data to the front of the buffer. 267 * Doing so upon writes rather than reads saves on memory moves when 268 * there are many small reads. Not using the buffer circularly saves 269 * on kernel calls. 270 */ 271 if (rip->i_start > 0) { 272 if (rip->i_size > 0) 273 memmove(rip->i_data, rip->i_data + rip->i_start, 274 rip->i_size); 275 276 rip->i_start = 0; 277 } 278 279 /* Copy the data from user space. */ 280 r = fsdriver_copyin(data, 0, rip->i_data + rip->i_size, bytes); 281 if (r != OK) 282 return r; 283 284 /* Update file size and times. */ 285 rip->i_size += bytes; 286 rip->i_update |= CTIME | MTIME; 287 288 /* Return the number of bytes transferred. */ 289 return bytes; 290 } 291 292 /* 293 * Truncate a pipe. 294 */ 295 static int 296 pfs_trunc(ino_t ino_nr, off_t start_pos, off_t end_pos) 297 { 298 struct inode *rip; 299 300 /* The target node must be a pipe. */ 301 if ((rip = pfs_findnode(ino_nr)) == NULL || !S_ISFIFO(rip->i_mode)) 302 return EINVAL; 303 304 /* We only support full truncation of pipes. */ 305 if (start_pos != 0 || end_pos != 0) 306 return EINVAL; 307 308 /* Update file size and times. */ 309 rip->i_size = 0; 310 rip->i_update |= CTIME | MTIME; 311 312 return OK; 313 } 314 315 /* 316 * Return node status. 317 */ 318 static int 319 pfs_stat(ino_t ino_nr, struct stat * statbuf) 320 { 321 struct inode *rip; 322 time_t now; 323 324 if ((rip = pfs_findnode(ino_nr)) == NULL) 325 return EINVAL; 326 327 /* Update the time fields in the inode, if need be. */ 328 if (rip->i_update != 0) { 329 now = clock_time(NULL); 330 331 if (rip->i_update & ATIME) rip->i_atime = now; 332 if (rip->i_update & MTIME) rip->i_mtime = now; 333 if (rip->i_update & CTIME) rip->i_ctime = now; 334 335 rip->i_update = 0; 336 } 337 338 /* Fill the stat buffer. */ 339 statbuf->st_dev = rip->i_rdev; /* workaround for old socketpair bug */ 340 statbuf->st_ino = rip->i_num; 341 statbuf->st_mode = rip->i_mode; 342 statbuf->st_nlink = 0; 343 statbuf->st_uid = rip->i_uid; 344 statbuf->st_gid = rip->i_gid; 345 statbuf->st_rdev = rip->i_rdev; 346 statbuf->st_size = rip->i_size; 347 statbuf->st_atime = rip->i_atime; 348 statbuf->st_mtime = rip->i_mtime; 349 statbuf->st_ctime = rip->i_ctime; 350 statbuf->st_blksize = PIPE_BUF; 351 statbuf->st_blocks = howmany(rip->i_size, S_BLKSIZE); 352 353 return OK; 354 } 355 356 /* 357 * Change node permissions. 358 */ 359 static int 360 pfs_chmod(ino_t ino_nr, mode_t * mode) 361 { 362 struct inode *rip; 363 364 if ((rip = pfs_findnode(ino_nr)) == NULL) 365 return EINVAL; 366 367 /* Update file mode and times. */ 368 rip->i_mode = (rip->i_mode & ~ALLPERMS) | (*mode & ALLPERMS); 369 rip->i_update |= MTIME | CTIME; 370 371 *mode = rip->i_mode; 372 return OK; 373 } 374 375 /* 376 * Process a signal. 377 */ 378 static void 379 pfs_signal(int signo) 380 { 381 382 /* Only check for termination signal, ignore anything else. */ 383 if (signo != SIGTERM) return; 384 385 fsdriver_terminate(); 386 } 387 388 /* 389 * Perform SEF initialization. 390 */ 391 static void 392 pfs_startup(void) 393 { 394 395 /* Register initialization callbacks. */ 396 sef_setcb_init_fresh(sef_cb_init_null); 397 sef_setcb_init_restart(sef_cb_init_fail); 398 399 /* No live update support for now. */ 400 401 /* Register signal callbacks. */ 402 sef_setcb_signal_handler(pfs_signal); 403 404 /* Let SEF perform startup. */ 405 sef_startup(); 406 } 407 408 /* 409 * Function call table for the fsdriver library. 410 */ 411 static struct fsdriver pfs_table = { 412 .fdr_mount = pfs_mount, 413 .fdr_unmount = pfs_unmount, 414 .fdr_newnode = pfs_newnode, 415 .fdr_putnode = pfs_putnode, 416 .fdr_read = pfs_read, 417 .fdr_write = pfs_write, 418 .fdr_trunc = pfs_trunc, 419 .fdr_stat = pfs_stat, 420 .fdr_chmod = pfs_chmod 421 }; 422 423 /* 424 * The main routine of this service. 425 */ 426 int 427 main(void) 428 { 429 430 /* Local startup. */ 431 pfs_startup(); 432 433 /* The fsdriver library does the actual work here. */ 434 fsdriver_task(&pfs_table); 435 436 return EXIT_SUCCESS; 437 } 438