blob: 49d77ee1739ed585eb79c0c93c652578de6a1c34 [file] [log] [blame]
The Android Open Source Project52d4c302009-03-03 19:29:09 -08001/*
2 * Copyright 2007 The Android Open Source Project
3 *
4 * Syscall and library intercepts.
5 */
6
7/* don't remap open() to open64() */
8#undef _FILE_OFFSET_BITS
9
10#define CREATE_FUNC_STORAGE
11#include "Common.h"
12
13#include <stdlib.h>
14#include <string.h>
15#include <stdarg.h>
16#include <unistd.h>
17#include <fcntl.h>
18#include <sys/uio.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <sys/time.h>
22#include <sys/resource.h>
23#include <utime.h>
24#include <limits.h>
25#include <ftw.h>
26#include <assert.h>
27
28
29#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64
30#warning "big"
31#endif
32
33//#define CALLTRACE(format, ...) wsLog(format, ##__VA_ARGS__)
34#define CALLTRACE(format, ...) ((void)0)
35
36//#define CALLTRACEV(format, ...) wsLog(format, ##__VA_ARGS__)
37#define CALLTRACEV(format, ...) ((void)0)
38
39/*
40When opening certain files, we need to simulate the contents. For example,
41we can pretend to open the frame buffer, and respond to ioctl()s by
42returning fake data or telling the front-end to render new data.
43
44We want to intercept specific files in /dev. In some cases we want to
45intercept and reject, e.g. to indicate that a standard Linux device does
46not exist.
47
48Some things we're not going to intercept:
49 /etc/... (e.g. /etc/timezone) -- std. Linux version should be okay
50 /proc/... (e.g. /proc/stat) -- we're showing real pid, so real proc will work
51
52For the device drivers we need to intercept:
53
54 close(), ioctl(), mmap(), open()/open64(), read(), readv(), write(),
55 writev()
56
57May also need stat(). We don't need all fd calls, e.g. fchdir() is
58not likely to succeed on a device driver. The expected uses of mmap()
59shouldn't require intercepting related calls like madvise() -- we will
60provide an actual mapping of the requested size. In some cases we will
61want to return a "real" fd so the app can poll() or select() on it.
62
63
64We also need to consider:
65 getuid/setuid + variations -- fake out multi-user-id stuff
66
67
68We also want to translate filenames, effectively performing a "chroot"
69without all the baggage that comes with it. The mapping looks like:
70
71 /system/... --> $ANDROID_PRODUCT_OUT/system/...
72 /data/... --> $ANDROID_PRODUCT_OUT/data/...
73
74Translating pathnames requires interception of additional system calls,
75substituting a new path. Calls include:
76
77 access(), chdir(), chmod(), chown(), creat(), execve(), getcwd(),
78 lchown(), link(), lstat()/lstat64(), mkdir(), open()/open64(),
79 readlink(), rename(), rmdir(), stat()/stat64(), statfs/statfs64(),
80 symlink(), unlink(), utimes(),
81
82Possibly also mknod(), mount(), umount().
83
84The "at" family, notably openat(), should just work since the root comes
85from an open directory fd.
86
87We also need these libc calls, because LD_LIBRARY_PATH substitutes at
88the libc link level, not the syscall layer:
89
90 execl(), execlp(), execle(), execv(), execvp(), fopen(), ftw(), getwd(),
91 opendir(), dlopen()
92
93It is possible for the cwd to leak out. Some possible leaks:
94 - /proc/[self]/exe
95 - /proc/[self]/cwd
96 - LD_LIBRARY_PATH (which may be awkward to work around)
97
98
99To provide a replacement for the dirent functions -- only required if we
100want to show "fake" directory contents -- we would need:
101
102 closedir(), dirfd() readdir(), rewinddir(), scandir(), seekdir(),
103 telldir()
104
105
106*/
107
108
109/*
110 * ===========================================================================
111 * Filename remapping
112 * ===========================================================================
113 */
114
115/*
116 * If appropriate, rewrite the path to point to a different location.
117 *
118 * Returns either "pathBuf" or "origPath" depending on whether or not we
119 * chose to rewrite the path. "origPath" must be a buffer capable of
120 * holding an extended pathname; for best results use PATH_MAX.
121 */
122static const char* rewritePath(const char* func, char* pathBuf,
123 const char* origPath)
124{
125 /*
126 * Rewrite paths that start with "/system/" or "/data/"
127 */
128 if (origPath[0] != '/')
129 goto skip_rewrite;
Marco Nelissen47acf132009-05-05 14:54:14 -0700130 while (origPath[1] == '/') origPath++; // some apps like to use paths like '//data/data/....'
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800131 if (memcmp(origPath+1, "system", 6) == 0 &&
132 (origPath[7] == '/' || origPath[7] == '\0'))
133 goto do_rewrite;
134 if (memcmp(origPath+1, "data", 4) == 0 &&
135 (origPath[5] == '/' || origPath[5] == '\0'))
136 goto do_rewrite;
137
138skip_rewrite:
139 /* check to see if something is side-stepping the rewrite */
140 if (memcmp(origPath, gWrapSim.remapBaseDir, gWrapSim.remapBaseDirLen) == 0)
141 {
142 wsLog("NOTE: full path used: %s(%s)\n", func, origPath);
143 }
144
145 CALLTRACE("rewrite %s('%s') --> (not rewritten)\n", func, origPath);
146 return origPath;
147
148do_rewrite:
149 memcpy(pathBuf, gWrapSim.remapBaseDir, gWrapSim.remapBaseDirLen);
150 strcpy(pathBuf + gWrapSim.remapBaseDirLen, origPath);
151 CALLTRACE("rewrite %s('%s') --> '%s'\n", func, origPath, pathBuf);
152 return pathBuf;
153}
154
155/*
156 * This works if the pathname is the first argument to the function, and
157 * the function returns "int".
158 */
159#define PASS_THROUGH_DECL(_fname, _rtype, ...) \
160 _rtype _fname( __VA_ARGS__ )
161#define PASS_THROUGH_BODY(_fname, _patharg, ...) \
162 { \
163 CALLTRACEV("%s\n", __FUNCTION__); \
164 char pathBuf[PATH_MAX]; \
165 return _ws_##_fname(rewritePath(#_fname, pathBuf, _patharg), \
166 ##__VA_ARGS__); \
167 }
168
169
170PASS_THROUGH_DECL(chdir, int, const char* path)
171PASS_THROUGH_BODY(chdir, path)
172
173PASS_THROUGH_DECL(chmod, int, const char* path, mode_t mode)
174PASS_THROUGH_BODY(chmod, path, mode)
175
176PASS_THROUGH_DECL(chown, int, const char* path, uid_t owner, gid_t group)
177PASS_THROUGH_BODY(chown, path, owner, group)
178
179PASS_THROUGH_DECL(creat, int, const char* path, mode_t mode)
180PASS_THROUGH_BODY(creat, path, mode)
181
182PASS_THROUGH_DECL(execve, int, const char* path, char* const argv[],
183 char* const envp[])
184PASS_THROUGH_BODY(execve, path, argv, envp)
185
186PASS_THROUGH_DECL(lchown, int, const char* path, uid_t owner, gid_t group)
187PASS_THROUGH_BODY(lchown, path, owner, group)
188
189PASS_THROUGH_DECL(lstat, int, const char* path, struct stat* buf)
190PASS_THROUGH_BODY(lstat, path, buf)
191
192PASS_THROUGH_DECL(lstat64, int, const char* path, struct stat* buf)
193PASS_THROUGH_BODY(lstat64, path, buf)
194
195PASS_THROUGH_DECL(mkdir, int, const char* path, mode_t mode)
196PASS_THROUGH_BODY(mkdir, path, mode)
197
198PASS_THROUGH_DECL(readlink, ssize_t, const char* path, char* buf, size_t bufsiz)
199PASS_THROUGH_BODY(readlink, path, buf, bufsiz)
200
201PASS_THROUGH_DECL(rmdir, int, const char* path)
202PASS_THROUGH_BODY(rmdir, path)
203
204PASS_THROUGH_DECL(stat, int, const char* path, struct stat* buf)
205PASS_THROUGH_BODY(stat, path, buf)
206
207PASS_THROUGH_DECL(stat64, int, const char* path, struct stat* buf)
208PASS_THROUGH_BODY(stat64, path, buf)
209
210PASS_THROUGH_DECL(statfs, int, const char* path, struct statfs* buf)
211PASS_THROUGH_BODY(statfs, path, buf)
212
213PASS_THROUGH_DECL(statfs64, int, const char* path, struct statfs* buf)
214PASS_THROUGH_BODY(statfs64, path, buf)
215
216PASS_THROUGH_DECL(unlink, int, const char* path)
217PASS_THROUGH_BODY(unlink, path)
218
219PASS_THROUGH_DECL(utime, int, const char* path, const struct utimbuf* buf)
220PASS_THROUGH_BODY(utime, path, buf)
221
222PASS_THROUGH_DECL(utimes, int, const char* path, const struct timeval times[2])
223PASS_THROUGH_BODY(utimes, path, times)
224
225
226PASS_THROUGH_DECL(fopen, FILE*, const char* path, const char* mode)
227PASS_THROUGH_BODY(fopen, path, mode)
228
229PASS_THROUGH_DECL(fopen64, FILE*, const char* path, const char* mode)
230PASS_THROUGH_BODY(fopen64, path, mode)
231
232PASS_THROUGH_DECL(freopen, FILE*, const char* path, const char* mode,
233 FILE* stream)
234PASS_THROUGH_BODY(freopen, path, mode, stream)
235
236PASS_THROUGH_DECL(ftw, int, const char* dirpath,
237 int (*fn) (const char* fpath, const struct stat* sb, int typeflag),
238 int nopenfd)
239PASS_THROUGH_BODY(ftw, dirpath, fn, nopenfd)
240
241PASS_THROUGH_DECL(opendir, DIR*, const char* path)
242PASS_THROUGH_BODY(opendir, path)
243
244PASS_THROUGH_DECL(dlopen, void*, const char* path, int flag)
245PASS_THROUGH_BODY(dlopen, path, flag)
246
247/*
248 * Opposite of path translation -- remove prefix.
249 *
250 * It looks like BSD allows you to pass a NULL value for "buf" to inspire
251 * getcwd to allocate storage with malloc() (as an extension to the POSIX
252 * definition, which doesn't specify this). getcwd() is a system call
253 * under Linux, so this doesn't work, but that doesn't stop gdb from
254 * trying to use it anyway.
255 */
256char* getcwd(char* buf, size_t size)
257{
258 CALLTRACEV("%s %p %d\n", __FUNCTION__, buf, size);
259
260 char* result = _ws_getcwd(buf, size);
261 if (buf != NULL && result != NULL) {
262 if (memcmp(buf, gWrapSim.remapBaseDir,
263 gWrapSim.remapBaseDirLen) == 0)
264 {
265 memmove(buf, buf + gWrapSim.remapBaseDirLen,
266 strlen(buf + gWrapSim.remapBaseDirLen)+1);
267 CALLTRACE("rewrite getcwd() -> %s\n", result);
268 } else {
269 CALLTRACE("not rewriting getcwd(%s)\n", result);
270 }
271 }
272 return result;
273}
274
275/*
276 * Need to tweak both pathnames.
277 */
278int link(const char* oldPath, const char* newPath)
279{
280 CALLTRACEV("%s\n", __FUNCTION__);
281
282 char pathBuf1[PATH_MAX];
283 char pathBuf2[PATH_MAX];
284 return _ws_link(rewritePath("link-1", pathBuf1, oldPath),
285 rewritePath("link-2", pathBuf2, newPath));
286}
287
288/*
289 * Need to tweak both pathnames.
290 */
291int rename(const char* oldPath, const char* newPath)
292{
293 CALLTRACEV("%s\n", __FUNCTION__);
294
295 char pathBuf1[PATH_MAX];
296 char pathBuf2[PATH_MAX];
297 return _ws_rename(rewritePath("rename-1", pathBuf1, oldPath),
298 rewritePath("rename-2", pathBuf2, newPath));
299}
300
301/*
302 * Need to tweak both pathnames.
303 */
304int symlink(const char* oldPath, const char* newPath)
305{
306 CALLTRACEV("%s\n", __FUNCTION__);
307
308 char pathBuf1[PATH_MAX];
309 char pathBuf2[PATH_MAX];
310 return _ws_symlink(rewritePath("symlink-1", pathBuf1, oldPath),
311 rewritePath("symlink-2", pathBuf2, newPath));
312}
313
314/*
315 * glibc stat turns into this (32-bit).
316 */
317int __xstat(int version, const char* path, struct stat* sbuf)
318{
319 CALLTRACEV("%s\n", __FUNCTION__);
320 char pathBuf[PATH_MAX];
321 return _ws___xstat(version, rewritePath("__xstat", pathBuf, path),
322 sbuf);
323}
324
325/*
326 * glibc stat turns into this (64-bit).
327 */
328int __xstat64(int version, const char* path, struct stat* sbuf)
329{
330 CALLTRACEV("%s\n", __FUNCTION__);
331 char pathBuf[PATH_MAX];
332 return _ws___xstat64(version, rewritePath("__xstat64", pathBuf, path),
333 sbuf);
334}
335
336/*
337 * glibc lstat turns into this (32-bit).
338 */
339int __lxstat(int version, const char* path, struct stat* sbuf)
340{
341 CALLTRACEV("%s\n", __FUNCTION__);
342 char pathBuf[PATH_MAX];
343 return _ws___lxstat(version, rewritePath("__lxstat", pathBuf, path),
344 sbuf);
345}
346
347/*
348 * glibc lstat turns into this (64-bit).
349 */
350int __lxstat64(int version, const char* path, struct stat* sbuf)
351{
352 CALLTRACEV("%s\n", __FUNCTION__);
353 char pathBuf[PATH_MAX];
354 return _ws___lxstat64(version, rewritePath("__lxstat64", pathBuf, path),
355 sbuf);
356}
357
358/*
359 * Copy the argument list out of varargs for execl/execlp/execle. This
360 * leaves the argc value in _argc, and a NULL-terminated array of character
361 * pointers in _argv. We stop at the first NULL argument, so we shouldn't
362 * end up copying "envp" out.
363 *
364 * We could use gcc __builtin_apply_args to just pass stuff through,
365 * but that may not get along with the path rewriting. It's unclear
366 * whether we want to rewrite the first argument (i.e. the string that
367 * becomes argv[0]); it only makes sense if the exec'ed program is also
368 * getting remapped.
369 */
370#define COPY_EXEC_ARGLIST(_first, _argc, _argv) \
371 int _argc = 0; \
372 { \
373 va_list vargs; \
374 va_start(vargs, _first); \
375 while (1) { \
376 _argc++; \
377 const char* val = va_arg(vargs, const char*); \
378 if (val == NULL) \
379 break; \
380 } \
381 va_end(vargs); \
382 } \
383 const char* _argv[_argc+1]; \
384 _argv[0] = _first; \
385 { \
386 va_list vargs; \
387 int i; \
388 va_start(vargs, _first); \
389 for (i = 1; i < _argc; i++) { \
390 _argv[i] = va_arg(vargs, const char*); \
391 } \
392 va_end(vargs); \
393 } \
394 _argv[_argc] = NULL;
395
396/*
397 * Debug dump.
398 */
399static void dumpExecArgs(const char* callName, const char* path,
400 int argc, const char* argv[], char* const envp[])
401{
402 int i;
403
404 CALLTRACE("Calling %s '%s' (envp=%p)\n", callName, path, envp);
405 for (i = 0; i <= argc; i++)
406 CALLTRACE(" %d: %s\n", i, argv[i]);
407}
408
409/*
410 * Extract varargs, convert paths, hand off to execv.
411 */
412int execl(const char* path, const char* arg, ...)
413{
414 CALLTRACEV("%s\n", __FUNCTION__);
415
416 char pathBuf[PATH_MAX];
417
418 COPY_EXEC_ARGLIST(arg, argc, argv);
419 dumpExecArgs("execl", path, argc, argv, NULL);
420 path = rewritePath("execl", pathBuf, path);
421 return _ws_execv(path, (char* const*) argv);
422}
423
424/*
425 * Extract varargs, convert paths, hand off to execve.
426 *
427 * The execle prototype in the man page isn't valid C -- it shows the
428 * "envp" argument after the "...". We have to pull it out with the rest
429 * of the varargs.
430 */
431int execle(const char* path, const char* arg, ...)
432{
433 CALLTRACEV("%s\n", __FUNCTION__);
434
435 char pathBuf[PATH_MAX];
436
437 COPY_EXEC_ARGLIST(arg, argc, argv);
438
439 /* run through again and find envp */
440 char* const* envp;
441
442 va_list vargs;
443 va_start(vargs, arg);
444 while (1) {
445 const char* val = va_arg(vargs, const char*);
446 if (val == NULL) {
447 envp = va_arg(vargs, char* const*);
448 break;
449 }
450 }
451 va_end(vargs);
452
453 dumpExecArgs("execle", path, argc, argv, envp);
454 path = rewritePath("execl", pathBuf, path);
455
456 return _ws_execve(path, (char* const*) argv, envp);
457}
458
459/*
460 * Extract varargs, convert paths, hand off to execvp.
461 */
462int execlp(const char* file, const char* arg, ...)
463{
464 CALLTRACEV("%s\n", __FUNCTION__);
465
466 char pathBuf[PATH_MAX];
467
468 COPY_EXEC_ARGLIST(arg, argc, argv);
469 dumpExecArgs("execlp", file, argc, argv, NULL);
470 file = rewritePath("execlp", pathBuf, file);
471 return _ws_execvp(file, (char* const*) argv);
472}
473
474/*
475 * Update path, forward to execv.
476 */
477int execv(const char* path, char* const argv[])
478{
479 CALLTRACEV("%s\n", __FUNCTION__);
480
481 char pathBuf[PATH_MAX];
482
483 path = rewritePath("execv", pathBuf, path);
484 return _ws_execv(path, argv);
485}
486
487/*
488 * Shouldn't need to do anything unless they specified a full path to execvp.
489 */
490int execvp(const char* file, char* const argv[])
491{
492 CALLTRACEV("%s\n", __FUNCTION__);
493
494 char pathBuf[PATH_MAX];
495
496 file = rewritePath("execvp", pathBuf, file);
497 return _ws_execvp(file, argv);
498}
499
500
501/*
502 * ===========================================================================
503 * Device fakery
504 * ===========================================================================
505 */
506
507/*
508 * Need to do filesystem translation and show fake devices.
509 */
510int access(const char* pathName, int mode)
511{
512 CALLTRACEV("%s\n", __FUNCTION__);
513
514 int status = wsInterceptDeviceAccess(pathName, mode);
515 if (status == 0)
516 return 0;
517 else if (status == -2)
518 return -1; // errno already set
519 else {
520 char pathBuf[PATH_MAX];
521 return _ws_access(rewritePath("access", pathBuf, pathName), mode);
522 }
523}
524
525/*
526 * Common handler for open().
527 */
528int openCommon(const char* pathName, int flags, mode_t mode)
529{
530 char pathBuf[PATH_MAX];
531 int fd;
532
533 assert(gWrapSim.initialized);
534
535 fd = wsInterceptDeviceOpen(pathName, flags);
536 if (fd >= 0) {
537 return fd;
538 } else if (fd == -2) {
539 /* errno should be set */
540 return -1;
541 }
542
543 if ((flags & O_CREAT) != 0) {
544 fd = _ws_open(rewritePath("open", pathBuf, pathName), flags, mode);
545 CALLTRACE("open(%s, 0x%x, 0%o) = %d\n", pathName, flags, mode, fd);
546 } else {
547 fd = _ws_open(rewritePath("open", pathBuf, pathName), flags, 0);
548 CALLTRACE("open(%s, 0x%x) = %d\n", pathName, flags, fd);
549 }
550 return fd;
551}
552
553/*
554 * Replacement open() and variants.
555 *
556 * We have to use the vararg decl for the standard call so it matches
557 * the definition in fcntl.h.
558 */
559int open(const char* pathName, int flags, ...)
560{
561 CALLTRACEV("%s\n", __FUNCTION__);
562
563 mode_t mode = 0;
564 if ((flags & O_CREAT) != 0) {
565 va_list args;
566
567 va_start(args, flags);
568 mode = va_arg(args, mode_t);
569 va_end(args);
570 }
571
572 return openCommon(pathName, flags, mode);
573}
574int __open(const char* pathName, int flags, mode_t mode)
575{
576 CALLTRACEV("%s\n", __FUNCTION__);
577
578 return openCommon(pathName, flags, mode);
579}
580
581/*
582 * Common handler for open64().
583 */
584int open64Common(const char* pathName, int flags, mode_t mode)
585{
586 char pathBuf[PATH_MAX];
587 int fd;
588
589 assert(gWrapSim.initialized);
590
591 fd = wsInterceptDeviceOpen(pathName, flags);
592 if (fd >= 0) {
593 return fd;
594 }
595
596 if ((flags & O_CREAT) != 0) {
597 fd = _ws_open64(rewritePath("open64", pathBuf, pathName), flags, mode);
598 CALLTRACE("open64(%s, 0x%x, 0%o) = %d\n", pathName, flags, mode, fd);
599 } else {
600 fd = _ws_open64(rewritePath("open64", pathBuf, pathName), flags, 0);
601 CALLTRACE("open64(%s, 0x%x) = %d\n", pathName, flags, fd);
602 }
603 return fd;
604}
605
606/*
607 * Replacement open64() and variants.
608 *
609 * We have to use the vararg decl for the standard call so it matches
610 * the definition in fcntl.h.
611 */
612int open64(const char* pathName, int flags, ...)
613{
614 CALLTRACEV("%s\n", __FUNCTION__);
615
616 mode_t mode = 0;
617 if ((flags & O_CREAT) != 0) {
618 va_list args;
619
620 va_start(args, flags);
621 mode = va_arg(args, mode_t);
622 va_end(args);
623 }
624 return open64Common(pathName, flags, mode);
625}
626int __open64(const char* pathName, int flags, mode_t mode)
627{
628 CALLTRACEV("%s\n", __FUNCTION__);
629
630 return open64Common(pathName, flags, mode);
631}
632
633
634/*
635 * Close a file descriptor.
636 */
637int close(int fd)
638{
639 CALLTRACEV("%s(%d)\n", __FUNCTION__, fd);
640
641 FakeDev* dev = wsFakeDevFromFd(fd);
642 if (dev != NULL) {
643 int result = dev->close(dev, fd);
644 wsFreeFakeDev(dev);
645 return result;
646 } else {
647 CALLTRACE("close(%d)\n", fd);
648 return _ws_close(fd);
649 }
650}
651
652/*
653 * Map a region.
654 */
655void* mmap(void* start, size_t length, int prot, int flags, int fd,
656 __off_t offset)
657{
658 CALLTRACEV("%s\n", __FUNCTION__);
659
660 FakeDev* dev = wsFakeDevFromFd(fd);
661 if (dev != NULL) {
662 return dev->mmap(dev, start, length, prot, flags, fd, offset);
663 } else {
664 CALLTRACE("mmap(%p, %d, %d, %d, %d, %d)\n",
665 start, (int) length, prot, flags, fd, (int) offset);
666 return _ws_mmap(start, length, prot, flags, fd, offset);
667 }
668}
669
670/*
671 * Map a region.
672 */
673void* mmap64(void* start, size_t length, int prot, int flags, int fd,
674 __off64_t offset)
675{
676 CALLTRACEV("%s\n", __FUNCTION__);
677
678 FakeDev* dev = wsFakeDevFromFd(fd);
679 if (dev != NULL) {
680 return dev->mmap(dev, start, length, prot, flags, fd, (__off_t) offset);
681 } else {
682 CALLTRACE("mmap64(%p, %d, %d, %d, %d, %d)\n",
683 start, (int) length, prot, flags, fd, (int) offset);
684 return _ws_mmap(start, length, prot, flags, fd, offset);
685 }
686}
687
688/*
689 * The Linux headers show this with a vararg header, but as far as I can
690 * tell the kernel always expects 3 args.
691 */
692int ioctl(int fd, int request, ...)
693{
694 CALLTRACEV("%s(%d, %d, ...)\n", __FUNCTION__, fd, request);
695
696 FakeDev* dev = wsFakeDevFromFd(fd);
697 va_list args;
698 void* argp;
699
700 /* extract argp from varargs */
701 va_start(args, request);
702 argp = va_arg(args, void*);
703 va_end(args);
704
705 if (dev != NULL) {
706 return dev->ioctl(dev, fd, request, argp);
707 } else {
708 CALLTRACE("ioctl(%d, 0x%x, %p)\n", fd, request, argp);
709 return _ws_ioctl(fd, request, argp);
710 }
711}
712
713/*
714 * Read data.
715 */
716ssize_t read(int fd, void* buf, size_t count)
717{
718 CALLTRACEV("%s\n", __FUNCTION__);
719
720 FakeDev* dev = wsFakeDevFromFd(fd);
721 if (dev != NULL) {
722 return dev->read(dev, fd, buf, count);
723 } else {
724 CALLTRACE("read(%d, %p, %u)\n", fd, buf, count);
725 return _ws_read(fd, buf, count);
726 }
727}
728
729/*
730 * Write data.
731 */
732ssize_t write(int fd, const void* buf, size_t count)
733{
734 CALLTRACEV("%s\n", __FUNCTION__);
735
736 FakeDev* dev = wsFakeDevFromFd(fd);
737 if (dev != NULL) {
738 return dev->write(dev, fd, buf, count);
739 } else {
740 CALLTRACE("write(%d, %p, %u)\n", fd, buf, count);
741 return _ws_write(fd, buf, count);
742 }
743}
744
745/*
746 * Read a data vector.
747 */
748ssize_t readv(int fd, const struct iovec* vector, int count)
749{
750 CALLTRACEV("%s\n", __FUNCTION__);
751
752 FakeDev* dev = wsFakeDevFromFd(fd);
753 if (dev != NULL) {
754 return dev->readv(dev, fd, vector, count);
755 } else {
756 CALLTRACE("readv(%d, %p, %u)\n", fd, vector, count);
757 return _ws_readv(fd, vector, count);
758 }
759}
760
761/*
762 * Write a data vector.
763 */
764ssize_t writev(int fd, const struct iovec* vector, int count)
765{
766 CALLTRACEV("%s\n", __FUNCTION__);
767
768 FakeDev* dev = wsFakeDevFromFd(fd);
769 if (dev != NULL) {
770 return dev->writev(dev, fd, vector, count);
771 } else {
772 CALLTRACE("writev(%d, %p, %u)\n", fd, vector, count);
773 return _ws_writev(fd, vector, count);
774 }
775}
776
777/*
778 * Set the scheduling priority. The sim doesn't run as root, so we have
779 * to fake this out.
780 *
781 * For now, do some basic verification of the which and who parameters,
782 * but otherwise return success. In the future we may want to track
783 * these so getpriority works.
784 */
785int setpriority(__priority_which_t which, id_t who, int what)
786{
787 CALLTRACEV("%s\n", __FUNCTION__);
788
789 if (which != PRIO_PROCESS &&
790 which != PRIO_PGRP &&
791 which != PRIO_USER) {
792 return EINVAL;
793 }
794
795 if ((int)who < 0) {
796 return ESRCH;
797 }
798
799 return 0;
800}
801
802#if 0
803/*
804 * Create a pipe. (Only needed for debugging an fd leak.)
805 */
806int pipe(int filedes[2])
807{
808 CALLTRACEV("%s\n", __FUNCTION__);
809
810 int result = _ws_pipe(filedes);
811 if (result == 0)
812 CALLTRACE("pipe(%p) -> %d,%d\n", filedes, filedes[0], filedes[1]);
813 if (filedes[0] == 83)
814 abort();
815 return result;
816}
817#endif