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 |
} |