1 /*
2 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3 * Alexander Warg <warg@os.inf.tu-dresden.de>
4 * economic rights: Technische Universität Dresden (Germany)
5 * This file is part of TUD:OS and distributed under the terms of the
6 * GNU Lesser General Public License 2.1.
7 * Please see the COPYING-LGPL-2.1 file for details.
8 */
9
10
11 #include <features.h>
12
13 #ifndef __USE_ATFILE
14 # define __USE_ATFILE 1
15 #endif
16
17 #include <l4/re/log>
18 #include <l4/re/env>
19
20 #include <stdarg.h>
21 #include <errno.h>
22 #include <unistd.h>
23 #include <limits.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <sys/ioctl.h>
27 #include <sys/mman.h>
28 #include <sys/uio.h>
29 #include <sys/time.h>
30 #include <l4/l4re_vfs/backend>
31 #include <string.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include "redirect.h"
35
36 using namespace L4Re::Vfs;
37 using cxx::Ref_ptr;
38
read(int fd,void * buf,size_t count)39 ssize_t read(int fd, void *buf, size_t count)
40 {
41 struct iovec iov;
42 iov.iov_base = buf;
43 iov.iov_len = count;
44 return readv(fd, &iov, 1);
45 }
46
write(int fd,const void * buf,size_t count)47 ssize_t write(int fd, const void *buf, size_t count)
48 {
49 struct iovec iov;
50 iov.iov_base = const_cast<void*>(buf);
51 iov.iov_len = count;
52 return writev(fd, &iov, 1);
53 }
54
copy_stat64_to_stat(struct stat * buf,struct stat64 * sb64)55 static void copy_stat64_to_stat(struct stat *buf, struct stat64 *sb64)
56 {
57 memset(buf, 0, sizeof(*buf));
58
59 buf->st_dev = sb64->st_dev;
60 buf->st_ino = sb64->st_ino;
61 buf->st_mode = sb64->st_mode;
62 buf->st_nlink = sb64->st_nlink;
63 buf->st_uid = sb64->st_uid;
64 buf->st_gid = sb64->st_gid;
65 buf->st_rdev = sb64->st_rdev;
66 buf->st_size = sb64->st_size;
67 buf->st_blksize = sb64->st_blksize;
68 buf->st_blocks = sb64->st_blocks;
69 buf->st_atime = sb64->st_atime;
70 buf->st_mtime = sb64->st_mtime;
71 buf->st_ctime = sb64->st_ctime;
72 }
73
fstat(int fd,struct stat * buf)74 int fstat(int fd, struct stat *buf) noexcept(noexcept(fstat(fd, buf)))
75 {
76 struct stat64 sb64;
77 int r = fstat64(fd, &sb64);
78 if (r < 0)
79 return r;
80
81 copy_stat64_to_stat(buf, &sb64);
82 return r;
83 }
84
85 #define ERRNO_RET(r) do { \
86 if ((r) < 0) \
87 { \
88 errno = -(r); \
89 return -1; \
90 } } while (0)
91
92
93 namespace {
94
__internal_get_dir(int dirfd,char const ** path)95 static Ref_ptr<File> __internal_get_dir(int dirfd, char const **path) L4_NOTHROW
96 {
97 Ops *vfs_ops = L4Re::Vfs::vfs_ops;
98 if (**path == '/')
99 {
100 while (**path == '/')
101 ++*path;
102
103 return vfs_ops->get_root();
104 }
105 else if (dirfd == AT_FDCWD)
106 return vfs_ops->get_cwd();
107 else
108 return vfs_ops->get_file(dirfd);
109 }
110
111 static char const *
__internal_resolvedir(int dirfd,const char * path,int flags,mode_t mode,Ref_ptr<File> * f)112 __internal_resolvedir(int dirfd, const char *path, int flags, mode_t mode,
113 Ref_ptr<File> *f) L4_NOTHROW
114 {
115 (void)flags;
116 (void)mode;
117 Ref_ptr<File> dir = __internal_get_dir(dirfd, &path);
118 if (!dir)
119 return 0;
120
121 return dir->get_mount(path, f);
122 }
123
124 static int
__internal_resolve(int dirfd,const char * path,int flags,mode_t mode,Ref_ptr<File> * f)125 __internal_resolve(int dirfd, const char *path, int flags, mode_t mode,
126 Ref_ptr<File> *f) L4_NOTHROW
127 {
128 Ref_ptr<File> dir = __internal_get_dir(dirfd, &path);
129 if (!dir)
130 return -EBADF;
131
132 return dir->openat(path, flags, mode, f);
133 }
134
135 static int
__internal_open(const char * path,int flags,mode_t mode)136 __internal_open(const char *path, int flags, mode_t mode) L4_NOTHROW
137 {
138 Ref_ptr<File> f;
139 int res = __internal_resolve(AT_FDCWD, path, flags, mode, &f);
140
141 ERRNO_RET(res);
142
143 int fd = L4Re::Vfs::vfs_ops->alloc_fd(f);
144
145 ERRNO_RET(fd);
146 return fd;
147 }
148 }
149
open(const char * name,int flags,...)150 int open(const char *name, int flags, ...)
151 {
152 mode_t mode = 0;
153
154 if (flags & O_CREAT)
155 {
156 va_list v;
157 va_start(v, flags);
158 mode = va_arg(v, mode_t);
159 va_end(v);
160 }
161
162 return __internal_open(name, flags, mode);
163
164 }
165
open64(const char * name,int flags,...)166 int open64(const char *name, int flags, ...)
167 {
168 mode_t mode = 0;
169
170 if (flags & O_CREAT)
171 {
172 va_list v;
173 va_start(v, flags);
174 mode = va_arg(v, mode_t);
175 va_end(v);
176 }
177
178 return __internal_open(name, flags, mode);
179 }
180
ioctl(int fd,unsigned long request,...)181 extern "C" int ioctl(int fd, unsigned long request, ...)
182 noexcept(noexcept(ioctl(fd, request)))
183 {
184 va_list v;
185 va_start(v, request);
186
187 L4B_FD;
188
189 int r = file->ioctl(request, v);
190 va_end(v);
191 POST();
192 }
193
194 #if !(defined(__USE_LARGEFILE64) && !defined(__LP64__))
195 // Duplicate here as uclibc only defines fcntl64
196 // with __USE_LARGEFILE64 && !__LP64__
197 extern "C" int fcntl64 (int __fd, int __cmd, ...);
198 #endif
199
fcntl64(int fd,int cmd,...)200 extern "C" int fcntl64(int fd, int cmd, ...)
201 {
202 Ops *o = L4Re::Vfs::vfs_ops;
203 Ref_ptr<File> f = o->get_file(fd);
204
205 if (!f)
206 {
207 errno = EBADF;
208 return -1;
209 }
210
211 switch (cmd)
212 {
213 case F_DUPFD:
214 case F_DUPFD_CLOEXEC:
215 // 'arg' has the lowest fd ... so dup isn't the correct thing
216 return dup(fd);
217
218 case F_GETFD:
219 return 0;
220 case F_SETFD:
221 return 0;
222
223 case F_GETFL:
224 return f->get_status_flags();
225 case F_SETFL:
226 return 0;
227
228 case F_GETLK:
229 case F_SETLK:
230 case F_SETLKW:
231 errno = EINVAL;
232 return -1;
233
234 case F_GETOWN:
235 return 0;
236 case F_SETOWN:
237 errno = EINVAL;
238 return -1;
239
240 case F_GETSIG:
241 return 0;
242 case F_SETSIG:
243 errno = EINVAL;
244 return -1;
245
246 default:
247 errno = EINVAL;
248 return -1;
249 }
250 }
251
fcntl(int fd,int cmd,...)252 extern "C" int fcntl(int fd, int cmd, ...)
253 {
254 unsigned long arg;
255 va_list v;
256
257 va_start(v, cmd);
258 arg = va_arg(v, unsigned long);
259 va_end(v);
260
261 return fcntl64(fd, cmd, arg);
262 }
263
264
lseek(int fd,off_t offset,int whence)265 off_t lseek(int fd, off_t offset, int whence)
266 noexcept(noexcept(lseek(fd, offset, whence)))
267 {
268 return lseek64(fd, offset, whence);
269 }
270
ftruncate(int fd,off_t length)271 int ftruncate(int fd, off_t length)
272 noexcept(noexcept(ftruncate(fd, length)))
273 {
274 return ftruncate64(fd, length);
275 }
276
lockf(int fd,int cmd,off_t len)277 int lockf(int fd, int cmd, off_t len)
278 {
279 (void)fd;
280 (void)cmd;
281 (void)len;
282 errno = EINVAL;
283 return -1;
284 }
285
286
287
dup2(int oldfd,int newfd)288 extern "C" int dup2(int oldfd, int newfd)
289 noexcept(noexcept(dup2(oldfd, newfd)))
290 {
291 if (newfd < 0)
292 {
293 errno = EBADF;
294 return -1;
295 }
296
297 Ops *o = L4Re::Vfs::vfs_ops;
298 Ref_ptr<File> oldf = o->get_file(oldfd);
299 if (!oldf)
300 {
301 errno = EBADF;
302 return -1;
303 }
304
305 cxx::Pair<Ref_ptr<File>, int> res = o->set_fd(newfd, oldf);
306 if (res.second)
307 {
308 errno = res.second;
309 return -1;
310 }
311
312 if (!res.first || res.first == oldf)
313 return newfd;
314
315 // do the stuff for close;
316 res.first->unlock_all_locks();
317
318 return newfd;
319 }
320
dup(int oldfd)321 extern "C" int dup(int oldfd)
322 noexcept(noexcept(dup(oldfd)))
323 {
324 Ops *o = L4Re::Vfs::vfs_ops;
325 Ref_ptr<File> f = o->get_file(oldfd);
326 if (!f)
327 {
328 errno = EBADF;
329 return -1;
330 }
331
332 int r = o->alloc_fd(f);
333 ERRNO_RET(r);
334 return r;
335 }
336
337
stat(const char * path,struct stat * buf)338 int stat(const char *path, struct stat *buf)
339 noexcept(noexcept(stat(path, buf)))
340 {
341 struct stat64 sb64;
342 int r = stat64(path, &sb64);
343 if (r < 0)
344 return r;
345
346 copy_stat64_to_stat(buf, &sb64);
347 return r;
348 }
349
lstat(const char * path,struct stat * buf)350 int lstat(const char *path, struct stat *buf)
351 noexcept(noexcept(lstat(path, buf)))
352 {
353 struct stat64 sb64;
354 int r = lstat64(path, &sb64);
355
356 if (r < 0)
357 return r;
358
359 copy_stat64_to_stat(buf, &sb64);
360 return r;
361 }
362
close(int fd)363 int close(int fd)
364 noexcept(noexcept(close(fd)))
365 {
366 Ops *o = L4Re::Vfs::vfs_ops;
367 Ref_ptr<File> f = o->free_fd(fd);
368 if (!f)
369 {
370 errno = EBADF;
371 return -1;
372 }
373
374 f->unlock_all_locks();
375 return 0;
376 }
377
access(const char * path,int mode)378 int access(const char *path, int mode)
379 noexcept(noexcept(access(path, mode)))
380 { return faccessat(AT_FDCWD, path, mode, 0); }
381
382 extern "C" ssize_t __getdents64(int fd, char *buf, size_t nbytes);
__getdents64(int fd,char * buf,size_t nbytes)383 extern "C" ssize_t __getdents64(int fd, char *buf, size_t nbytes)
384 {
385 Ops *o = L4Re::Vfs::vfs_ops;
386 Ref_ptr<File> fdo = o->get_file(fd);
387 if (!fdo)
388 {
389 errno = EBADF;
390 return -1;
391 }
392
393 ssize_t r = fdo->getdents(buf, nbytes);
394 if (r < 0)
395 {
396 errno = -r;
397 return -1;
398 }
399
400 return r;
401 }
402
403 #if __WORDSIZE == 64
404 extern "C" ssize_t __getdents(int, char *, size_t);
L4_STRONG_ALIAS(__getdents64,__getdents)405 L4_STRONG_ALIAS(__getdents64,__getdents)
406 #endif
407
408
409 #define L4B_REDIRECT(ret, func, ptlist, plist) \
410 extern "C" ret func ptlist noexcept(noexcept(func plist)) \
411 { \
412 cxx::Ref_ptr<L4Re::Vfs::File> file; \
413 int res = __internal_resolve(AT_FDCWD, _a1, 0, 0, &file); \
414 ERRNO_RET(res); \
415 ret r = file->L4B_REDIRECT_FUNC(func)(L4B_STRIP_FIRST(plist)); \
416 POST(); \
417 }
418
419 #define L4B_REDIRECT_FUNC(func) func
420 L4B_REDIRECT_3(ssize_t, readlink, const char *, char *, size_t)
421 L4B_REDIRECT_2(int, utime, const char *, const struct utimbuf *)
422 L4B_REDIRECT_2(int, utimes, const char *, const struct timeval *)
423 #undef L4B_REDIRECT_FUNC
424
425 #define L4B_REDIRECT_FUNC(func) f##func
426 L4B_REDIRECT_2(int, stat64, const char *, struct stat64 *)
427 L4B_REDIRECT_2(int, chmod, const char *, mode_t)
428 #undef L4B_REDIRECT_FUNC
429
430 #define L4B_REDIRECT_FUNC(func) fstat64
431 L4B_REDIRECT_2(int, lstat64, const char *, struct stat64 *)
432 #undef L4B_REDIRECT_FUNC
433 #undef L4B_REDIRECT
434
435 #define L4B_REDIRECT(ret, func, ptlist, plist) \
436 extern "C" ret func ptlist noexcept(noexcept(func plist)) \
437 { \
438 cxx::Ref_ptr<L4Re::Vfs::File> dir; \
439 _a1 = __internal_resolvedir(AT_FDCWD, _a1, 0, 0, &dir); \
440 ret r = dir->func plist; \
441 POST(); \
442 }
443
444 L4B_REDIRECT_1(int, unlink, const char *)
445 L4B_REDIRECT_2(int, mkdir, const char *, mode_t)
446 L4B_REDIRECT_1(int, rmdir, const char *)
447 #undef L4B_REDIRECT
448
449 #define L4B_REDIRECT(ret, func, ptlist, plist) \
450 extern "C" ret func ptlist noexcept(noexcept(func plist)) \
451 { \
452 cxx::Ref_ptr<L4Re::Vfs::File> dir1; \
453 cxx::Ref_ptr<L4Re::Vfs::File> dir2; \
454 _a1 = __internal_resolvedir(AT_FDCWD, _a1, 0, 0, &dir1); \
455 _a2 = __internal_resolvedir(AT_FDCWD, _a2, 0, 0, &dir2); \
456 ret r = dir1->func plist; \
457 POST(); \
458 }
459
460 L4B_REDIRECT_2(int, rename, const char *, const char *)
461 L4B_REDIRECT_2(int, link, const char *, const char *)
462 L4B_REDIRECT_2(int, symlink, const char *, const char *)
463 #undef L4B_REDIRECT
464
465 #define L4B_REDIRECT(ret, func, ptlist, plist) \
466 extern "C" ret func ptlist noexcept(noexcept(func plist)) \
467 { \
468 cxx::Ref_ptr<L4Re::Vfs::File> file; \
469 int res = __internal_resolve(AT_FDCWD, _a1, 0, 0, &file); \
470 ERRNO_RET(res); \
471 ret r = file->ftruncate64(L4B_STRIP_FIRST(plist)); \
472 POST(); \
473 }
474
475 L4B_REDIRECT_2(int, truncate, const char *, off_t)
476 L4B_REDIRECT_2(int, truncate64, const char *, off64_t)
477
478 #undef L4B_REDIRECT
479
480 #define L4B_REDIRECT(ret, func, ptlist, plist) \
481 extern "C" ret func ptlist noexcept(noexcept(func plist)) \
482 { \
483 cxx::Ref_ptr<L4Re::Vfs::File> dir; \
484 _a2 = __internal_resolvedir(_a1, _a2, 0, 0, &dir); \
485 if (!_a2) \
486 { \
487 errno = EBADF; \
488 return -1; \
489 } \
490 ret r = dir->func(L4B_STRIP_FIRST(plist)); \
491 POST(); \
492 }
493
494 //L4B_REDIRECT_3(int, unlinkat, int, const char *, int)
495 L4B_REDIRECT_4(int, faccessat, int, const char *, int, int)
496 L4B_REDIRECT_4(int, fchmodat, int, const char *, mode_t, int)
497 L4B_REDIRECT_4(int, utimensat, int, const char *,
498 const struct timespec *, int)
499
500
501 // ------------------------------------------------------
502
503 //#include <stdio.h>
504 #include <l4/util/util.h>
505
506 int select(int nfds, fd_set *readfds, fd_set *writefds,
507 fd_set *exceptfds, struct timeval *timeout)
508 {
509 (void)nfds; (void)readfds; (void)writefds; (void)exceptfds;
510 //printf("Call: %s(%d, %p, %p, %p, %p[%ld])\n", __func__, nfds, readfds, writefds, exceptfds, timeout, timeout->tv_usec + timeout->tv_sec * 1000000);
511
512 #if 0
513 int us = timeout->tv_usec + timeout->tv_sec * 1000000;
514 l4_timeout_t to = l4_timeout(L4_IPC_TIMEOUT_NEVER,
515 l4util_micros2l4to(us));
516 #endif
517
518 // only the timeout for now
519 if (timeout)
520 l4_usleep(timeout->tv_usec + timeout->tv_sec * 1000000);
521 else
522 l4_sleep_forever();
523
524 return 0;
525 }
526
527 #undef L4B_REDIRECT
528
529 #define L4B_REDIRECT(ret, func, ptlist, plist) \
530 ret func ptlist noexcept(noexcept(func plist)) \
531 { \
532 L4Re::Vfs::Ops *o = L4Re::Vfs::vfs_ops; \
533 cxx::Ref_ptr<L4Re::Vfs::File> f = o->get_file(_a1); \
534 if (!f) \
535 { \
536 errno = EBADF; \
537 return -1; \
538 } \
539 ret r = f->func(L4B_STRIP_FIRST(plist)); \
540 POST(); \
541 }
542
543 __BEGIN_DECLS
544 ssize_t preadv(int, const struct iovec *, int, off_t);
545 ssize_t pwritev(int, const struct iovec *, int, off_t);
546 __END_DECLS
547
548 L4B_REDIRECT_2(int, fstat64, int, struct stat64 *)
549 L4B_REDIRECT_3(ssize_t, readv, int, const struct iovec *, int)
550 L4B_REDIRECT_3(ssize_t, writev, int, const struct iovec *, int)
551 L4B_REDIRECT_4(ssize_t, preadv, int, const struct iovec *, int, off_t)
552 L4B_REDIRECT_4(ssize_t, pwritev, int, const struct iovec *, int, off_t)
553 L4B_REDIRECT_3(__off64_t, lseek64, int, __off64_t, int)
554 L4B_REDIRECT_2(int, ftruncate64, int, off64_t)
555 L4B_REDIRECT_1(int, fsync, int)
556 L4B_REDIRECT_1(int, fdatasync, int)
557 L4B_REDIRECT_2(int, fchmod, int, mode_t)
558
559 static char const * const _default_current_working_dir = "/";
560 static char *_current_working_dir = const_cast<char *>(_default_current_working_dir);
561
free_cwd()562 static void free_cwd()
563 {
564 if (_current_working_dir != _default_current_working_dir)
565 free(_current_working_dir);
566 }
567
chdir(const char * path)568 extern "C" int chdir(const char *path) noexcept(noexcept(chdir(path)))
569 {
570 Ref_ptr<File> f;
571 int res = __internal_resolve(AT_FDCWD, path, 0, 0, &f);
572 ERRNO_RET(res);
573
574 if (*path == '/')
575 {
576 char *new_cwd = strdup(path);
577 if (!new_cwd)
578 {
579 errno = ENOMEM;
580 return -1;
581 }
582 free_cwd();
583 _current_working_dir = new_cwd;
584 }
585 else
586 {
587 unsigned len_cwd = strlen(_current_working_dir);
588 unsigned len_path = strlen(path);
589 char *new_cwd = (char *)malloc(len_cwd + len_path + 2);
590 if (!new_cwd)
591 {
592 errno = ENOMEM;
593 return -1;
594 }
595 memcpy(new_cwd, _current_working_dir, len_cwd);
596 if (new_cwd[len_cwd - 1] != '/')
597 new_cwd[len_cwd++] = '/';
598 memcpy(new_cwd + len_cwd, path, len_path + 1);
599
600 free_cwd();
601 _current_working_dir = new_cwd;
602 }
603
604 // would need to check whether 'f' is a directory
605 L4Re::Vfs::vfs_ops->set_cwd(f);
606
607 return 0;
608 }
609
fchdir(int fd)610 extern "C" int fchdir(int fd) noexcept(noexcept(fchdir(fd)))
611 {
612 L4Re::Vfs::Ops *o = L4Re::Vfs::vfs_ops;
613 cxx::Ref_ptr<L4Re::Vfs::File> f = o->get_file(fd);
614 if (!f)
615 {
616 errno = EBADF;
617 return -1;
618 }
619
620 // would need to check whether 'f' is a directory
621 o->set_cwd(f);
622 return 0;
623 }
624
625 extern "C"
pread64(int fd,void * buf,size_t count,off64_t offset)626 ssize_t pread64(int fd, void *buf, size_t count, off64_t offset)
627 {
628 struct iovec iov;
629 iov.iov_base = buf;
630 iov.iov_len = count;
631 return preadv(fd, &iov, 1, offset);
632 }
633
634 extern "C"
pread(int fd,void * buf,size_t count,off_t offset)635 ssize_t pread(int fd, void *buf, size_t count, off_t offset)
636 {
637 return pread64(fd, buf, count, offset);
638 }
639
640 extern "C"
pwrite64(int fd,const void * buf,size_t count,off64_t offset)641 ssize_t pwrite64(int fd, const void *buf, size_t count, off64_t offset)
642 {
643 struct iovec iov;
644 iov.iov_base = const_cast<void*>(buf);
645 iov.iov_len = count;
646 return pwritev(fd, &iov, 1, offset);
647 }
648
649 extern "C"
pwrite(int fd,const void * buf,size_t count,off_t offset)650 ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
651 {
652 return pwrite64(fd, buf, count, offset);
653 }
654
getcwd(char * buf,size_t size)655 extern "C" char *getcwd(char *buf, size_t size)
656 noexcept(noexcept(getcwd(buf, size)))
657 {
658 unsigned len_cwd = strlen(_current_working_dir) + 1;
659
660 /* Posix mandates returning EINVAL if a buffer is supplied without a size */
661 if (buf != 0 && size == 0)
662 {
663 errno = EINVAL;
664 return 0;
665 }
666
667 if (buf == 0 && size == 0)
668 size = len_cwd;
669
670 if (len_cwd > size)
671 {
672 errno = ERANGE;
673 return 0;
674 }
675
676 if (buf == 0)
677 buf = (char *)malloc(size);
678
679 if (buf == 0)
680 {
681 errno = ENOMEM;
682 return 0;
683 }
684
685 memcpy(buf, _current_working_dir, len_cwd);
686 return buf;
687 }
688
chroot(const char * p)689 extern "C" int chroot(const char *p)
690 noexcept(noexcept(chroot(p)))
691 {
692 errno = EIO;
693 return -1;
694 }
695
mkfifo(const char * p,mode_t m)696 extern "C" int mkfifo(const char *p, mode_t m)
697 noexcept(noexcept(mkfifo(p, m)))
698 {
699 /* mkfifo on Linux returns EPERM on unsupported file systems */
700 errno = EPERM;
701 return -1;
702 }
703
mknod(const char * p,mode_t m,dev_t d)704 extern "C" int mknod(const char *p, mode_t m, dev_t d)
705 noexcept(noexcept(mknod(p, m, d)))
706 {
707 errno = EINVAL;
708 return -1;
709 }
710
chown(const char *,uid_t,gid_t)711 int chown(const char *, uid_t, gid_t)
712 {
713 errno = EINVAL;
714 return -1;
715 }
716
fchown(int,uid_t,gid_t)717 int fchown(int, uid_t, gid_t)
718 {
719 errno = EINVAL;
720 return -1;
721 }
722
723
lchown(const char * p,uid_t u,gid_t g)724 extern "C" int lchown(const char *p, uid_t u, gid_t g)
725 noexcept(noexcept(lchown(p, u, g)))
726 {
727 errno = EINVAL;
728 return -1;
729 }
730