Project

General

Profile

Statistics
| Branch: | Revision:

scoutos / prex-0.9.0 / usr / server / fs / vfs / main.c @ 03e9c04a

History | View | Annotate | Download (21 KB)

1 03e9c04a Brad Neuman
/*
2
 * Copyright (c) 2005-2007, Kohsuke Ohtani
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 * 3. Neither the name of the author nor the names of any co-contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
/*
31
 * main.c - File system server
32
 */
33
34
/*
35
 * All file systems work as a sub-modules under VFS (Virtual File System).
36
 * The routines in this file have the responsible to the following jobs.
37
 *
38
 *  - Interpret the IPC message and pass the request into VFS routines.
39
 *  - Validate the some of passed arguments in the message.
40
 *  - Mapping of the task ID and cwd/file pointers.
41
 *
42
 * Note: All path string is translated to the full path before passing
43
 * it to the sys_* routines.
44
 */
45
46
#include <sys/prex.h>
47
#include <sys/capability.h>
48
#include <sys/param.h>
49
#include <ipc/fs.h>
50
#include <ipc/proc.h>
51
#include <ipc/exec.h>
52
#include <ipc/ipc.h>
53
#include <sys/list.h>
54
#include <sys/stat.h>
55
#include <sys/vnode.h>
56
#include <sys/mount.h>
57
#include <sys/buf.h>
58
#include <sys/file.h>
59
60
#include <limits.h>
61
#include <unistd.h>
62
#include <stdio.h>
63
#include <stdlib.h>
64
#include <string.h>
65
#include <errno.h>
66
#include <fcntl.h>
67
#include <signal.h>
68
69
#include "vfs.h"
70
71
#ifdef DEBUG_VFS
72
int        vfs_debug = VFSDB_FLAGS;
73
#endif
74
75
/*
76
 * Message mapping
77
 */
78
struct msg_map {
79
        int        code;
80
        int        (*func)(struct task *, struct msg *);
81
};
82
83
#define MSGMAP(code, fn) {code, (int (*)(struct task *, struct msg *))fn}
84
85
/* object for file service */
86
static object_t fsobj;
87
88
static int
89
fs_mount(struct task *t, struct mount_msg *msg)
90
{
91
        int error = 0;
92
93
        /* Check client's mount capability. */
94
        if (task_chkcap(t->t_taskid, CAP_DISKADMIN) != 0)
95
                error = EPERM;
96
97
        if (error == 0) {
98
                error = sys_mount(msg->dev, msg->dir, msg->fs, msg->flags,
99
                                (void *)msg->data);
100
        }
101
#ifdef DEBUG
102
        if (error)
103
                dprintf("VFS: mount failed!\n");
104
#endif
105
        return error;
106
}
107
108
static int
109
fs_umount(struct task *t, struct path_msg *msg)
110
{
111
112
        /* Check mount capability. */
113
        if (task_chkcap(t->t_taskid, CAP_DISKADMIN) != 0)
114
                return EPERM;
115
116
        return sys_umount(msg->path);
117
}
118
119
static int
120
fs_sync(struct task *t, struct msg *msg)
121
{
122
123
        return sys_sync();
124
}
125
126
static int
127
fs_open(struct task *t, struct open_msg *msg)
128
{
129
        char path[PATH_MAX];
130
        file_t fp;
131
        int fd, error;
132
        int acc;
133
134
        /* Find empty slot for file descriptor. */
135
        if ((fd = task_newfd(t)) == -1)
136
                return EMFILE;
137
138
        acc = 0;
139
        switch (msg->flags & O_ACCMODE) {
140
        case O_RDONLY:
141
                acc = VREAD;
142
                break;
143
        case O_WRONLY:
144
                acc = VWRITE;
145
                break;
146
        case O_RDWR:
147
                acc = VREAD | VWRITE;
148
                break;
149
        }
150
        if ((error = task_conv(t, msg->path, acc, path)) != 0)
151
                return error;
152
153
        if ((error = sys_open(path, msg->flags, msg->mode, &fp)) != 0)
154
                return error;
155
156
        t->t_ofile[fd] = fp;
157
        t->t_nopens++;
158
        msg->fd = fd;
159
        return 0;
160
}
161
162
static int
163
fs_close(struct task *t, struct msg *msg)
164
{
165
        file_t fp;
166
        int fd, error;
167
168
        fd = msg->data[0];
169
        if (fd >= OPEN_MAX)
170
                return EBADF;
171
172
        fp = t->t_ofile[fd];
173
        if (fp == NULL)
174
                return EBADF;
175
176
        if ((error = sys_close(fp)) != 0)
177
                return error;
178
179
        t->t_ofile[fd] = NULL;
180
        t->t_nopens--;
181
        return 0;
182
}
183
184
static int
185
fs_mknod(struct task *t, struct open_msg *msg)
186
{
187
        char path[PATH_MAX];
188
        int error;
189
190
        if ((error = task_conv(t, msg->path, VWRITE, path)) != 0)
191
                return error;
192
193
        return sys_mknod(path, msg->mode);
194
}
195
196
static int
197
fs_lseek(struct task *t, struct msg *msg)
198
{
199
        file_t fp;
200
        off_t offset, org;
201
        int error, type;
202
203
        if ((fp = task_getfp(t, msg->data[0])) == NULL)
204
                return EBADF;
205
        offset = (off_t)msg->data[1];
206
        type = msg->data[2];
207
208
        error = sys_lseek(fp, offset, type, &org);
209
        msg->data[0] = (int)org;
210
        return error;
211
}
212
213
static int
214
fs_read(struct task *t, struct io_msg *msg)
215
{
216
        file_t fp;
217
        void *buf;
218
        size_t size, bytes;
219
        int error;
220
221
        if ((fp = task_getfp(t, msg->fd)) == NULL)
222
                return EBADF;
223
        size = msg->size;
224
        if ((error = vm_map(msg->hdr.task, msg->buf, size, &buf)) != 0)
225
                return EFAULT;
226
227
        error = sys_read(fp, buf, size, &bytes);
228
        msg->size = bytes;
229
        vm_free(task_self(), buf);
230
        return error;
231
}
232
233
static int
234
fs_write(struct task *t, struct io_msg *msg)
235
{
236
        file_t fp;
237
        void *buf;
238
        size_t size, bytes;
239
        int error;
240
241
        if ((fp = task_getfp(t, msg->fd)) == NULL)
242
                return EBADF;
243
        size = msg->size;
244
        if ((error = vm_map(msg->hdr.task, msg->buf, size, &buf)) != 0)
245
                return EFAULT;
246
247
        error = sys_write(fp, buf, size, &bytes);
248
        msg->size = bytes;
249
        vm_free(task_self(), buf);
250
        return error;
251
}
252
253
static int
254
fs_ioctl(struct task *t, struct ioctl_msg *msg)
255
{
256
        file_t fp;
257
258
        if ((fp = task_getfp(t, msg->fd)) == NULL)
259
                return EBADF;
260
261
        return sys_ioctl(fp, msg->request, msg->buf);
262
}
263
264
static int
265
fs_fsync(struct task *t, struct msg *msg)
266
{
267
        file_t fp;
268
269
        if ((fp = task_getfp(t, msg->data[0])) == NULL)
270
                return EBADF;
271
272
        return sys_fsync(fp);
273
}
274
275
static int
276
fs_fstat(struct task *t, struct stat_msg *msg)
277
{
278
        file_t fp;
279
        struct stat *st;
280
        int error;
281
282
        if ((fp = task_getfp(t, msg->fd)) == NULL)
283
                return EBADF;
284
285
        st = &msg->st;
286
        error = sys_fstat(fp, st);
287
        return error;
288
}
289
290
static int
291
fs_opendir(struct task *t, struct open_msg *msg)
292
{
293
        char path[PATH_MAX];
294
        file_t fp;
295
        int fd, error;
296
297
        /* Find empty slot for file descriptor. */
298
        if ((fd = task_newfd(t)) == -1)
299
                return EMFILE;
300
301
        /* Get the mounted file system and node */
302
        if ((error = task_conv(t, msg->path, VREAD, path)) != 0)
303
                return error;
304
305
        if ((error = sys_opendir(path, &fp)) != 0)
306
                return error;
307
        t->t_ofile[fd] = fp;
308
        msg->fd = fd;
309
        return 0;
310
}
311
312
static int
313
fs_closedir(struct task *t, struct msg *msg)
314
{
315
        file_t fp;
316
        int fd, error;
317
318
        fd = msg->data[0];
319
        if (fd >= OPEN_MAX)
320
                return EBADF;
321
        fp = t->t_ofile[fd];
322
        if (fp == NULL)
323
                return EBADF;
324
325
        if ((error = sys_closedir(fp)) != 0)
326
                return error;
327
        t->t_ofile[fd] = NULL;
328
        return 0;
329
}
330
331
static int
332
fs_readdir(struct task *t, struct dir_msg *msg)
333
{
334
        file_t fp;
335
336
        if ((fp = task_getfp(t, msg->fd)) == NULL)
337
                return EBADF;
338
339
        return sys_readdir(fp, &msg->dirent);
340
}
341
342
static int
343
fs_rewinddir(struct task *t, struct msg *msg)
344
{
345
        file_t fp;
346
347
        if ((fp = task_getfp(t, msg->data[0])) == NULL)
348
                return EBADF;
349
350
        return sys_rewinddir(fp);
351
}
352
353
static int
354
fs_seekdir(struct task *t, struct msg *msg)
355
{
356
        file_t fp;
357
        long loc;
358
359
        if ((fp = task_getfp(t, msg->data[0])) == NULL)
360
                return EBADF;
361
        loc = msg->data[1];
362
363
        return sys_seekdir(fp, loc);
364
}
365
366
static int
367
fs_telldir(struct task *t, struct msg *msg)
368
{
369
        file_t fp;
370
        long loc;
371
        int error;
372
373
        if ((fp = task_getfp(t, msg->data[0])) == NULL)
374
                return EBADF;
375
        loc = msg->data[1];
376
377
        if ((error = sys_telldir(fp, &loc)) != 0)
378
                return error;
379
        msg->data[0] = loc;
380
        return 0;
381
}
382
383
static int
384
fs_mkdir(struct task *t, struct open_msg *msg)
385
{
386
        char path[PATH_MAX];
387
        int error;
388
389
        if ((error = task_conv(t, msg->path, VWRITE, path)) != 0)
390
                return error;
391
392
        return sys_mkdir(path, msg->mode);
393
}
394
395
static int
396
fs_rmdir(struct task *t, struct path_msg *msg)
397
{
398
        char path[PATH_MAX];
399
        int error;
400
401
        if (msg->path == NULL)
402
                return ENOENT;
403
        if ((error = task_conv(t, msg->path, VWRITE, path)) != 0)
404
                return error;
405
406
        return sys_rmdir(path);
407
}
408
409
static int
410
fs_rename(struct task *t, struct path_msg *msg)
411
{
412
        char src[PATH_MAX];
413
        char dest[PATH_MAX];
414
        int error;
415
416
        if (msg->path == NULL || msg->path2 == NULL)
417
                return ENOENT;
418
419
        if ((error = task_conv(t, msg->path, VREAD, src)) != 0)
420
                return error;
421
422
        if ((error = task_conv(t, msg->path2, VWRITE, dest)) != 0)
423
                return error;
424
425
        return sys_rename(src, dest);
426
}
427
428
static int
429
fs_chdir(struct task *t, struct path_msg *msg)
430
{
431
        char path[PATH_MAX];
432
        file_t fp;
433
        int error;
434
435
        if (msg->path == NULL)
436
                return ENOENT;
437
        if ((error = task_conv(t, msg->path, VREAD, path)) != 0)
438
                return error;
439
440
        /* Check if directory exits */
441
        if ((error = sys_opendir(path, &fp)) != 0)
442
                return error;
443
        if (t->t_cwdfp)
444
                sys_closedir(t->t_cwdfp);
445
        t->t_cwdfp = fp;
446
        strlcpy(t->t_cwd, path, sizeof(t->t_cwd));
447
         return 0;
448
}
449
450
static int
451
fs_fchdir(struct task *t, struct msg *msg)
452
{
453
        file_t fp;
454
        int fd;
455
456
        fd = msg->data[0];
457
        if ((fp = task_getfp(t, fd)) == NULL)
458
                return EBADF;
459
460
        if (t->t_cwdfp)
461
                sys_closedir(t->t_cwdfp);
462
        t->t_cwdfp = fp;
463
        return sys_fchdir(fp, t->t_cwd);
464
}
465
466
static int
467
fs_link(struct task *t, struct msg *msg)
468
{
469
        /* XXX */
470
        return EPERM;
471
}
472
473
static int
474
fs_unlink(struct task *t, struct path_msg *msg)
475
{
476
        char path[PATH_MAX];
477
        int error;
478
479
        if (msg->path == NULL)
480
                return ENOENT;
481
        if ((error = task_conv(t, msg->path, VWRITE, path)) != 0)
482
                return error;
483
484
        return sys_unlink(path);
485
}
486
487
static int
488
fs_stat(struct task *t, struct stat_msg *msg)
489
{
490
        char path[PATH_MAX];
491
        struct stat *st;
492
        int error;
493
494
        error = task_conv(t, msg->path, 0, path);
495
        if (error == 0) {
496
                st = &msg->st;
497
                error = sys_stat(path, st);
498
        }
499
        return error;
500
}
501
502
static int
503
fs_getcwd(struct task *t, struct path_msg *msg)
504
{
505
506
        strlcpy(msg->path, t->t_cwd, sizeof(msg->path));
507
        return 0;
508
}
509
510
/*
511
 * Duplicate a file descriptor
512
 */
513
static int
514
fs_dup(struct task *t, struct msg *msg)
515
{
516
        file_t fp;
517
        int old_fd, new_fd;
518
519
        old_fd = msg->data[0];
520
        if ((fp = task_getfp(t, old_fd)) == NULL)
521
                return EBADF;
522
523
        /* Find smallest empty slot as new fd. */
524
        if ((new_fd = task_newfd(t)) == -1)
525
                return EMFILE;
526
527
        t->t_ofile[new_fd] = fp;
528
529
        /* Increment file reference */
530
        vref(fp->f_vnode);
531
        fp->f_count++;
532
533
        msg->data[0] = new_fd;
534
        return 0;
535
}
536
537
/*
538
 * Duplicate a file descriptor to a particular value.
539
 */
540
static int
541
fs_dup2(struct task *t, struct msg *msg)
542
{
543
        file_t fp, org;
544
        int old_fd, new_fd;
545
        int error;
546
547
        old_fd = msg->data[0];
548
        new_fd = msg->data[1];
549
        if (old_fd >= OPEN_MAX || new_fd >= OPEN_MAX)
550
                return EBADF;
551
        fp = t->t_ofile[old_fd];
552
        if (fp == NULL)
553
                return EBADF;
554
        org = t->t_ofile[new_fd];
555
        if (org != NULL) {
556
                /* Close previous file if it's opened. */
557
                error = sys_close(org);
558
        }
559
        t->t_ofile[new_fd] = fp;
560
561
        /* Increment file reference */
562
        vref(fp->f_vnode);
563
        fp->f_count++;
564
565
        msg->data[0] = new_fd;
566
        return 0;
567
}
568
569
/*
570
 * The file control system call.
571
 */
572
static int
573
fs_fcntl(struct task *t, struct fcntl_msg *msg)
574
{
575
        file_t fp;
576
        int arg, new_fd;
577
578
        if ((fp = task_getfp(t, msg->fd)) == NULL)
579
                return EBADF;
580
581
        arg = msg->arg;
582
        switch (msg->cmd) {
583
        case F_DUPFD:
584
                if (arg >= OPEN_MAX)
585
                        return EINVAL;
586
                /* Find smallest empty slot as new fd. */
587
                if ((new_fd = task_newfd(t)) == -1)
588
                        return EMFILE;
589
                t->t_ofile[new_fd] = fp;
590
591
                /* Increment file reference */
592
                vref(fp->f_vnode);
593
                fp->f_count++;
594
                msg->arg = new_fd;
595
                break;
596
        case F_GETFD:
597
                msg->arg = fp->f_flags & FD_CLOEXEC;
598
                break;
599
        case F_SETFD:
600
                fp->f_flags = (fp->f_flags & ~FD_CLOEXEC) |
601
                        (msg->arg & FD_CLOEXEC);
602
                msg->arg = 0;
603
                break;
604
        case F_GETFL:
605
        case F_SETFL:
606
                msg->arg = -1;
607
                break;
608
        default:
609
                msg->arg = -1;
610
                break;
611
        }
612
        return 0;
613
}
614
615
/*
616
 * Check permission for file access
617
 */
618
static int
619
fs_access(struct task *t, struct path_msg *msg)
620
{
621
        char path[PATH_MAX];
622
        int acc, mode, error = 0;
623
624
        mode = msg->data[0];
625
        acc = 0;
626
        if (mode & R_OK)
627
                acc |= VREAD;
628
        if (mode & W_OK)
629
                acc |= VWRITE;
630
631
        if ((error = task_conv(t, msg->path, acc, path)) != 0)
632
                return error;
633
634
        return sys_access(path, mode);
635
}
636
637
/*
638
 * Copy parent's cwd & file/directory descriptor to child's.
639
 */
640
static int
641
fs_fork(struct task *t, struct msg *msg)
642
{
643
        struct task *newtask;
644
        file_t fp;
645
        int error, i;
646
647
        DPRINTF(VFSDB_CORE, ("fs_fork\n"));
648
649
        if ((error = task_alloc((task_t)msg->data[0], &newtask)) != 0)
650
                return error;
651
652
        /*
653
         * Copy task related data
654
         */
655
        newtask->t_cwdfp = t->t_cwdfp;
656
        strlcpy(newtask->t_cwd, t->t_cwd, sizeof(newtask->t_cwd));
657
        for (i = 0; i < OPEN_MAX; i++) {
658
                fp = t->t_ofile[i];
659
                newtask->t_ofile[i] = fp;
660
                /*
661
                 * Increment file reference if it's
662
                 * already opened.
663
                 */
664
                if (fp != NULL) {
665
                        vref(fp->f_vnode);
666
                        fp->f_count++;
667
                }
668
        }
669
        if (newtask->t_cwdfp)
670
                newtask->t_cwdfp->f_count++;
671
        /* Increment cwd's reference count */
672
        if (newtask->t_cwdfp)
673
                vref(newtask->t_cwdfp->f_vnode);
674
675
        DPRINTF(VFSDB_CORE, ("fs_fork-complete\n"));
676
        return 0;
677
}
678
679
/*
680
 * fs_exec() is called for POSIX exec().
681
 * It closes all directory stream.
682
 * File descriptor which is marked close-on-exec are also closed.
683
 */
684
static int
685
fs_exec(struct task *t, struct msg *msg)
686
{
687
        task_t old_id, new_id;
688
        struct task *target;
689
        file_t fp;
690
        int fd;
691
692
        old_id = (task_t)msg->data[0];
693
        new_id = (task_t)msg->data[1];
694
695
        if (!(target = task_lookup(old_id)))
696
                return EINVAL;
697
698
        /* Update task id in the task. */
699
        task_setid(target, new_id);
700
701
        /* Close all directory descriptor */
702
        for (fd = 0; fd < OPEN_MAX; fd++) {
703
                fp = target->t_ofile[fd];
704
                if (fp) {
705
                        if (fp->f_vnode->v_type == VDIR) {
706
                                sys_close(fp);
707
                                target->t_ofile[fd] = NULL;
708
                        }
709
710
                        /* XXX: need to check close-on-exec flag */
711
                }
712
        }
713
        task_unlock(target);
714
        return 0;
715
}
716
717
/*
718
 * fs_exit() cleans up data for task's termination.
719
 */
720
static int
721
fs_exit(struct task *t, struct msg *msg)
722
{
723
        file_t fp;
724
        int fd;
725
726
        DPRINTF(VFSDB_CORE, ("fs_exit\n"));
727
728
        /*
729
         * Close all files opened by task.
730
         */
731
        for (fd = 0; fd < OPEN_MAX; fd++) {
732
                fp = t->t_ofile[fd];
733
                if (fp != NULL)
734
                        sys_close(fp);
735
        }
736
        if (t->t_cwdfp)
737
                sys_close(t->t_cwdfp);
738
        task_free(t);
739
        return 0;
740
}
741
742
/*
743
 * fs_register() is called by boot tasks.
744
 * This can be called even when no fs is mounted.
745
 */
746
static int
747
fs_register(struct task *t, struct msg *msg)
748
{
749
        struct task *tmp;
750
        int error;
751
752
        DPRINTF(VFSDB_CORE, ("fs_register\n"));
753
754
        error = task_alloc(msg->hdr.task, &tmp);
755
        return error;
756
}
757
758
static int
759
fs_pipe(struct task *t, struct msg *msg)
760
{
761
#ifdef CONFIG_FIFOFS
762
        char path[PATH_MAX];
763
        file_t rfp, wfp;
764
        int error, rfd, wfd;
765
766
        DPRINTF(VFSDB_CORE, ("fs_pipe\n"));
767
768
        if ((rfd = task_newfd(t)) == -1)
769
                return EMFILE;
770
        t->t_ofile[rfd] = (file_t)1; /* temp */
771
772
        if ((wfd = task_newfd(t)) == -1) {
773
                t->t_ofile[rfd] = NULL;
774
                return EMFILE;
775
        }
776
        sprintf(path, "/mnt/fifo/pipe-%x-%d", (u_int)t->t_taskid, rfd);
777
778
        if ((error = sys_mknod(path, S_IFIFO)) != 0)
779
                goto out;
780
        if ((error = sys_open(path, O_RDONLY | O_NONBLOCK, 0, &rfp)) != 0) {
781
                goto out;
782
        }
783
        if ((error = sys_open(path, O_WRONLY | O_NONBLOCK, 0, &wfp)) != 0) {
784
                goto out;
785
        }
786
        t->t_ofile[rfd] = rfp;
787
        t->t_ofile[wfd] = wfp;
788
        t->t_nopens += 2;
789
        msg->data[0] = rfd;
790
        msg->data[1] = wfd;
791
        return 0;
792
 out:
793
        t->t_ofile[rfd] = NULL;
794
        t->t_ofile[wfd] = NULL;
795
        return error;
796
#else
797
        return ENOSYS;
798
#endif
799
}
800
801
/*
802
 * Return if specified file is a tty
803
 */
804
static int
805
fs_isatty(struct task *t, struct msg *msg)
806
{
807
        file_t fp;
808
        int istty = 0;
809
810
        if ((fp = task_getfp(t, msg->data[0])) == NULL)
811
                return EBADF;
812
813
        if (fp->f_vnode->v_flags & VISTTY)
814
                istty = 1;
815
        msg->data[0] = istty;
816
        return 0;
817
}
818
819
static int
820
fs_truncate(struct task *t, struct path_msg *msg)
821
{
822
        char path[PATH_MAX];
823
        int error;
824
825
        if (msg->path == NULL)
826
                return ENOENT;
827
        if ((error = task_conv(t, msg->path, VWRITE, path)) != 0)
828
                return error;
829
830
        return sys_truncate(path, msg->data[0]);
831
}
832
833
static int
834
fs_ftruncate(struct task *t, struct msg *msg)
835
{
836
        file_t fp;
837
838
        if ((fp = task_getfp(t, msg->data[0])) == NULL)
839
                return EBADF;
840
841
        return sys_ftruncate(fp, msg->data[1]);
842
}
843
844
/*
845
 * Prepare for boot
846
 */
847
static int
848
fs_boot(struct task *t, struct msg *msg)
849
{
850
        object_t execobj, procobj;
851
        struct bind_msg bm;
852
        struct msg m;
853
854
        /* Check client's capability. */
855
        if (task_chkcap(msg->hdr.task, CAP_PROTSERV) != 0)
856
                return EPERM;
857
858
        /*
859
         * Request exec server to bind an appropriate
860
         * capability for us.
861
         */
862
        if (object_lookup("!exec", &execobj) != 0)
863
                sys_panic("fs: no exec found");
864
        bm.hdr.code = EXEC_BINDCAP;
865
        strlcpy(bm.path, "/boot/fs", sizeof(bm.path));
866
        msg_send(execobj, &bm, sizeof(bm));
867
868
        /*
869
         * Notify to process server.
870
         */
871
        if (object_lookup("!proc", &procobj) != 0)
872
                sys_panic("fs: no proc found");
873
        m.hdr.code = PS_REGISTER;
874
        msg_send(procobj, &m, sizeof(m));
875
876
        return 0;
877
}
878
879
/*
880
 * Prepare for shutdown
881
 */
882
static int
883
fs_shutdown(struct task *t, struct msg *msg)
884
{
885
886
        DPRINTF(VFSDB_CORE, ("fs_shutdown\n"));
887
        return 0;
888
}
889
890
int
891
fs_noop(void)
892
{
893
        return 0;
894
}
895
896
#ifdef DEBUG_VFS
897
/*
898
 * Dump internal data.
899
 */
900
static int
901
fs_debug(struct task *t, struct msg *msg)
902
{
903
904
        dprintf("<File System Server>\n");
905
        task_dump();
906
        vnode_dump();
907
        mount_dump();
908
        return 0;
909
}
910
#endif
911
912
static void
913
vfs_init(void)
914
{
915
        const struct vfssw *fs;
916
        struct msg msg;
917
918
        /*
919
         * Initialize VFS core.
920
         */
921
        task_init();
922
        bio_init();
923
        vnode_init();
924
925
        /*
926
         * Initialize each file system.
927
         */
928
        for (fs = vfssw; fs->vs_name; fs++) {
929
                DPRINTF(VFSDB_CORE, ("VFS: initializing %s\n",
930
                                     fs->vs_name));
931
                fs->vs_init();
932
        }
933
934
        /*
935
         * Create task data for ourselves.
936
         */
937
        msg.hdr.task = task_self();
938
        fs_register(NULL, &msg);
939
}
940
941
/*
942
 * Run specified routine as a thread.
943
 */
944
static int
945
run_thread(void (*entry)(void))
946
{
947
        task_t self;
948
        thread_t t;
949
        void *stack, *sp;
950
        int error;
951
952
        self = task_self();
953
        if ((error = thread_create(self, &t)) != 0)
954
                return error;
955
        if ((error = vm_allocate(self, &stack, DFLSTKSZ, 1)) != 0)
956
                return error;
957
958
        sp = (void *)((u_long)stack + DFLSTKSZ - sizeof(u_long) * 3);
959
        if ((error = thread_load(t, entry, sp)) != 0)
960
                return error;
961
962
        return thread_resume(t);
963
}
964
965
static void
966
exception_handler(int sig)
967
{
968
969
        exception_return();
970
}
971
972
/*
973
 * Message mapping
974
 */
975
static const struct msg_map fsmsg_map[] = {
976
        MSGMAP( FS_MOUNT,        fs_mount ),
977
        MSGMAP( FS_UMOUNT,        fs_umount ),
978
        MSGMAP( FS_SYNC,        fs_sync ),
979
        MSGMAP( FS_OPEN,        fs_open ),
980
        MSGMAP( FS_CLOSE,        fs_close ),
981
        MSGMAP( FS_MKNOD,        fs_mknod ),
982
        MSGMAP( FS_LSEEK,        fs_lseek ),
983
        MSGMAP( FS_READ,        fs_read ),
984
        MSGMAP( FS_WRITE,        fs_write ),
985
        MSGMAP( FS_IOCTL,        fs_ioctl ),
986
        MSGMAP( FS_FSYNC,        fs_fsync ),
987
        MSGMAP( FS_FSTAT,        fs_fstat ),
988
        MSGMAP( FS_OPENDIR,        fs_opendir ),
989
        MSGMAP( FS_CLOSEDIR,        fs_closedir ),
990
        MSGMAP( FS_READDIR,        fs_readdir ),
991
        MSGMAP( FS_REWINDDIR,        fs_rewinddir ),
992
        MSGMAP( FS_SEEKDIR,        fs_seekdir ),
993
        MSGMAP( FS_TELLDIR,        fs_telldir ),
994
        MSGMAP( FS_MKDIR,        fs_mkdir ),
995
        MSGMAP( FS_RMDIR,        fs_rmdir ),
996
        MSGMAP( FS_RENAME,        fs_rename ),
997
        MSGMAP( FS_CHDIR,        fs_chdir ),
998
        MSGMAP( FS_LINK,        fs_link ),
999
        MSGMAP( FS_UNLINK,        fs_unlink ),
1000
        MSGMAP( FS_STAT,        fs_stat ),
1001
        MSGMAP( FS_GETCWD,        fs_getcwd ),
1002
        MSGMAP( FS_DUP,                fs_dup ),
1003
        MSGMAP( FS_DUP2,        fs_dup2 ),
1004
        MSGMAP( FS_FCNTL,        fs_fcntl ),
1005
        MSGMAP( FS_ACCESS,        fs_access ),
1006
        MSGMAP( FS_FORK,        fs_fork ),
1007
        MSGMAP( FS_EXEC,        fs_exec ),
1008
        MSGMAP( FS_EXIT,        fs_exit ),
1009
        MSGMAP( FS_REGISTER,        fs_register ),
1010
        MSGMAP( FS_PIPE,        fs_pipe ),
1011
        MSGMAP( FS_ISATTY,        fs_isatty ),
1012
        MSGMAP( FS_TRUNCATE,        fs_truncate ),
1013
        MSGMAP( FS_FTRUNCATE,        fs_ftruncate ),
1014
        MSGMAP( FS_FCHDIR,        fs_fchdir ),
1015
        MSGMAP( STD_BOOT,        fs_boot ),
1016
        MSGMAP( STD_SHUTDOWN,        fs_shutdown ),
1017
#ifdef DEBUG_VFS
1018
        MSGMAP( STD_DEBUG,        fs_debug ),
1019
#endif
1020
        MSGMAP( 0,                NULL ),
1021
};
1022
1023
/*
1024
 * File system thread.
1025
 */
1026
static void
1027
fs_thread(void)
1028
{
1029
        struct msg *msg;
1030
        const struct msg_map *map;
1031
        struct task *t;
1032
        int error;
1033
1034
        msg = malloc(MAX_FSMSG);
1035
1036
        /*
1037
         * Message loop
1038
         */
1039
        for (;;) {
1040
                /*
1041
                 * Wait for an incoming request.
1042
                 */
1043
                if ((error = msg_receive(fsobj, msg, MAX_FSMSG)) != 0)
1044
                        continue;
1045
1046
                error = EINVAL;
1047
                map = &fsmsg_map[0];
1048
                while (map->code != 0) {
1049
                        if (map->code == msg->hdr.code) {
1050
                                /*
1051
                                 * Handle messages by non-registerd tasks
1052
                                 */
1053
                                if (map->code == STD_BOOT) {
1054
                                        error = fs_boot(NULL, msg);
1055
                                        break;
1056
                                }
1057
                                if (map->code == FS_REGISTER) {
1058
                                        error = fs_register(NULL, msg);
1059
                                        break;
1060
                                }
1061
1062
                                /* Lookup and lock task */
1063
                                t = task_lookup(msg->hdr.task);
1064
                                if (t == NULL)
1065
                                        break;
1066
1067
                                /* Dispatch request */
1068
                                error = (*map->func)(t, msg);
1069
                                if (map->code != FS_EXIT)
1070
                                        task_unlock(t);
1071
                                break;
1072
                        }
1073
                        map++;
1074
                }
1075
#ifdef DEBUG_VFS
1076
                if (error)
1077
                        dprintf("VFS: task=%x code=%x error=%d\n",
1078
                                msg->hdr.task, map->code, error);
1079
#endif
1080
                /*
1081
                 * Reply to the client.
1082
                 */
1083
                msg->hdr.status = error;
1084
                msg_reply(fsobj, msg, MAX_FSMSG);
1085
        }
1086
}
1087
1088
/*
1089
 * Main routine for file system service
1090
 */
1091
int
1092
main(int argc, char *argv[])
1093
{
1094
        int i;
1095
1096
        sys_log("Starting file system server\n");
1097
1098
        DPRINTF(VFSDB_CORE, ("VFS: number of fs threads: %d\n",
1099
                             CONFIG_FS_THREADS));
1100
1101
        /* Set thread priority. */
1102
        thread_setpri(thread_self(), PRI_FS);
1103
1104
        /* Setup exception handler */
1105
        exception_setup(exception_handler);
1106
1107
        /* Initialize the file systems. */
1108
        vfs_init();
1109
1110
        /* Create an object to expose our service. */
1111
        if (object_create("!fs", &fsobj))
1112
                sys_panic("VFS: fail to create object");
1113
1114
        /*
1115
         * Create new server threads.
1116
         */
1117
        i = CONFIG_FS_THREADS;
1118
        while (--i > 0) {
1119
                if (run_thread(fs_thread))
1120
                        goto err;
1121
        }
1122
        fs_thread();
1123
1124
        sys_panic("VFS: exit!");
1125
        exit(0);
1126
 err:
1127
        sys_panic("VFS: failed to create thread");
1128
        return 0;
1129
}