vfs.c (14462B)
1 /* Copyright 1998-1999, Sidney Cammeresi. All rights reserved. 2 ** Distributed under the terms of the OpenBLT License 3 */ 4 5 #include <stdio.h> 6 #include <string.h> 7 #include <stdlib.h> 8 #include <unistd.h> 9 #include <errno.h> 10 #include <boot.h> 11 #include <dlfcn.h> 12 #include <sys/stat.h> 13 #include <blt/syscall.h> 14 #include <blt/namer.h> 15 #include <blt/error.h> 16 #include <blt/hash.h> 17 #include <blt/libsyms.h> 18 #include <blt/vfs.h> 19 #include "vfs-int.h" 20 #include "path.h" 21 #include "shm.h" 22 23 #define FG_GREEN "\033[32m" 24 #define FG_RED "\033[34m" 25 #define FG_WHITE "\033[37m" 26 27 int vfs_port; 28 struct fs_type *fs_drivers; 29 struct superblock *mount_list = NULL; 30 hashtable_t *conn_table; 31 32 void __libc_init_vfs (void), __dlinit (void); 33 34 extern struct fs_type rootfs, bootfs; 35 extern void __libc_init_console (); 36 extern int __blk_ref; 37 38 vfs_res_t *vfs_openconn (int rport, int area) 39 { 40 int i, private_port; 41 vfs_res_t *res; 42 struct client *client; 43 44 res = malloc (sizeof (vfs_res_t)); 45 res->status = VFS_OK; 46 res->errno = 0; 47 private_port = port_create (rport, "vfs_private_port"); 48 port_slave (vfs_port, private_port); 49 res->data[0] = private_port; 50 51 client = malloc (sizeof (struct client)); 52 client->in = rport; 53 client->out = private_port; 54 client->filename_area = area; 55 area_clone (area, 0, (void **) &client->nameptr, 0); 56 client->ioctx.cwd = malloc (BLT_MAX_NAME_LENGTH); 57 strcpy (client->ioctx.cwd, "/"); 58 for (i = 0; i < MAX_FDS; i++) 59 client->ioctx.fdarray.ofile[i] = NULL; 60 hashtable_insert (conn_table, client->in, client, sizeof (struct client)); 61 62 #ifdef VFS_DEBUG 63 printf ("vfs_openconn: from port %d, assigned port %d, area %d " 64 "mapped to %p\n", rport, private_port, area, client->nameptr); 65 #endif 66 return res; 67 } 68 69 vfs_res_t *vfs_scroll_area (struct client *client, vfs_cmd_t *vc) 70 { 71 struct ofile *ofile; 72 vfs_res_t *res; 73 74 res = malloc (sizeof (vfs_res_t)); 75 ofile = client->ioctx.fdarray.ofile[vc->data[0]]; 76 shm_write (ofile, vc->data[1], 0, ofile->length, &res->data[0], 77 &res->data[1]); 78 res->status = VFS_OK; 79 res->errno = 0; 80 return res; 81 } 82 83 int vfs_mkdir (const char *dir, mode_t mode) 84 { 85 const char *s; 86 int res; 87 struct superblock *super; 88 struct vnode *vnode; 89 90 #ifdef VFS_DEBUG 91 printf ("vfs_mkdir %s %d\n", dir, mode); 92 #endif 93 94 /* find superblock and check if mkdir supported */ 95 super = fs_find (dir); 96 if (super->sb_vops->mkdir == NULL) 97 return ENOSYS; 98 99 /* XXX dispatch to root vnode for now */ 100 vnode = super->sb_root; 101 s = dir + strlen (super->sb_dir); 102 res = super->sb_vops->mkdir (vnode, s, mode); 103 return res; 104 } 105 106 vfs_res_t *vfs_opendir (struct client *client, vfs_cmd_t *vc) 107 { 108 char *reldir, *dir; 109 int i; 110 vfs_res_t *res; 111 struct ofile *ofile; 112 struct superblock *super; 113 struct vnode *vnode; 114 115 reldir = client->nameptr + vc->data[0]; 116 res = malloc (sizeof (vfs_res_t)); 117 #ifdef VFS_DEBUG 118 printf ("vfs_opendir %s\n", reldir); 119 #endif 120 121 /* get a file descriptor */ 122 for (i = 0; i < MAX_FDS; i++) 123 if (client->ioctx.fdarray.ofile[i] == NULL) 124 break; 125 if (i == MAX_FDS) 126 { 127 res->status = VFS_ERROR; 128 res->errno = EMFILE; 129 return res; 130 } 131 132 /* is opendir supported? */ 133 dir = malloc (BLT_MAX_NAME_LENGTH); 134 strlcpy (dir, client->ioctx.cwd, BLT_MAX_NAME_LENGTH); 135 path_combine (client->ioctx.cwd, reldir, dir); 136 super = fs_find (dir); 137 if (super == NULL) 138 { 139 res->status = VFS_ERROR; 140 res->errno = ENOENT; 141 free (dir); 142 return res; 143 } 144 if (super->sb_vops->opendir == NULL) 145 { 146 res->status = VFS_ERROR; 147 res->errno = ENOSYS; 148 free (dir); 149 return res; 150 } 151 152 /* find directory's vnode */ 153 if (!strcmp (dir, super->sb_dir)) 154 vnode = super->sb_root; 155 else 156 vnode = super->sb_vops->walk (super->sb_root, dir + 157 strlen (super->sb_dir) + 1); 158 if (vnode == NULL) 159 { 160 res->status = VFS_ERROR; 161 res->errno = ENOENT; 162 free (dir); 163 return res; 164 } 165 166 /* stat here to check for directory */ 167 168 /* call filesystem's opendir and read the directory */ 169 ofile = client->ioctx.fdarray.ofile[i] = malloc (sizeof (struct ofile)); 170 ofile->o_vnode = vnode; 171 ofile->area = area_clone (vc->data[1], 0, &ofile->dataptr, 0); 172 ofile->offset = vc->data[2]; 173 ofile->length = vc->data[3]; 174 res->errno = super->sb_vops->opendir (vnode, &ofile->o_cookie); 175 res->status = res->errno ? VFS_ERROR : VFS_OK; 176 res->data[0] = i; 177 free (dir); 178 return res; 179 } 180 181 vfs_res_t *vfs_closedir (struct client *client, vfs_cmd_t *vc) 182 { 183 vfs_res_t *res; 184 struct ofile *ofile; 185 struct vnode *vnode; 186 187 #ifdef VFS_DEBUG 188 printf ("vfs_closedir %d\n", vc->data[0]); 189 #endif 190 res = malloc (sizeof (vfs_res_t)); 191 192 /* is file descriptor valid? */ 193 if ((ofile = client->ioctx.fdarray.ofile[vc->data[0]]) == NULL) 194 { 195 res->errno = EBADF; 196 res->status = VFS_ERROR; 197 return res; 198 } 199 200 /* is closedir supported? */ 201 vnode = ofile->o_vnode; 202 if (vnode->v_sb->sb_vops->closedir == NULL) 203 { 204 res->errno = ENOSYS; 205 res->status = VFS_ERROR; 206 return res; 207 } 208 209 /* call filesystem */ 210 vnode->v_sb->sb_vops->closedir (vnode, ofile->o_cookie); 211 if (!res->errno && (vnode->v_sb->sb_vops->free_dircookie != NULL)) 212 vnode->v_sb->sb_vops->free_dircookie (ofile->o_cookie); 213 free (ofile); 214 client->ioctx.fdarray.ofile[vc->data[0]] = NULL; 215 216 res->status = VFS_OK; 217 res->errno = 0; 218 return res; 219 } 220 221 vfs_res_t *vfs_open (struct client *client, vfs_cmd_t *vc) 222 { 223 int i; 224 char *path; 225 vfs_res_t *res; 226 struct ofile *ofile; 227 struct superblock *super; 228 struct vnode *vnode; 229 230 res = malloc (sizeof (vfs_res_t)); 231 path = client->nameptr + vc->data[0]; 232 #ifdef VFS_DEBUG 233 printf ("vfs_open %s\n", path); 234 #endif 235 236 /* get a file descriptor */ 237 for (i = 0; i < MAX_FDS; i++) 238 if (client->ioctx.fdarray.ofile[i] == NULL) 239 break; 240 if (i == MAX_FDS) 241 { 242 res->status = VFS_ERROR; 243 res->errno = EMFILE; 244 return res; 245 } 246 247 /* is open supported? */ 248 super = fs_find (path); 249 if (super == NULL) 250 { 251 res->status = VFS_ERROR; 252 res->errno = ENOENT; 253 return res; 254 } 255 if (super->sb_vops->open == NULL) 256 { 257 res->status = VFS_ERROR; 258 res->errno = ENOSYS; 259 return res; 260 } 261 262 /* find file's vnode */ 263 vnode = super->sb_vops->walk (super->sb_root, path + 264 strlen (super->sb_dir) + 1); 265 if (vnode == NULL) 266 { 267 res->status = VFS_ERROR; 268 res->errno = ENOENT; 269 return res; 270 } 271 272 /* call filesystem */ 273 ofile = client->ioctx.fdarray.ofile[i] = malloc (sizeof (struct ofile)); 274 ofile->o_vnode = vnode; 275 ofile->o_pos = 0; 276 ofile->area = area_clone (vc->data[1], 0, &ofile->dataptr, 0); 277 ofile->offset = vc->data[2]; 278 ofile->length = vc->data[3]; 279 res->errno = super->sb_vops->open (vnode, &ofile->o_cookie); 280 res->status = res->errno ? VFS_ERROR : VFS_OK; 281 res->data[0] = i; 282 return res; 283 } 284 285 vfs_res_t *vfs_close (struct client *client, vfs_cmd_t *vc) 286 { 287 vfs_res_t *res; 288 struct ofile *ofile; 289 struct superblock *super; 290 291 res = malloc (sizeof (vfs_res_t)); 292 #ifdef VFS_DEBUG 293 printf ("vfs_close\n"); 294 #endif 295 296 ofile = client->ioctx.fdarray.ofile[vc->data[0]]; 297 if (ofile == NULL) 298 { 299 res->status = VFS_ERROR; 300 res->errno = EBADF; 301 return res; 302 } 303 super = ofile->o_vnode->v_sb; 304 if (super->sb_vops->close == NULL) 305 { 306 res->status = VFS_ERROR; 307 res->errno = ENOSYS; 308 return res; 309 } 310 res->errno = super->sb_vops->close (ofile->o_vnode, 311 ofile->o_cookie); 312 313 if (super->sb_vops->free_cookie != NULL) 314 super->sb_vops->free_cookie (ofile->o_cookie); 315 316 res->status = res->errno ? VFS_ERROR : VFS_OK; 317 return res; 318 } 319 320 vfs_res_t *vfs_read (struct client *client, vfs_cmd_t *vc, void **data, 321 int *len) 322 { 323 size_t numread; 324 void *buf; 325 vfs_res_t *res; 326 struct ofile *ofile; 327 struct superblock *super; 328 329 #ifdef VFS_DEBUG 330 printf ("vfs_read\n"); 331 #endif 332 res = malloc (sizeof (vfs_res_t)); 333 buf = malloc (vc->data[1]); 334 335 ofile = client->ioctx.fdarray.ofile[vc->data[0]]; 336 if (ofile == NULL) 337 { 338 res->status = VFS_ERROR; 339 res->errno = EBADF; 340 return res; 341 } 342 super = ofile->o_vnode->v_sb; 343 if (super->sb_vops->read == NULL) 344 { 345 res->status = VFS_ERROR; 346 res->errno = ENOSYS; 347 return res; 348 } 349 350 res->errno = super->sb_vops->read (ofile->o_vnode, buf, vc->data[1], 351 ofile->o_pos, &numread, ofile->o_cookie); 352 res->status = res->errno ? VFS_ERROR : VFS_OK; 353 res->data[0] = numread; 354 ofile->o_pos += *len = numread; 355 *data = buf; 356 return res; 357 } 358 359 vfs_res_t *vfs_rstat (struct client *client, vfs_cmd_t *vc) 360 { 361 char *path; 362 vfs_res_t *res; 363 struct superblock *super; 364 struct vnode *vnode; 365 struct stat *buf; 366 367 #ifdef VFS_DEBUG 368 printf ("vfs_rstat\n"); 369 #endif 370 res = malloc (sizeof (vfs_res_t) + sizeof (struct stat)); 371 buf = (void *) res + sizeof (vfs_res_t); 372 path = client->nameptr + vc->data[0]; 373 374 /* is stat supported? */ 375 super = fs_find (path); 376 if (super == NULL) 377 { 378 res->status = VFS_ERROR; 379 res->errno = ENOENT; 380 return res; 381 } 382 if (super->sb_vops->rstat == NULL) 383 { 384 res->status = VFS_ERROR; 385 res->errno = ENOSYS; 386 return res; 387 } 388 389 /* find file's vnode */ 390 vnode = super->sb_vops->walk (super->sb_root, path + 391 strlen (super->sb_dir) + 1); 392 if (vnode == NULL) 393 { 394 res->status = VFS_ERROR; 395 res->errno = ENOENT; 396 return res; 397 } 398 399 /* call filesystem */ 400 res->errno = super->sb_vops->rstat (vnode, buf); 401 res->status = res->errno ? VFS_ERROR : VFS_OK; 402 return res; 403 } 404 405 void vfs_tell_cmd (const char *cmd, char *arg) 406 { 407 char *name; 408 const char *type, *dir, *data; 409 int i, len; 410 void *handle; 411 412 if (!strcmp (cmd, "load")) 413 { 414 printf (" %s", arg); 415 name = malloc (len = BLT_MAX_NAME_LENGTH); 416 strlcpy (name, "/boot/", len); 417 strlcat (name, arg, len); 418 strlcat (name, ".so", len); 419 handle = dlopen (name, 0); 420 if (handle == NULL) 421 { 422 printf ("(error)"); 423 return; 424 } 425 free (name); 426 } 427 else if (!strcmp (cmd, "mount")) 428 { 429 type = arg; 430 for (i = 0; arg[i] != ' '; i++) ; 431 arg[i] = 0; 432 dir = arg + i + 1; 433 for (arg++; arg[i] != ' '; i++) ; 434 arg[i] = 0; 435 data = arg + i + 1; 436 vfs_mount (dir, type, 0, data); 437 } 438 } 439 440 void vfs_tell_parse (const char *msg) 441 { 442 const char *c, *cmd; 443 char *full; 444 char *d; 445 int i, whole, len; 446 447 c = msg; 448 cmd = full = NULL; 449 whole = len = 0; 450 while (*c) 451 { 452 i = 0; 453 while ((c[i] != ' ') && c[i]) 454 i++; 455 d = malloc (i + 1); 456 strlcpy (d, c, i + 1); 457 if (cmd == NULL) 458 { 459 cmd = d; 460 if (!strcmp (cmd, "load")) 461 printf ("vfs: loading drivers. ["); 462 else if (!strcmp (cmd, "mount")) 463 { 464 whole = 1; 465 full = malloc (len = strlen (msg + 1)); 466 *full = 0; 467 } 468 } 469 else if (!whole) 470 vfs_tell_cmd (cmd, d); 471 else 472 { 473 strlcat (full, d, len); 474 strlcat (full, " ", len); 475 } 476 if (i != strlen (c)) 477 c += i + 1; 478 else 479 break; 480 } 481 if (whole) 482 full[strlen (full) - 1] = 0; 483 if (!strcmp (cmd, "load")) 484 printf (" ]\n"); 485 else if (!strcmp (cmd, "mount")) 486 vfs_tell_cmd (cmd, full); 487 } 488 489 void vfs_tell (void) 490 { 491 char buf[64]; 492 int port; 493 msg_hdr_t mh; 494 495 __libc_init_fdl (); 496 __libc_init_vfs (); 497 __dlinit (); 498 __blk_ref++; 499 500 port = port_create (0, "vfs:tell"); 501 namer_register (port, "vfs:tell"); 502 503 for (;;) 504 { 505 mh.src = 0; 506 mh.dst = port; 507 mh.data = buf; 508 mh.size = sizeof (buf); 509 old_port_recv (&mh); 510 vfs_tell_parse (mh.data); 511 512 mh.dst = mh.src; 513 mh.src = port; 514 mh.data = &port; 515 mh.size = 1; 516 old_port_send (&mh); 517 } 518 } 519 520 int vfs_main (volatile int *ready) 521 { 522 int i, size, len; 523 void *data; 524 msg_hdr_t msg, reply; 525 vfs_cmd_t vc; 526 vfs_res_t *res; 527 struct client *client; 528 529 /* open a connection to the console */ 530 __libc_init_console (); 531 532 /* get a public port and register ourself with the namer */ 533 vfs_port = port_create (0, "vfs_listen_port"); 534 namer_register (vfs_port, "vfs"); 535 536 /* say hello */ 537 #ifdef VFS_DEBUG 538 printf ("vfs: " FG_GREEN "listener ready" FG_WHITE " (port %d)\n", 539 vfs_port); 540 #endif 541 542 /* initialise structures */ 543 fs_drivers = NULL; 544 conn_table = hashtable_new (0.75); 545 res = NULL; 546 client = NULL; 547 548 /* mount the root and boot filesystems */ 549 fs_register (&rootfs); 550 fs_register (&bootfs); 551 vfs_mount ("/", "rootfs", 0, NULL); 552 vfs_mkdir ("/boot", 755); 553 vfs_mount ("/boot", "bootfs", 0, NULL); 554 thr_create (vfs_tell, 0, "vfs:tell"); 555 *ready = 1; 556 557 for (;;) 558 { 559 /* 560 * listen for commands. all ports will be slaved to the one 561 * we just created, so we only need to listen on one port. 562 */ 563 msg.src = 0; 564 msg.dst = vfs_port; 565 msg.data = &vc; 566 msg.size = sizeof (vc); 567 old_port_recv (&msg); 568 569 if (vc.cmd != VFS_OPENCONN) 570 client = hashtable_lookup (conn_table, msg.src, NULL); 571 size = sizeof (vfs_res_t); 572 data = NULL; 573 574 switch (vc.cmd) 575 { 576 case VFS_OPENCONN: 577 res = vfs_openconn (msg.src, vc.data[0]); 578 break; 579 580 case VFS_SCROLL_AREA: 581 res = vfs_scroll_area (client, &vc); 582 break; 583 584 case VFS_OPENDIR: 585 res = vfs_opendir (client, &vc); 586 if (res->status == VFS_OK) 587 shm_write_dir (client->ioctx.fdarray.ofile[res->data[0]], 588 0, 0, vc.data[3], &res->data[1], &res->data[2]); 589 break; 590 591 case VFS_CLOSEDIR: 592 res = vfs_closedir (client, &vc); 593 break; 594 595 case VFS_OPEN: 596 res = vfs_open (client, &vc); 597 if (res->status == VFS_OK) 598 shm_write (client->ioctx.fdarray.ofile[res->data[0]], 599 0, 0, vc.data[3], &res->data[1], &res->data[2]); 600 break; 601 602 case VFS_CLOSE: 603 res = vfs_close (client, &vc); 604 break; 605 606 case VFS_READ: 607 res = vfs_read (client, &vc, &data, &len); 608 break; 609 610 case VFS_RSTAT: 611 res = vfs_rstat (client, &vc); 612 size = sizeof (vfs_res_t) + sizeof (struct stat); 613 break; 614 615 case VFS_MKDIR: 616 res = malloc (sizeof (vfs_res_t)); 617 res->status = vfs_mkdir (client->nameptr + vc.data[0], 618 vc.data[1]); 619 res->errno = 0; 620 break; 621 } 622 623 if (res != NULL) 624 { 625 reply.src = (vc.cmd == VFS_OPENCONN) ? vfs_port : client->out; 626 reply.dst = msg.src; 627 reply.data = res; 628 reply.size = size; 629 old_port_send (&reply); 630 free (res); 631 632 if (data != NULL) 633 { 634 reply.src = client->out; 635 reply.dst = msg.src; 636 if (len < 0x1000) 637 { 638 reply.data = data; 639 reply.size = len; 640 old_port_send (&reply); 641 } 642 else 643 { 644 for (i = 0; len > 0x1000; i += 0x1000, len -= 0x1000) 645 { 646 reply.data = (char *) data + i; 647 reply.size = 0x1000; 648 old_port_send (&reply); 649 } 650 reply.data = (char *) data + i; 651 reply.size = len; 652 old_port_send (&reply); 653 } 654 free (data); 655 } 656 } 657 } 658 659 /* not reached */ 660 return 0; 661 } 662 663 int main (void) 664 { 665 volatile int ready = 0; 666 667 thr_create (vfs_main, (int *) &ready, "vfs"); 668 while (!ready) ; 669 return 0; 670 } 671