Project

General

Profile

Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (21 KB)

1
/*
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
}