diff options
Diffstat (limited to 'ports')
223 files changed, 6627 insertions, 0 deletions
diff --git a/ports/common/guts/execl.c b/ports/common/guts/execl.c new file mode 100644 index 0000000..be86b49 --- /dev/null +++ b/ports/common/guts/execl.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int execl(const char *file, const char *arg, va_list ap) + * int rc = -1; + */ + + /* NOTE THAT THIS IS NEVER USED! + * We implement all execl() in terms of execv() + * so this call is not used. + */ + + rc = real_execl(file, arg, ap); + +/* return rc; + * } + */ diff --git a/ports/common/guts/execle.c b/ports/common/guts/execle.c new file mode 100644 index 0000000..a3bc3ca --- /dev/null +++ b/ports/common/guts/execle.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int execle(const char *file, const char *arg, va_list ap) + * int rc = -1; + */ + + /* NOTE THAT THIS IS NEVER USED! + * We implement all execl() in terms of execv() + * so this call is not used. + */ + + rc = real_execle(file, arg, ap); + +/* return rc; + * } + */ diff --git a/ports/common/guts/execlp.c b/ports/common/guts/execlp.c new file mode 100644 index 0000000..3cf2889 --- /dev/null +++ b/ports/common/guts/execlp.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int execlp(const char *file, const char *arg, va_list ap) + * int rc = -1; + */ + + /* NOTE THAT THIS IS NEVER USED! + * We implement all execl() in terms of execv() + * so this call is not used. + */ + + rc = real_execlp(file, arg, ap); + +/* return rc; + * } + */ diff --git a/ports/common/guts/execv.c b/ports/common/guts/execv.c new file mode 100644 index 0000000..ba1ce65 --- /dev/null +++ b/ports/common/guts/execv.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_execv(const char *file, char *const *argv) { + * int rc = -1; + */ + /* note: we don't canonicalize this, because we are intentionally + * NOT redirecting execs into the chroot environment. If you try + * to execute /bin/sh, you get the actual /bin/sh, not + * <CHROOT>/bin/sh. This allows use of basic utilities. This + * design will likely be revisited. + */ + if (antimagic == 0) { + const char *path_guess = pseudo_exec_path(file, 0); + pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, path_guess, 0); + } + + pseudo_setupenv(); + if (pseudo_has_unload(NULL)) + pseudo_dropenv(); + + /* if exec() fails, we may end up taking signals unexpectedly... + * not much we can do about that. + */ + sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL); + rc = real_execv(file, argv); + +/* return rc; + * } + */ diff --git a/ports/common/guts/execve.c b/ports/common/guts/execve.c new file mode 100644 index 0000000..24cc177 --- /dev/null +++ b/ports/common/guts/execve.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_execve(const char *file, char *const *argv, char *const *envp) { + * int rc = -1; + */ + char * const *new_environ; + /* note: we don't canonicalize this, because we are intentionally + * NOT redirecting execs into the chroot environment. If you try + * to execute /bin/sh, you get the actual /bin/sh, not + * <CHROOT>/bin/sh. This allows use of basic utilities. This + * design will likely be revisited. + */ + if (antimagic == 0) { + const char *path_guess = pseudo_exec_path(file, 0); + pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, path_guess, 0); + } + + new_environ = pseudo_setupenvp(envp); + if (pseudo_has_unload(new_environ)) + new_environ = pseudo_dropenvp(new_environ); + + /* if exec() fails, we may end up taking signals unexpectedly... + * not much we can do about that. + */ + sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL); + rc = real_execve(file, argv, new_environ); + +/* return rc; + * } + */ diff --git a/ports/common/guts/execvp.c b/ports/common/guts/execvp.c new file mode 100644 index 0000000..e6bf09f --- /dev/null +++ b/ports/common/guts/execvp.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_execvp(const char *file, char *const *argv) { + * int rc = -1; + */ + + /* note: we don't canonicalize this, because we are intentionally + * NOT redirecting execs into the chroot environment. If you try + * to execute /bin/sh, you get the actual /bin/sh, not + * <CHROOT>/bin/sh. This allows use of basic utilities. This + * design will likely be revisited. + */ + if (antimagic == 0) { + const char *path_guess = pseudo_exec_path(file, 1); + pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, path_guess, 0); + } + + pseudo_setupenv(); + if (pseudo_has_unload(NULL)) + pseudo_dropenv(); + + /* if exec() fails, we may end up taking signals unexpectedly... + * not much we can do about that. + */ + sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL); + rc = real_execvp(file, argv); + +/* return rc; + * } + */ diff --git a/ports/common/guts/fork.c b/ports/common/guts/fork.c new file mode 100644 index 0000000..bebe3b0 --- /dev/null +++ b/ports/common/guts/fork.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_fork(void) { + * int rc = -1; + */ + rc = real_fork(); + /* special case: we may want to enable or disable + * pseudo in the child process + */ + if (rc == 0) { + pseudo_setupenv(); + if (!pseudo_has_unload(NULL)) { + pseudo_reinit_libpseudo(); + } else { + pseudo_dropenv(); + } + } +/* return rc; + * } + */ diff --git a/ports/common/pseudo_wrappers.c b/ports/common/pseudo_wrappers.c new file mode 100644 index 0000000..81be635 --- /dev/null +++ b/ports/common/pseudo_wrappers.c @@ -0,0 +1,408 @@ +/* these aren't used, but the wrapper table isn't happy unless they + * exist + */ +static int +wrap_execl(const char *file, const char *arg, va_list ap) { + (void) file; + (void) arg; + (void) ap; + return 0; +} + +static int +wrap_execle(const char *file, const char *arg, va_list ap) { + (void) file; + (void) arg; + (void) ap; + return 0; +} + +static int +wrap_execlp(const char *file, const char *arg, va_list ap) { + (void) file; + (void) arg; + (void) ap; + return 0; +} + +static char ** +execl_to_v(va_list ap, const char *argv0, char *const **envp) { + size_t i = 0; + size_t alloc_size = 256; + + char **argv = malloc((sizeof *argv) * alloc_size); + + if (!argv) { + pseudo_debug(PDBGF_CLIENT, "execl failed: couldn't allocate memory for %lu arguments\n", + (unsigned long) alloc_size); + return NULL; + } + argv[i++] = (char *) argv0; + + while (argv[i-1]) { + argv[i++] = va_arg(ap, char *const); + if (i > alloc_size - 1) { + alloc_size = alloc_size + 256; + argv = realloc(argv, (sizeof *argv) * alloc_size); + if (!argv) { + pseudo_debug(PDBGF_CLIENT, "execl failed: couldn't allocate memory for %lu arguments\n", + (unsigned long) alloc_size); + return NULL; + } + } + } + if (envp) { + *envp = va_arg(ap, char **); + } + return argv; +} + +/* The following wrappers require Special Handling */ + +int +execl(const char *file, const char *arg, ...) { + sigset_t saved; + va_list ap; + char **argv; + + int rc = -1; + + PROFILE_START; + + if (!pseudo_check_wrappers()) { + /* rc was initialized to the "failure" value */ + pseudo_enosys("execl"); + PROFILE_DONE; + return rc; + } + + va_start(ap, arg); + argv = execl_to_v(ap, arg, 0); + va_end(ap); + if (!argv) { + errno = ENOMEM; + PROFILE_DONE; + return -1; + } + + pseudo_debug(PDBGF_WRAPPER, "called: execl\n"); + pseudo_sigblock(&saved); + if (pseudo_getlock()) { + errno = EBUSY; + sigprocmask(SIG_SETMASK, &saved, NULL); + PROFILE_DONE; + return -1; + } + + int save_errno; + + /* exec*() use this to restore the sig mask */ + pseudo_saved_sigmask = saved; + rc = wrap_execv(file, argv); + + save_errno = errno; + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(PDBGF_WRAPPER, "completed: execl\n"); + errno = save_errno; + free(argv); + PROFILE_DONE; + return rc; +} + +int +execlp(const char *file, const char *arg, ...) { + sigset_t saved; + va_list ap; + char **argv; + + int rc = -1; + PROFILE_START; + + if (!pseudo_check_wrappers()) { + /* rc was initialized to the "failure" value */ + pseudo_enosys("execlp"); + PROFILE_DONE; + return rc; + } + + va_start(ap, arg); + argv = execl_to_v(ap, arg, 0); + va_end(ap); + if (!argv) { + errno = ENOMEM; + PROFILE_DONE; + return -1; + } + + pseudo_debug(PDBGF_WRAPPER, "called: execlp\n"); + pseudo_sigblock(&saved); + if (pseudo_getlock()) { + errno = EBUSY; + sigprocmask(SIG_SETMASK, &saved, NULL); + PROFILE_DONE; + return -1; + } + + int save_errno; + + /* exec*() use this to restore the sig mask */ + pseudo_saved_sigmask = saved; + rc = wrap_execvp(file, argv); + + save_errno = errno; + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(PDBGF_WRAPPER, "completed: execlp\n"); + errno = save_errno; + free(argv); + PROFILE_DONE; + return rc; +} + +int +execle(const char *file, const char *arg, ...) { + sigset_t saved; + va_list ap; + char **argv; + char **envp; + + int rc = -1; + PROFILE_START; + + if (!pseudo_check_wrappers()) { + /* rc was initialized to the "failure" value */ + pseudo_enosys("execle"); + PROFILE_DONE; + return rc; + } + + va_start(ap, arg); + argv = execl_to_v(ap, arg, (char *const **)&envp); + va_end(ap); + if (!argv) { + errno = ENOMEM; + PROFILE_DONE; + return -1; + } + + pseudo_debug(PDBGF_WRAPPER, "called: execle\n"); + pseudo_sigblock(&saved); + if (pseudo_getlock()) { + errno = EBUSY; + sigprocmask(SIG_SETMASK, &saved, NULL); + PROFILE_DONE; + return -1; + } + + int save_errno; + + /* exec*() use this to restore the sig mask */ + pseudo_saved_sigmask = saved; + rc = wrap_execve(file, argv, envp); + + save_errno = errno; + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(PDBGF_WRAPPER, "completed: execle\n"); + errno = save_errno; + free(argv); + PROFILE_DONE; + return rc; +} + +int +execv(const char *file, char *const *argv) { + sigset_t saved; + + int rc = -1; + + PROFILE_START; + + if (!pseudo_check_wrappers() || !real_execv) { + /* rc was initialized to the "failure" value */ + pseudo_enosys("execv"); + PROFILE_DONE; + return rc; + } + + pseudo_debug(PDBGF_WRAPPER, "called: execv\n"); + pseudo_sigblock(&saved); + if (pseudo_getlock()) { + errno = EBUSY; + sigprocmask(SIG_SETMASK, &saved, NULL); + PROFILE_DONE; + return -1; + } + + int save_errno; + + /* exec*() use this to restore the sig mask */ + pseudo_saved_sigmask = saved; + rc = wrap_execv(file, argv); + + save_errno = errno; + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(PDBGF_WRAPPER, "completed: execv\n"); + errno = save_errno; + PROFILE_DONE; + return rc; +} + +int +execve(const char *file, char *const *argv, char *const *envp) { + sigset_t saved; + + int rc = -1; + PROFILE_START; + + if (!pseudo_check_wrappers() || !real_execve) { + /* rc was initialized to the "failure" value */ + pseudo_enosys("execve"); + PROFILE_DONE; + return rc; + } + + pseudo_debug(PDBGF_WRAPPER, "called: execve\n"); + pseudo_sigblock(&saved); + if (pseudo_getlock()) { + errno = EBUSY; + sigprocmask(SIG_SETMASK, &saved, NULL); + PROFILE_DONE; + return -1; + } + + int save_errno; + + /* exec*() use this to restore the sig mask */ + pseudo_saved_sigmask = saved; + rc = wrap_execve(file, argv, envp); + + save_errno = errno; + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(PDBGF_WRAPPER, "completed: execve\n"); + errno = save_errno; + PROFILE_DONE; + return rc; +} + +int +execvp(const char *file, char *const *argv) { + sigset_t saved; + + int rc = -1; + PROFILE_START; + + if (!pseudo_check_wrappers() || !real_execvp) { + /* rc was initialized to the "failure" value */ + pseudo_enosys("execvp"); + PROFILE_DONE; + return rc; + } + + pseudo_debug(PDBGF_WRAPPER, "called: execvp\n"); + pseudo_sigblock(&saved); + if (pseudo_getlock()) { + errno = EBUSY; + sigprocmask(SIG_SETMASK, &saved, NULL); + PROFILE_DONE; + return -1; + } + + int save_errno; + + /* exec*() use this to restore the sig mask */ + pseudo_saved_sigmask = saved; + rc = wrap_execvp(file, argv); + + save_errno = errno; + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(PDBGF_WRAPPER, "completed: execvp\n"); + errno = save_errno; + PROFILE_DONE; + return rc; +} + +/* no profiling in fork because it wouldn't work anyway + * half the time + */ +int +fork(void) { + sigset_t saved; + + int rc = -1; + + if (!pseudo_check_wrappers() || !real_fork) { + /* rc was initialized to the "failure" value */ + pseudo_enosys("fork"); + return rc; + } + + pseudo_debug(PDBGF_WRAPPER, "called: fork\n"); + pseudo_sigblock(&saved); + if (pseudo_getlock()) { + errno = EBUSY; + sigprocmask(SIG_SETMASK, &saved, NULL); + return -1; + } + + int save_errno; + + rc = wrap_fork(); + + save_errno = errno; + + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(PDBGF_WRAPPER, "completed: fork\n"); + errno = save_errno; + return rc; +} + +int +vfork(void) { + /* we don't provide support for the distinct semantics + * of vfork() + */ + return fork(); +} + +static int +wrap_execv(const char *file, char *const *argv) { + int rc = -1; + +#include "guts/execv.c" + + return rc; +} + +static int +wrap_execve(const char *file, char *const *argv, char *const *envp) { + int rc = -1; + +#include "guts/execve.c" + + return rc; +} + +static int +wrap_execvp(const char *file, char *const *argv) { + int rc = -1; + +#include "guts/execvp.c" + + return rc; +} + +static int +wrap_fork(void) { + int rc = -1; + +#include "guts/fork.c" + + return rc; +} + diff --git a/ports/common/subports b/ports/common/subports new file mode 100755 index 0000000..e2aac56 --- /dev/null +++ b/ports/common/subports @@ -0,0 +1,8 @@ +#!/bin/sh +case $(uname -s) in +Linux) echo "linux";; +Darwin) echo "darwin";; +*) echo >&2 "Unknown result from uname -s: %(uname -s). Aborting." + exit 1 + ;; +esac diff --git a/ports/common/wrapfuncs.in b/ports/common/wrapfuncs.in new file mode 100644 index 0000000..17440f9 --- /dev/null +++ b/ports/common/wrapfuncs.in @@ -0,0 +1,7 @@ +int execlp(const char *file, const char *arg, ...); /* hand_wrapped=1 */ +int execl(const char *file, const char *arg, ...); /* hand_wrapped=1 */ +int execle(const char *file, const char *arg, ...); /* hand_wrapped=1 */ +int execv(const char *file, char *const *argv); /* hand_wrapped=1 */ +int execve(const char *file, char *const *argv, char *const *envp); /* hand_wrapped=1 */ +int execvp(const char *file, char *const *argv); /* hand_wrapped=1 */ +int fork(void); /* hand_wrapped=1 */ diff --git a/ports/darwin/guts/COPYRIGHT b/ports/darwin/guts/COPYRIGHT new file mode 100644 index 0000000..c96e1b1 --- /dev/null +++ b/ports/darwin/guts/COPYRIGHT @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the Lesser GNU General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * version 2.1 along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ diff --git a/ports/darwin/guts/fcntl.c b/ports/darwin/guts/fcntl.c new file mode 100644 index 0000000..c0b142b --- /dev/null +++ b/ports/darwin/guts/fcntl.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011, 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fcntl(int fd, int cmd, ... { struct flock *lock }) + * int rc = -1; + */ + int save_errno; + long long flag = 0; + + va_start(ap, cmd); + flag = va_arg(ap, long long); + va_end(ap); + rc = real_fcntl(fd, cmd, flag); + + switch (cmd) { + case F_DUPFD: +#ifdef F_DUPFD_CLOEXEC + /* it doesn't exist now, but if I take this out they'll add it + * just to mess with me. + */ + case F_DUPFD_CLOEXEC: +#endif + /* actually do something */ + save_errno = errno; + if (rc != -1) { + pseudo_debug(PDBGF_OP, "fcntl_dup: %d->%d\n", fd, rc); + pseudo_client_op(OP_DUP, 0, fd, rc, 0, 0); + } + errno = save_errno; + break; + default: + /* nothing to do, we hope */ + break; + } + + save_errno = errno; + pseudo_debug(PDBGF_OP, "fcntl(fd %d, cmd %d, %llx) => %d (%s)\n", + fd, cmd, flag, rc, strerror(errno)); + errno = save_errno; + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/fgetgrent_r.c b/ports/darwin/guts/fgetgrent_r.c new file mode 100644 index 0000000..e760cdd --- /dev/null +++ b/ports/darwin/guts/fgetgrent_r.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fgetgrent_r(FILE *fp, struct group*gbuf, char *buf, size_t buflen, struct group **gbufp) + * int rc = -1; + */ + + rc = real_fgetgrent_r(fp, gbuf, buf, buflen, gbufp); + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/fgetpwent_r.c b/ports/darwin/guts/fgetpwent_r.c new file mode 100644 index 0000000..cfea5b8 --- /dev/null +++ b/ports/darwin/guts/fgetpwent_r.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fgetpwent_r(FILE *fp, struct passwd *pbuf, char *buf, size_t buflen, struct passwd **pbufp) + * int rc = -1; + */ + + rc = real_fgetpwent_r(fp, pbuf, buf, buflen, pbufp); + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/fgetxattr.c b/ports/darwin/guts/fgetxattr.c new file mode 100644 index 0000000..dbb3681 --- /dev/null +++ b/ports/darwin/guts/fgetxattr.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size, u_int32_t position, int options) + * ssize_t rc = -1; + */ + + rc = shared_getxattr(NULL, filedes, name, value, size, position, options); + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/flistxattr.c b/ports/darwin/guts/flistxattr.c new file mode 100644 index 0000000..bfaa4e9 --- /dev/null +++ b/ports/darwin/guts/flistxattr.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t flistxattr(int filedes, char *list, size_t size, int options) + * ssize_t rc = -1; + */ + + rc = shared_listxattr(NULL, filedes, list, size, options); + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/fremovexattr.c b/ports/darwin/guts/fremovexattr.c new file mode 100644 index 0000000..4edc38c --- /dev/null +++ b/ports/darwin/guts/fremovexattr.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fremovexattr(int filedes, const char *name, int options) + * int rc = -1; + */ + + rc = shared_removexattr(NULL, filedes, name, options); + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/fsetxattr.c b/ports/darwin/guts/fsetxattr.c new file mode 100644 index 0000000..d707595 --- /dev/null +++ b/ports/darwin/guts/fsetxattr.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fsetxattr(int filedes, const char *name, const void *value, size_t size, u_int32_t position, int options) + * int rc = -1; + */ + + rc = shared_setxattr(NULL, filedes, name, value, size, position, options); + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/fstat.c b/ports/darwin/guts/fstat.c new file mode 100644 index 0000000..7695147 --- /dev/null +++ b/ports/darwin/guts/fstat.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fstat(int fd, struct stat *buf) + * int rc = -1; + */ + pseudo_msg_t *msg; + + rc = real_fstat(fd, buf); + + if (rc == -1) { + return rc; + } + + /* query database + * note that symlink canonicalizing is now automatic, so we + * don't need to check for a symlink on this end + */ + msg = pseudo_client_op(OP_FSTAT, 0, fd, -1, 0, buf); + if (msg && msg->result == RESULT_SUCCEED) { + pseudo_stat_msg(buf, msg); + } + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/getgrent_r.c b/ports/darwin/guts/getgrent_r.c new file mode 100644 index 0000000..9d5db5a --- /dev/null +++ b/ports/darwin/guts/getgrent_r.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int getgrent_r(struct group *gbuf, char *buf, size_t buflen, struct group **gbufp) + * int rc = -1; + */ + + rc = real_getgrent_r(gbuf, buf, buflen, gbufp); + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/getgrouplist.c b/ports/darwin/guts/getgrouplist.c new file mode 100644 index 0000000..85fccc9 --- /dev/null +++ b/ports/darwin/guts/getgrouplist.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_getgrouplist(const char *name, int basegid, int *groups, int *ngroups) { + * int rc = -1; + */ + + int found = 0; + int found_group = 0; + char buf[PSEUDO_PWD_MAX]; + struct group grp, *gbuf = &grp; + + setgrent(); + while ((rc = wrap_getgrent_r(gbuf, buf, PSEUDO_PWD_MAX, &gbuf)) == 0) { + int i = 0; + for (i = 0; gbuf->gr_mem[i]; ++i) { + if (!strcmp(gbuf->gr_mem[i], name)) { + if (found < *ngroups) + groups[found] = gbuf->gr_gid; + ++found; + if ((int) gbuf->gr_gid == basegid) + found_group = 1; + } + } + } + endgrent(); + if (!found_group) { + if (found < *ngroups) + groups[found] = basegid; + ++found; + } + if (found >= *ngroups) + rc = -1; + else + rc = found; + *ngroups = found; + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/getgroups.c b/ports/darwin/guts/getgroups.c new file mode 100644 index 0000000..3cbeb76 --- /dev/null +++ b/ports/darwin/guts/getgroups.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_getgroups(int size, gid_t *list) { + * int rc = -1; + */ + struct passwd *p = wrap_getpwuid(wrap_getuid()); + int oldsize = size; + + if (p) { + rc = wrap_getgrouplist(p->pw_name, wrap_getgid(), (int *) list, &size); + if (oldsize == 0 || size <= oldsize) + rc = size; + } else { + errno = ENOENT; + } + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/getpwent_r.c b/ports/darwin/guts/getpwent_r.c new file mode 100644 index 0000000..3de41b9 --- /dev/null +++ b/ports/darwin/guts/getpwent_r.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp) + * int rc = -1; + */ + + rc = real_getpwent_r(pwbuf, buf, buflen, pwbufp); + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/getxattr.c b/ports/darwin/guts/getxattr.c new file mode 100644 index 0000000..ecef9cf --- /dev/null +++ b/ports/darwin/guts/getxattr.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t getxattr(const char *path, const char *name, void *value, size_t size, u_int32_t position, int options) + * ssize_t rc = -1; + */ + + rc = shared_getxattr(path, -1, name, value, size, position, options); + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/listxattr.c b/ports/darwin/guts/listxattr.c new file mode 100644 index 0000000..5a8a7a8 --- /dev/null +++ b/ports/darwin/guts/listxattr.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t listxattr(const char *path, char *list, size_t size, int options) + * ssize_t rc = -1; + */ + + rc = shared_listxattr(path, -1, list, size, options); + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/lstat.c b/ports/darwin/guts/lstat.c new file mode 100644 index 0000000..01e0f30 --- /dev/null +++ b/ports/darwin/guts/lstat.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int lstat(const char *path, struct stat *buf) + * int rc = -1; + */ + + pseudo_msg_t *msg; + + rc = real_lstat(path, buf); + if (rc == -1) { + return rc; + } + + /* query database + * note that symlink canonicalizing is now automatic, so we + * don't need to check for a symlink on this end + */ + msg = pseudo_client_op(OP_STAT, 0, -1, -1, path, buf); + if (msg && msg->result == RESULT_SUCCEED) { + pseudo_stat_msg(buf, msg); + } + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/open.c b/ports/darwin/guts/open.c new file mode 100644 index 0000000..f34b0d3 --- /dev/null +++ b/ports/darwin/guts/open.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011-2013 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int open(const char *path, int flags, ... { int mode }) + * int rc = -1; + */ + + struct stat buf = { }; + int existed = 1; + int save_errno; + + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; +#ifdef PSEUDO_FORCE_ASYNCH + flags &= ~O_SYNC; +#endif + + /* if a creation has been requested, check whether file exists */ + if (flags & O_CREAT) { + save_errno = errno; + rc = real_stat(path, &buf); + existed = (rc != -1); + if (!existed) + pseudo_debug(PDBGF_FILE, "open_creat: %s -> 0%o\n", path, mode); + errno = save_errno; + } + + /* because we are not actually root, secretly mask in 0600 to the + * underlying mode. The ", 0" is because the only time mode matters + * is if a file is going to be created, in which case it's + * not a directory. + */ + rc = real_open(path, flags, PSEUDO_FS_MODE(mode, 0)); + save_errno = errno; + + if (rc != -1) { + int stat_rc; + stat_rc = real_stat(path, &buf); + + if (stat_rc != -1) { + buf.st_mode = PSEUDO_DB_MODE(buf.st_mode, mode); + if (!existed) { + real_fchmod(rc, PSEUDO_FS_MODE(mode, 0)); + pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf); + } + pseudo_client_op(OP_OPEN, PSEUDO_ACCESS(flags), rc, -1, path, &buf); + } else { + pseudo_debug(PDBGF_CONSISTENCY, "open (fd %d, path %s, flags %d) succeeded, but stat failed (%s).\n", + rc, path, flags, strerror(errno)); + pseudo_client_op(OP_OPEN, PSEUDO_ACCESS(flags), rc, -1, path, 0); + } + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/removexattr.c b/ports/darwin/guts/removexattr.c new file mode 100644 index 0000000..c125b1a --- /dev/null +++ b/ports/darwin/guts/removexattr.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int removexattr(const char *path, const char *name, int options) + * int rc = -1; + */ + + rc = shared_removexattr(path, -1, name, options); + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/scandir.c b/ports/darwin/guts/scandir.c new file mode 100644 index 0000000..6492b1b --- /dev/null +++ b/ports/darwin/guts/scandir.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_scandir(const char *path, struct dirent ***namelist, int (*filter)(struct dirent *), int (*compar)(const void *, const void *)) { + * int rc = -1; + */ + + rc = real_scandir(path, namelist, filter, compar); + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/setxattr.c b/ports/darwin/guts/setxattr.c new file mode 100644 index 0000000..10ffba4 --- /dev/null +++ b/ports/darwin/guts/setxattr.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int setxattr(const char *path, const char *name, const void *value, size_t size, u_int32_t position, int options) + * int rc = -1; + */ + + rc = shared_setxattr(path, -1, name, value, size, position, options); + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/stat.c b/ports/darwin/guts/stat.c new file mode 100644 index 0000000..8a0742c --- /dev/null +++ b/ports/darwin/guts/stat.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int stat(const char *path, struct stat *buf) + * int rc = -1; + */ + + pseudo_msg_t *msg; + int save_errno; + + rc = real_stat(path, buf); + if (rc == -1) { + return rc; + } + save_errno = errno; + + /* query database + * note that symlink canonicalizing is now automatic, so we + * don't need to check for a symlink on this end + */ + msg = pseudo_client_op(OP_STAT, 0, -1, AT_FDCWD, path, buf); + if (msg && msg->result == RESULT_SUCCEED) { + pseudo_stat_msg(buf, msg); + } + + errno = save_errno; + +/* return rc; + * } + */ diff --git a/ports/darwin/guts/sync_file_range.c b/ports/darwin/guts/sync_file_range.c new file mode 100644 index 0000000..e0a31a4 --- /dev/null +++ b/ports/darwin/guts/sync_file_range.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2013 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int sync_file_range(int fd, off_t offset, off_t nbytes, unsigned int flags) + * int rc = -1; + */ + + rc = real_sync_file_range(fd, offset, nbytes, flags); + +/* return rc; + * } + */ diff --git a/ports/darwin/portdefs.h b/ports/darwin/portdefs.h new file mode 100644 index 0000000..900d98e --- /dev/null +++ b/ports/darwin/portdefs.h @@ -0,0 +1,13 @@ +#define PRELINK_LIBRARIES "DYLD_INSERT_LIBRARIES" +#define PRELINK_PATH "DYLD_LIBRARY_PATH" +#define PSEUDO_STATBUF_64 0 +#define PSEUDO_STATBUF struct stat +#define PSEUDO_LINKPATH_SEPARATOR ":" +/* hackery to allow sneaky things to be done with getgrent() */ +extern int pseudo_host_etc_passwd_fd; +extern int pseudo_host_etc_group_fd; +extern FILE *pseudo_host_etc_passwd_file; +extern FILE *pseudo_host_etc_group_file; +/* Darwin ALWAYS follows symlinks for link(2) */ +#undef PSEUDO_LINK_SYMLINK_BEHAVIOR +#define PSEUDO_LINK_SYMLINK_BEHAVIOR AT_SYMLINK_FOLLOW diff --git a/ports/darwin/preports b/ports/darwin/preports new file mode 100755 index 0000000..a996c69 --- /dev/null +++ b/ports/darwin/preports @@ -0,0 +1,2 @@ +#!/bin/sh +echo "unix" "uids_generic" diff --git a/ports/darwin/pseudo_wrappers.c b/ports/darwin/pseudo_wrappers.c new file mode 100644 index 0000000..e33533e --- /dev/null +++ b/ports/darwin/pseudo_wrappers.c @@ -0,0 +1,606 @@ +/* + * pseudo_wrappers.c, darwin pseudo wrappers + * + * Copyright (c) 2008-2011 Wind River Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the Lesser GNU General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * version 2.1 along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +/* we need XATTR_NOFOLLOW in scope */ +#include <sys/xattr.h> + +/* shared functionality for the xattr code */ +/* Each of these functions is expecting to get an optional name, and + * a populated statbuf to use for sending messages to the server. + */ + +/* to avoid namespace pollution and such, we now duplicate the + * basic functionality of a POSIX ACL list, as used by libacl or + * the kernel. Documentation was obtained from the headers of libacl + * and from a page or two of _The Linux Programming Interface_, by + * Michael Kerrisk. + */ + +typedef struct { + uint16_t tag; + uint16_t perm; + uint32_t id; +} acl_entry; + +typedef struct { + uint32_t version; + acl_entry entries[]; +} acl_header; + +enum acl_tags { + ACL_UNDEFINED = 0x0, + ACL_USER_OBJ = 0x1, + ACL_USER = 0x2, + ACL_GROUP_OBJ = 0x4, + ACL_GROUP = 0x8, + ACL_MASK = 0x10, + ACL_OTHER = 0x20, +}; + +static const int endian_test = 1; +static const char *endian_tester = (char *) &endian_test; + +static inline int +le16(int x16) { + if (*endian_tester) { + return x16; + } else { + return ((x16 & 0xff) << 8) | ((x16 & 0xff00) >> 8); + } +} + +static inline int +le32(int x32) { + if (*endian_tester) { + return x32; + } else { + return ((x32 & 0xff) << 24) | ((x32 & 0xff00) << 8) | + ((x32 & 0xff0000) >> 8) | ((x32 & 0xff000000) >> 24); + } +} + +/* set mode to match the contents of header. Return non-zero on error. + * On a zero return, mode is a valid posix mode, and *extra is set to + * 1 if any of the entries are not reflected by that mode. On a non-zero + * return, no promises are made about *extra or *mode. + */ +static int +posix_permissions(const acl_header *header, int entries, int *extra, int *mode) { + int acl_seen = 0; + if (le32(header->version) != 2) { + pseudo_diag("Fatal: ACL support no available for header version %d.\n", + le32(header->version)); + return 1; + } + *mode = 0; + *extra = 0; + for (int i = 0; i < entries; ++i) { + const acl_entry *e = &header->entries[i]; + int tag = le16(e->tag); + int perm = le16(e->perm); + acl_seen |= tag; + switch (tag) { + case ACL_USER_OBJ: + *mode = *mode | (perm << 6); + break; + case ACL_GROUP_OBJ: + *mode = *mode | (perm << 3); + break; + case ACL_OTHER: + *mode = *mode | perm; + break; + case ACL_USER: + case ACL_GROUP: + case ACL_MASK: + *extra = *extra + 1; + break; + default: + pseudo_debug(PDBGF_XATTR, "Unknown tag in ACL: 0x%x.\n", + tag); + return 1; + } + } + return 0; +} + +#define RC_AND_BUF \ + int rc; \ + PSEUDO_STATBUF buf; \ + if (path) { \ + rc = base_lstat(path, &buf); \ + } else { \ + rc = base_fstat(fd, &buf); \ + } \ + if (rc == -1) { \ + return rc; \ + } + +/* Note: no profiling implementation yet. */ +static ssize_t shared_getxattr(const char *path, int fd, const char *name, void *value, size_t size, u_int32_t position, int options) { + RC_AND_BUF + + if (!strncmp(name, "com.apple.", 10)) { + if (fd != -1) { + return real_fgetxattr(fd, name, value, size, position, options); + } else { + return real_getxattr(path, name, value, size, position, options); + } + } + + pseudo_debug(PDBGF_XATTR, "getxattr(%s [fd %d], %s)\n", + path ? path : "<no path>", fd, name); + pseudo_msg_t *result = pseudo_client_op(OP_GET_XATTR, 0, fd, -1, path, &buf, name); + if (result->result != RESULT_SUCCEED) { + errno = ENOATTR; + return -1; + } + + if (value) { + pseudo_debug(PDBGF_XATTR, "returned attributes: '%s' (%d bytes)\n", + result->path, result->pathlen); + if (size >= result->pathlen) { + memcpy(value, result->path, result->pathlen); + } else { + memcpy(value, result->path, size); + errno = ERANGE; + } + } + return result->pathlen; +} + +static int shared_setxattr(const char *path, int fd, const char *name, const void *value, size_t size, u_int32_t position, int options) { + RC_AND_BUF + pseudo_op_t op; + + pseudo_debug(PDBGF_XATTR, "setxattr(%s [fd %d], %s => '%.*s')\n", + path ? path : "<no path>", fd, name, (int) size, (char *) value); + + if (!strncmp(name, "com.apple.", 10)) { + if (fd != -1) { + return real_fsetxattr(fd, name, value, size, position, options); + } else { + return real_setxattr(path, name, value, size, position, options); + } + } + + /* this may be a plain chmod */ + if (!strcmp(name, "system.posix_acl_access")) { + int extra; + int mode; + int entries = (size - sizeof(acl_header)) / sizeof(acl_entry); + if (!posix_permissions(value, entries, &extra, &mode)) { + pseudo_debug(PDBGF_XATTR, "posix_acl_access translated to mode %04o. Remaining attribute(s): %d.\n", + mode, extra); + buf.st_mode = mode; + /* we want to actually issue a corresponding chmod, + * as well, or else the file ends up 0600 on the + * host. Using the slightly-less-efficient wrap_chmod + * avoids possible misalignment. + */ + if (path) { + wrap_chmod(path, mode); + } else { + wrap_fchmod(fd, mode); + } + /* we are sneaky, and do not actually record this using + * extended attributes. */ + if (!extra) { + return 0; + } + } + } + + if (options & XATTR_CREATE) { + op = OP_CREATE_XATTR; + } else if (options & XATTR_REPLACE) { + op = OP_REPLACE_XATTR; + } else { + op = OP_SET_XATTR; + } + + pseudo_msg_t *result = pseudo_client_op(op, 0, fd, -1, path, &buf, name, value, size); + + /* we automatically assume success */ + if (op == OP_SET_XATTR) { + return 0; + } + + /* CREATE/REPLACE operations can report failure */ + if (!result || result->result == RESULT_FAIL) { + return -1; + } + + return 0; +} + +static ssize_t shared_listxattr(const char *path, int fd, char *list, size_t size, int options) { + RC_AND_BUF + char extra_name_buf[4096]; + ssize_t real_attr_len; + ssize_t used = 0; + if (fd != -1) { + real_attr_len = real_flistxattr(fd, extra_name_buf, sizeof(extra_name_buf), options); + } else { + real_attr_len = real_listxattr(path, extra_name_buf, sizeof(extra_name_buf), options); + } + pseudo_debug(PDBGF_XATTR, "listxattr: %d bytes of FS xattr names, starting '%.*s'\n", + (int) real_attr_len, (int) real_attr_len, extra_name_buf); + + /* we don't care why there aren't any */ + if (real_attr_len < 1) { + real_attr_len = 0; + } + + pseudo_msg_t *result = pseudo_client_op(OP_LIST_XATTR, 0, fd, -1, path, &buf); + + if (result->result != RESULT_SUCCEED && real_attr_len < 1) { + pseudo_debug(PDBGF_XATTR, "listxattr: no success.\n"); + errno = ENOATTR; + return -1; + } + + if (list) { + pseudo_debug(PDBGF_XATTR, "listxattr: %d bytes of names, starting '%.*s'\n", + (int) result->pathlen, (int) result->pathlen, result->path); + if (size >= result->pathlen) { + memcpy(list, result->path, result->pathlen); + used = result->pathlen; + } else { + memcpy(list, result->path, size); + used = size; + errno = ERANGE; + } + if (real_attr_len > 0) { + if ((ssize_t) size >= used + real_attr_len) { + memcpy(list + used, extra_name_buf, real_attr_len); + used += real_attr_len; + } else { + memcpy(list + used, extra_name_buf, size - used); + used = size; + errno = ERANGE; + } + + } + } else { + used = real_attr_len + result->pathlen; + } + return used; +} + +static int shared_removexattr(const char *path, int fd, const char *name, int options) { + RC_AND_BUF + + if (!strncmp(name, "com.apple.", 10)) { + if (fd != -1) { + return real_fremovexattr(fd, name, options); + } else { + return real_removexattr(path, name, options); + } + } + + pseudo_msg_t *result = pseudo_client_op(OP_REMOVE_XATTR, 0, fd, -1, path, &buf, name); + + if (result->result != RESULT_SUCCEED) { + /* docs say ENOATTR, but I don't have one */ + errno = ENOENT; + return -1; + } + return 0; +} + + +/* there's no fgetgrent_r or fgetpwent_r in Darwin */ + +#define PLENTY_LONG 2048 +/* the original uid/gid code for Linux was written in terms of the + * fget*ent_r() functions... which Darwin doesn't have. But wait! They're + * actually pretty easy to implement. + */ +int +pseudo_fgetgrent_r(FILE *fp, struct group *gbuf, char *buf, size_t buflen, struct group **gbufp) { + char linebuf[PLENTY_LONG] = { 0 }; + char *s, *t, *u; + size_t max_members; + char **members; + size_t member = 0; + long started_at = -1; + gid_t gid; + int error = ENOENT; + size_t len; + + /* any early exit should set *gbufp to NULL */ + if (gbufp) + *gbufp = NULL; + + if (!gbuf || !fp || !buf) + goto error_out; + + if (fp == pseudo_host_etc_group_file) { + struct group *g; + pseudo_antimagic(); + g = getgrent(); + pseudo_magic(); + if (g) { + char *s = linebuf; + s += snprintf(linebuf, PLENTY_LONG, + "%s:%s:%ld:", + g->gr_name, + g->gr_passwd, + (long) g->gr_gid); + if (g->gr_mem) { + int i; + for (i = 0; g->gr_mem[i]; ++i) { + s += snprintf(s, + PLENTY_LONG - (s - linebuf), + "%s,", + g->gr_mem[i]); + } + if (s[-1] == ',') + --s; + } + strcpy(s, "\n"); + } else { + goto error_out; + } + } else { + started_at = ftell(fp); + if (started_at == -1) { + goto error_out; + } + s = fgets(linebuf, PLENTY_LONG, fp); + if (!s) { + goto error_out; + } + } + /* fgets will have stored a '\0' if there was no error; if there + * was an error, though, linebuf was initialized to all zeroes so + * the string is null-terminated anyway... + */ + len = strlen(linebuf); + if (len > buflen) { + error = ERANGE; + goto error_out; + } + memcpy(buf, linebuf, len); + /* round up to 8, hope for the best? */ + len = len + 8 + (((unsigned long long) (buf + len)) % 8); + members = (char **) (buf + len); + if (len >= buflen) { + error = ERANGE; + goto error_out; + } + /* this is how many pointers we have room for... */ + max_members = (buflen - len) / sizeof(*members); + + t = buf; + /* yes, I can assume that Darwin has strsep() */ + s = strsep(&t, ":"); + if (!s) { + goto error_out; + } + gbuf->gr_name = s; + s = strsep(&t, ":"); + if (!s) { + goto error_out; + } + gbuf->gr_passwd = s; + s = strsep(&t, ":"); + if (!s) { + goto error_out; + } + gid = (gid_t) strtol(s, &u, 10); + /* should be a null byte, otherwise we didn't get a valid number */ + if (*u) + goto error_out; + gbuf->gr_gid = gid; + + /* now, s points to a comma-separated list of members, which we + * want to stash pointers to in 'members'. + */ + s = strsep(&t, ":"); + t = s; + while ((s = strsep(&t, ",")) != NULL) { + if (*s) { + if (member + 1 > max_members) { + errno = ERANGE; + goto error_out; + } + members[member++] = s; + } + } + if (member + 1 > max_members) { + errno = ERANGE; + goto error_out; + } + members[member++] = NULL; + *gbufp = gbuf; + return 0; + +error_out: + if (started_at != -1) + fseek(fp, started_at, SEEK_SET); + return error; + return -1; +} + +int +pseudo_fgetpwent_r(FILE *fp, struct passwd *pbuf, char *buf, size_t buflen, struct passwd **pbufp) { + char linebuf[PLENTY_LONG] = { 0 }; + char *s, *t, *u; + long started_at = -1; + __darwin_time_t timestamp; + uid_t uid; + gid_t gid; + int error = ENOENT; + size_t len; + + /* any early exit should set *gbufp to NULL */ + if (pbufp) + *pbufp = NULL; + + if (!pbuf || !fp || !buf) + goto error_out; + + if (fp == pseudo_host_etc_passwd_file) { + struct passwd *p; + + pseudo_antimagic(); + p = getpwent(); + pseudo_magic(); + if (p) { + snprintf(linebuf, PLENTY_LONG, + "%s:%s:%ld:%ld:%s:%ld:%ld:%s:%s:%s\n", + p->pw_name, + p->pw_passwd, + (long) p->pw_uid, + (long) p->pw_gid, + p->pw_class, + (long) p->pw_change, + (long) p->pw_expire, + p->pw_gecos, + p->pw_dir, + p->pw_shell); + } else { + goto error_out; + } + } else { + started_at = ftell(fp); + if (started_at == -1) { + goto error_out; + } + s = fgets(linebuf, PLENTY_LONG, fp); + if (!s) { + goto error_out; + } + } + /* fgets will have stored a '\0' if there was no error; if there + * was an error, though, linebuf was initialized to all zeroes so + * the string is null-terminated anyway... + */ + len = strlen(linebuf); + if (len > buflen) { + error = ERANGE; + goto error_out; + } + if (linebuf[len - 1] == '\n') { + linebuf[len - 1] = '\0'; + --len; + } + memcpy(buf, linebuf, len); + + t = buf; + /* yes, I can assume that Darwin has strsep() */ + s = strsep(&t, ":"); + if (!s) { + goto error_out; + } + pbuf->pw_name = s; + + s = strsep(&t, ":"); + if (!s) + goto error_out; + pbuf->pw_passwd = s; + + s = strsep(&t, ":"); + if (!s) + goto error_out; + uid = (uid_t) strtol(s, &u, 10); + /* should be a null byte, otherwise we didn't get a valid number */ + if (*u) + goto error_out; + pbuf->pw_uid = uid; + + s = strsep(&t, ":"); + if (!s) + goto error_out; + gid = (gid_t) strtol(s, &u, 10); + /* should be a null byte, otherwise we didn't get a valid number */ + if (*u) + goto error_out; + pbuf->pw_gid = gid; + + s = strsep(&t, ":"); + if (!s) + goto error_out; + pbuf->pw_class = s; + + s = strsep(&t, ":"); + if (!s) + goto error_out; + timestamp = (__darwin_time_t) strtol(s, &u, 10); + /* should be a null byte, otherwise we didn't get a valid number */ + if (*u) + goto error_out; + pbuf->pw_change = timestamp; + + timestamp = (__darwin_time_t) strtol(s, &u, 10); + /* should be a null byte, otherwise we didn't get a valid number */ + if (*u) + goto error_out; + pbuf->pw_expire = timestamp; + + s = strsep(&t, ":"); + if (!s) + goto error_out; + pbuf->pw_gecos = s; + + s = strsep(&t, ":"); + if (!s) + goto error_out; + pbuf->pw_dir = s; + + s = strsep(&t, ":"); + if (!s) + goto error_out; + pbuf->pw_shell = s; + + *pbufp = pbuf; + return 0; + +error_out: + if (started_at != -1) + fseek(fp, started_at, SEEK_SET); + return error; + return -1; +} + +int +pseudo_getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp) { + /* note that we don't wrap fgetpwent_r, since there's no path + * references in it. + */ + if (!pseudo_pwd) { + errno = ENOENT; + return -1; + } + return pseudo_fgetpwent_r(pseudo_pwd, pwbuf, buf, buflen, pwbufp); +} + +int +pseudo_getgrent_r(struct group *gbuf, char *buf, size_t buflen, struct group **gbufp) { + /* note that we don't wrap fgetgrent_r, since there's no path + * references in it. + */ + if (!pseudo_grp) { + errno = ENOENT; + return -1; + } + return pseudo_fgetgrent_r(pseudo_grp, gbuf, buf, buflen, gbufp); +} + diff --git a/ports/darwin/subports b/ports/darwin/subports new file mode 100755 index 0000000..57bdd6d --- /dev/null +++ b/ports/darwin/subports @@ -0,0 +1,3 @@ +#!/bin/sh +# no subports at this time +exit 0 diff --git a/ports/darwin/wrapfuncs.in b/ports/darwin/wrapfuncs.in new file mode 100644 index 0000000..306ad66 --- /dev/null +++ b/ports/darwin/wrapfuncs.in @@ -0,0 +1,27 @@ +# On Darwin, mode_t promotes to int, so you have to use int for va_arg +int open(const char *path, int flags, ...{int mode}); /* flags=0 */ +int stat(const char *path, struct stat *buf); /* inode64=1 */ +int lstat(const char *path, struct stat *buf); /* flags=AT_SYMLINK_NOFOLLOW, inode64=1 */ +int fstat(int fd, struct stat *buf); /* inode64=1 */ +int fcntl(int fd, int cmd, ...{struct flock *lock}); +# just so we know the inums of symlinks +# for emulation of passwd utilities +int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups); +# local color UIDs +int getgrouplist(const char *name, int basegid, int *groups, int *ngroups); +int scandir(const char *path, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)()); +int getgroups(int size, gid_t *list); +int fgetgrent_r(FILE *fp, struct group *gbuf, char *buf, size_t buflen, struct group **gbufp); /* real_func=pseudo_fgetgrent_r */ +int fgetpwent_r(FILE *fp, struct passwd *pbuf, char *buf, size_t buflen, struct passwd **pbufp); /* real_func=pseudo_fgetpwent_r */ +int getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp); /* real_func=pseudo_getpwent_r */ +int getgrent_r(struct group *gbuf, char *buf, size_t buflen, struct group **gbufp); /* real_func=pseudo_getgrent_r */ +int sync_file_range(int fd, off_t offset, off_t nbytes, unsigned int flags); /* async_skip=0 */ + +ssize_t getxattr(const char *path, const char *name, void *value, size_t size, u_int32_t position, int options); /* flags=(options&XATTR_NOFOLLOW?AT_SYMLINK_NOFOLLOW:0) */ +ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size, u_int32_t position, int options); +int setxattr(const char *path, const char *name, const void *value, size_t size, u_int32_t position, int options); /* flags=0 */ +int fsetxattr(int filedes, const char *name, const void *value, size_t size, u_int32_t position, int options); +ssize_t listxattr(const char *path, char *list, size_t size, int options); /* flags=0 */ +ssize_t flistxattr(int filedes, char *list, size_t size, int options); +int removexattr(const char *path, const char *name, int options); /* flags=0 */ +int fremovexattr(int filedes, const char *name, int options); diff --git a/ports/linux/guts/COPYRIGHT b/ports/linux/guts/COPYRIGHT new file mode 100644 index 0000000..c96e1b1 --- /dev/null +++ b/ports/linux/guts/COPYRIGHT @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the Lesser GNU General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * version 2.1 along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ diff --git a/ports/linux/guts/__fxstat.c b/ports/linux/guts/__fxstat.c new file mode 100644 index 0000000..db9716b --- /dev/null +++ b/ports/linux/guts/__fxstat.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int + * wrap___fxstat(int ver, int fd, struct stat *buf) { + * int rc = -1; + */ + + struct stat64 buf64; + /* populate buffer with complete data */ + real___fxstat(ver, fd, buf); + /* obtain fake data */ + rc = wrap___fxstat64(ver, fd, &buf64); + /* overwrite */ + pseudo_stat32_from64(buf, &buf64); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/__fxstat64.c b/ports/linux/guts/__fxstat64.c new file mode 100644 index 0000000..8601904 --- /dev/null +++ b/ports/linux/guts/__fxstat64.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int + * wrap___fxstat64(int ver, int fd, struct stat64 *buf) { + * int rc = -1; + */ + pseudo_msg_t *msg; + int save_errno; + + rc = real___fxstat64(ver, fd, buf); + save_errno = errno; + if (rc == -1) { + return rc; + } + if (ver != _STAT_VER) { + pseudo_debug(PDBGF_CLIENT, "version mismatch: got stat version %d, only supporting %d\n", ver, _STAT_VER); + errno = save_errno; + return rc; + } + msg = pseudo_client_op(OP_FSTAT, 0, fd, -1, 0, buf); + if (msg && msg->result == RESULT_SUCCEED) { + pseudo_stat_msg(buf, msg); + } + + errno = save_errno; +/* return rc; + * } + */ diff --git a/ports/linux/guts/__fxstatat.c b/ports/linux/guts/__fxstatat.c new file mode 100644 index 0000000..94c5ff6 --- /dev/null +++ b/ports/linux/guts/__fxstatat.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap___fxstatat(int ver, int dirfd, const char *path, struct stat *buf, int flags) { + * int rc = -1; + */ + + struct stat64 buf64; + /* populate buffer with complete data */ +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + if (flags & AT_SYMLINK_NOFOLLOW) { + rc = real___lxstat(ver, path, buf); + } else { + rc = real___xstat(ver, path, buf); + } +#else + real___fxstatat(ver, dirfd, path, buf, flags); +#endif + /* obtain fake data */ + rc = wrap___fxstatat64(ver, dirfd, path, &buf64, flags); + /* overwrite */ + pseudo_stat32_from64(buf, &buf64); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/__fxstatat64.c b/ports/linux/guts/__fxstatat64.c new file mode 100644 index 0000000..62fc3f1 --- /dev/null +++ b/ports/linux/guts/__fxstatat64.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap___fxstatat64(int ver, int dirfd, const char *path, struct stat64 *buf, int flags) { + * int rc = -1; + */ + pseudo_msg_t *msg; + int save_errno; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } +#endif + if (flags & AT_SYMLINK_NOFOLLOW) { +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real___lxstat64(ver, path, buf); +#else + rc = real___fxstatat64(ver, dirfd, path, buf, flags); +#endif + if (rc == -1) { + return rc; + } + } else { +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real___xstat64(ver, path, buf); +#else + rc = real___fxstatat64(ver, dirfd, path, buf, flags); +#endif + if (rc == -1) { + return rc; + } + } + save_errno = errno; + + if (ver != _STAT_VER) { + pseudo_debug(PDBGF_CLIENT, "version mismatch: got stat version %d, only supporting %d\n", ver, _STAT_VER); + errno = save_errno; + return rc; + } + + /* query database + * note that symlink canonicalizing is now automatic, so we + * don't need to check for a symlink on this end + */ + msg = pseudo_client_op(OP_STAT, 0, -1, dirfd, path, buf); + if (msg && msg->result == RESULT_SUCCEED) { + pseudo_stat_msg(buf, msg); + } + + errno = save_errno; + +/* return rc; + * } + */ diff --git a/ports/linux/guts/__lxstat.c b/ports/linux/guts/__lxstat.c new file mode 100644 index 0000000..32b0301 --- /dev/null +++ b/ports/linux/guts/__lxstat.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap___lxstat(int ver, const char *path, struct stat *buf) { + * int rc = -1; + */ + + rc = wrap___fxstatat(ver, AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW); + +/* + * } + */ diff --git a/ports/linux/guts/__lxstat64.c b/ports/linux/guts/__lxstat64.c new file mode 100644 index 0000000..ac1f782 --- /dev/null +++ b/ports/linux/guts/__lxstat64.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap___lxstat64(int ver, const char *path, struct stat64 *buf) { + * int rc = -1; + */ + + rc = wrap___fxstatat64(ver, AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW); + +/* + * } + */ diff --git a/ports/linux/guts/__openat64_2.c b/ports/linux/guts/__openat64_2.c new file mode 100644 index 0000000..e970df7 --- /dev/null +++ b/ports/linux/guts/__openat64_2.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010,2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap___openat64_2(int dirfd, const char *path, int flags) { + * int rc = -1; + */ + + rc = wrap_openat(dirfd, path, flags | O_LARGEFILE, 0); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/__openat_2.c b/ports/linux/guts/__openat_2.c new file mode 100644 index 0000000..33ed620 --- /dev/null +++ b/ports/linux/guts/__openat_2.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap___openat_2(int dirfd, const char *path, int flags) { + * int rc = -1; + */ + + rc = wrap_openat(dirfd, path, flags, 0); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/__xmknod.c b/ports/linux/guts/__xmknod.c new file mode 100644 index 0000000..fa31b66 --- /dev/null +++ b/ports/linux/guts/__xmknod.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap___xmknod(int ver, const char *path, mode_t mode, dev_t *dev) { + * int rc = -1; + */ + + rc = wrap___xmknodat(ver, AT_FDCWD, path, mode, dev); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/__xmknodat.c b/ports/linux/guts/__xmknodat.c new file mode 100644 index 0000000..296918a --- /dev/null +++ b/ports/linux/guts/__xmknodat.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap___xmknodat(int ver, int dirfd, const char *path, mode_t mode, dev_t *dev) { + * int rc = -1; + */ + pseudo_msg_t *msg; + struct stat64 buf; + + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; + + /* we don't use underlying call, so _ver is irrelevant to us */ + (void) ver; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + rc = real___xstat64(_STAT_VER, path, &buf); +#else + rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, AT_SYMLINK_NOFOLLOW); +#endif + if (rc != -1) { + /* if we can stat the file, you can't mknod it */ + errno = EEXIST; + return -1; + } + if (!dev) { + errno = EINVAL; + return -1; + } +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real_open(path, O_CREAT | O_WRONLY | O_EXCL, + PSEUDO_FS_MODE(mode, 0)); +#else + rc = real_openat(dirfd, path, O_CREAT | O_WRONLY | O_EXCL, + PSEUDO_FS_MODE(mode, 0)); +#endif + if (rc == -1) { + return -1; + } + real_fchmod(rc, PSEUDO_FS_MODE(mode, 0)); + real___fxstat64(_STAT_VER, rc, &buf); + /* mknod does not really open the file. We don't have + * to use wrap_close because we've never exposed this file + * descriptor to the client code. + */ + real_close(rc); + + /* mask in the mode type bits again */ + buf.st_mode = (PSEUDO_DB_MODE(buf.st_mode, mode) & 07777) | + (mode & ~07777); + buf.st_rdev = *dev; + msg = pseudo_client_op(OP_MKNOD, 0, -1, dirfd, path, &buf); + if (msg && msg->result != RESULT_SUCCEED) { + errno = EPERM; + rc = -1; + } else { + /* just pretend we worked */ + rc = 0; + } + if (rc == -1) { + int save_errno = errno; +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + real_unlink(path); +#else + real_unlinkat(dirfd, path, AT_SYMLINK_NOFOLLOW); +#endif + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/ports/linux/guts/__xstat.c b/ports/linux/guts/__xstat.c new file mode 100644 index 0000000..ec10abb --- /dev/null +++ b/ports/linux/guts/__xstat.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap___xstat(int ver, const char *path, struct stat *buf) { + * int rc = -1; + */ + + rc = wrap___fxstatat(ver, AT_FDCWD, path, buf, 0); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/__xstat64.c b/ports/linux/guts/__xstat64.c new file mode 100644 index 0000000..ed62e7e --- /dev/null +++ b/ports/linux/guts/__xstat64.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap___xstat64(int ver, const char *path, struct stat64 *buf) { + * int rc = -1; + */ + rc = wrap___fxstatat64(ver, AT_FDCWD, path, buf, 0); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/canonicalize_file_name.c b/ports/linux/guts/canonicalize_file_name.c new file mode 100644 index 0000000..9a04f33 --- /dev/null +++ b/ports/linux/guts/canonicalize_file_name.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static char * + * wrap_canonicalize_file_name(const char *filename) { + * char * rc = NULL; + */ + + rc = wrap_realpath(filename, NULL); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/creat64.c b/ports/linux/guts/creat64.c new file mode 100644 index 0000000..2d2fc27 --- /dev/null +++ b/ports/linux/guts/creat64.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_creat64(const char *path, ...mode_t mode) { + * int rc = -1; + */ + + rc = wrap_openat(AT_FDCWD, path, O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE, mode); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/eaccess.c b/ports/linux/guts/eaccess.c new file mode 100644 index 0000000..e2119cc --- /dev/null +++ b/ports/linux/guts/eaccess.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_eaccess(const char *path, int mode) { + * int rc = -1; + */ + + rc = wrap_access(path, mode); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/euidaccess.c b/ports/linux/guts/euidaccess.c new file mode 100644 index 0000000..85433a8 --- /dev/null +++ b/ports/linux/guts/euidaccess.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_euidaccess(const char *path, int mode) { + * int rc = -1; + */ + + rc = wrap_access(path, mode); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/fcntl.c b/ports/linux/guts/fcntl.c new file mode 100644 index 0000000..639fd24 --- /dev/null +++ b/ports/linux/guts/fcntl.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_fcntl(int fd, int cmd, ...struct flock *lock) { + * int rc = -1; + */ + long arg; + int save_errno; + + /* we don't know whether we need lock or arg; grab both, which + * should be safe enough on Linuxy systems. */ + va_start(ap, cmd); + arg = va_arg(ap, long); + va_end(ap); + + switch (cmd) { + case F_DUPFD: +#ifdef F_DUPFD_CLOEXEC + case F_DUPFD_CLOEXEC: +#endif + /* actually do something */ + rc = real_fcntl(fd, cmd, arg); + save_errno = errno; + if (rc != -1) { + pseudo_debug(PDBGF_OP, "fcntl_dup: %d->%d\n", fd, rc); + pseudo_client_op(OP_DUP, 0, fd, rc, 0, 0); + } + errno = save_errno; + break; + /* no argument: */ + case F_GETFD: + case F_GETFL: + case F_GETOWN: + case F_GETSIG: + case F_GETLEASE: + rc = real_fcntl(fd, cmd); + break; + /* long argument */ + case F_SETFD: + case F_SETFL: + case F_SETOWN: + case F_SETSIG: + case F_SETLEASE: + case F_NOTIFY: + rc = real_fcntl(fd, cmd, arg); + break; + /* struct flock * argument */ + case F_GETLK: + case F_SETLK: + case F_SETLKW: + rc = real_fcntl(fd, cmd, lock); + break; +#if defined(F_GETLK64) && (F_GETLK64 != F_GETLK) + /* the cast is safe, all struct pointers must smell the same */ + case F_GETLK64: + case F_SETLK64: + case F_SETLKW64: + rc = real_fcntl(fd, cmd, (struct flock64 *) lock); + break; +#endif + default: + pseudo_diag("unknown fcntl argument %d, assuming long argument.\n", + cmd); + rc = real_fcntl(fd, cmd, arg); + break; + } +/* return rc; + * } + */ diff --git a/ports/linux/guts/fopen64.c b/ports/linux/guts/fopen64.c new file mode 100644 index 0000000..b243345 --- /dev/null +++ b/ports/linux/guts/fopen64.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static FILE * + * wrap_fopen64(const char *path, const char *mode) { + * FILE * rc = 0; + */ + struct stat64 buf; + int save_errno; + + int existed = (real___xstat64(_STAT_VER, path, &buf) != -1); + + rc = real_fopen64(path, mode); + save_errno = errno; + + if (rc) { + int fd = fileno(rc); + + pseudo_debug(PDBGF_FILE, "fopen64 '%s': fd %d <FILE %p>\n", path, fd, (void *) rc); + if (real___fxstat64(_STAT_VER, fd, &buf) != -1) { + if (!existed) { + real_fchmod(fd, PSEUDO_FS_MODE(0666 & ~pseudo_umask, 0)); + pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf); + } + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, &buf); + } else { + pseudo_debug(PDBGF_CONSISTENCY, "fopen64 (fd %d) succeeded, but fstat failed (%s).\n", + fd, strerror(errno)); + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, 0); + } + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/ports/linux/guts/freopen64.c b/ports/linux/guts/freopen64.c new file mode 100644 index 0000000..4bad533 --- /dev/null +++ b/ports/linux/guts/freopen64.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static FILE * + * wrap_freopen64(const char *path, const char *mode, FILE *stream) { + * FILE * rc = NULL; + */ + struct stat64 buf; + int save_errno; + int existed = (real___xstat64(_STAT_VER, path, &buf) != -1); + + rc = real_freopen64(path, mode, stream); + save_errno = errno; + + if (rc) { + int fd = fileno(rc); + + pseudo_debug(PDBGF_FILE, "freopen64 '%s': fd %d\n", path, fd); + if (real___fxstat64(_STAT_VER, fd, &buf) != -1) { + if (!existed) { + real_fchmod(fd, PSEUDO_FS_MODE(0666 & ~pseudo_umask, 0)); + pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf); + } + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, &buf); + } else { + pseudo_debug(PDBGF_FILE, "fopen (fd %d) succeeded, but stat failed (%s).\n", + fd, strerror(errno)); + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, 0); + } + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/ports/linux/guts/fstat.c b/ports/linux/guts/fstat.c new file mode 100644 index 0000000..2cf2787 --- /dev/null +++ b/ports/linux/guts/fstat.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fstat(int fd, struct stat *buf) + * int rc = -1; + */ + + rc = wrap___fxstat(_STAT_VER, fd, buf); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/fstat64.c b/ports/linux/guts/fstat64.c new file mode 100644 index 0000000..4a759f7 --- /dev/null +++ b/ports/linux/guts/fstat64.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fstat64(int fd, struct stat *buf) + * int rc = -1; + */ + + rc = wrap___fxstat64(_STAT_VER, fd, buf); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/ftw64.c b/ports/linux/guts/ftw64.c new file mode 100644 index 0000000..a375fbf --- /dev/null +++ b/ports/linux/guts/ftw64.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_ftw64(const char *path, int (*fn)(const char *, const struct stat64 *, int), int nopenfd) { + * int rc = -1; + */ + + rc = real_ftw64(path, fn, nopenfd); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/get_current_dir_name.c b/ports/linux/guts/get_current_dir_name.c new file mode 100644 index 0000000..79f82f9 --- /dev/null +++ b/ports/linux/guts/get_current_dir_name.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static char * + * wrap_get_current_dir_name(void) { + * char * rc = NULL; + */ + + /* this relies on a Linux extension, but we dutifully + * emulated that extension. + */ + rc = wrap_getcwd(NULL, 0); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/getgrent_r.c b/ports/linux/guts/getgrent_r.c new file mode 100644 index 0000000..b04373d --- /dev/null +++ b/ports/linux/guts/getgrent_r.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010-2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_getgrent_r(struct group *gbuf, char *buf, size_t buflen, struct group **gbufp) { + * int rc = -1; + */ + + /* note that we don't wrap fgetgrent_r, since there's no path + * references in it. + */ + if (!pseudo_grp) { + errno = ENOENT; + return -1; + } + rc = fgetgrent_r(pseudo_grp, gbuf, buf, buflen, gbufp); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/getgrouplist.c b/ports/linux/guts/getgrouplist.c new file mode 100644 index 0000000..3489ec9 --- /dev/null +++ b/ports/linux/guts/getgrouplist.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups) { + * int rc = -1; + */ + + int found = 0; + int found_group = 0; + char buf[PSEUDO_PWD_MAX]; + struct group grp, *gbuf = &grp; + + setgrent(); + while ((rc = wrap_getgrent_r(gbuf, buf, PSEUDO_PWD_MAX, &gbuf)) == 0) { + int i = 0; + for (i = 0; gbuf->gr_mem[i]; ++i) { + if (!strcmp(gbuf->gr_mem[i], user)) { + if (found < *ngroups) + groups[found] = gbuf->gr_gid; + ++found; + if (gbuf->gr_gid == group) + found_group = 1; + } + } + } + endgrent(); + if (!found_group) { + if (found < *ngroups) + groups[found] = group; + ++found; + } + if (found >= *ngroups) + rc = -1; + else + rc = found; + *ngroups = found; + +/* return rc; + * } + */ diff --git a/ports/linux/guts/getgroups.c b/ports/linux/guts/getgroups.c new file mode 100644 index 0000000..afb9662 --- /dev/null +++ b/ports/linux/guts/getgroups.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_getgroups(int size, gid_t *list) { + * int rc = -1; + */ + struct passwd *p = wrap_getpwuid(wrap_getuid()); + int oldsize = size; + + if (p) { + rc = wrap_getgrouplist(p->pw_name, wrap_getgid(), list, &size); + if (oldsize == 0 || size <= oldsize) + rc = size; + } else { + errno = ENOENT; + } + +/* return rc; + * } + */ diff --git a/ports/linux/guts/getpw.c b/ports/linux/guts/getpw.c new file mode 100644 index 0000000..62b44da --- /dev/null +++ b/ports/linux/guts/getpw.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_getpw(uid_t uid, char *buf) { + * int rc = -1; + */ + static struct passwd pwd; + static char pwbuf[PSEUDO_PWD_MAX]; + struct passwd *pwp; + + pseudo_diag("warning: unsafe getpw() called. hoping buf has at least %d chars.\n", + PSEUDO_PWD_MAX); + rc = wrap_getpwuid_r(uid, &pwd, pwbuf, PSEUDO_PWD_MAX, &pwp); + /* different error return conventions */ + if (rc != 0) { + errno = rc; + rc = -1; + } else { + snprintf(buf, PSEUDO_PWD_MAX, "%s:%s:%d:%d:%s:%s:%s", + pwd.pw_name, + pwd.pw_passwd, + pwd.pw_uid, + pwd.pw_gid, + pwd.pw_gecos, + pwd.pw_dir, + pwd.pw_shell); + } + +/* return rc; + * } + */ diff --git a/ports/linux/guts/getpwent_r.c b/ports/linux/guts/getpwent_r.c new file mode 100644 index 0000000..4fd9cc0 --- /dev/null +++ b/ports/linux/guts/getpwent_r.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010-2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp) { + * int rc = -1; + */ + + /* note that we don't wrap fgetpwent_r, since there's no path + * references in it. + */ + if (!pseudo_pwd) { + errno = ENOENT; + return -1; + } + rc = fgetpwent_r(pseudo_pwd, pwbuf, buf, buflen, pwbufp); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/getresgid.c b/ports/linux/guts/getresgid.c new file mode 100644 index 0000000..13551a4 --- /dev/null +++ b/ports/linux/guts/getresgid.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) { + * int rc = -1; + */ + if (rgid) + *rgid = pseudo_rgid; + if (egid) + *egid = pseudo_egid; + if (sgid) + *sgid = pseudo_sgid; + if (rgid && egid && sgid) { + rc = 0; + } else { + rc = -1; + errno = EFAULT; + } +/* return rc; + * } + */ diff --git a/ports/linux/guts/getresuid.c b/ports/linux/guts/getresuid.c new file mode 100644 index 0000000..2e47520 --- /dev/null +++ b/ports/linux/guts/getresuid.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) { + * int rc = -1; + */ + if (ruid) + *ruid = pseudo_ruid; + if (euid) + *euid = pseudo_euid; + if (suid) + *suid = pseudo_suid; + if (ruid && euid && suid) { + rc = 0; + } else { + rc = -1; + errno = EFAULT; + } +/* return rc; + * } + */ diff --git a/ports/linux/guts/glob64.c b/ports/linux/guts/glob64.c new file mode 100644 index 0000000..ccac6e4 --- /dev/null +++ b/ports/linux/guts/glob64.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_glob64(const char *pattern, int flags, int (*errfunc)(const char *, int), glob64_t *pglob) { + * int rc = -1; + */ + char *rpattern = NULL; + int alloced = 0; + + /* note: no canonicalization */ + if (pattern && (*pattern == '/') && pseudo_chroot_len) { + size_t len = strlen(pattern) + pseudo_chroot_len + 2; + rpattern = malloc(len); + if (!rpattern) { + errno = ENOMEM; + return GLOB_NOSPACE; + } + snprintf(rpattern, len, "%s/%s", pseudo_chroot, pattern); + alloced = 1; + } + + rc = real_glob64(alloced ? rpattern : pattern, flags, errfunc, pglob); + + free(rpattern); + + if (rc == 0) { + unsigned int i; + for (i = 0; i < pglob->gl_pathc; ++i) { + pseudo_dechroot(pglob->gl_pathv[i], (size_t) -1); + } + } +/* return rc; + * } + */ diff --git a/ports/linux/guts/lchown.c b/ports/linux/guts/lchown.c new file mode 100644 index 0000000..4eb1202 --- /dev/null +++ b/ports/linux/guts/lchown.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_lchown(const char *path, uid_t owner, gid_t group) { + */ + + rc = wrap_fchownat(AT_FDCWD, path, owner, group, AT_SYMLINK_NOFOLLOW); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/lckpwdf.c b/ports/linux/guts/lckpwdf.c new file mode 100644 index 0000000..b452ec0 --- /dev/null +++ b/ports/linux/guts/lckpwdf.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_lckpwdf(void) { + * int rc = -1; + */ + rc = pseudo_pwd_lck_open(); + if (rc != -1) { + struct flock lck = { + .l_type = F_RDLCK, + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 1 + }; + /* I don't really care whether this works. */ + fcntl(rc, F_SETFD, FD_CLOEXEC); + /* Now lock it. */ + alarm(15); /* magic number from man page */ + rc = fcntl(rc, F_SETLKW, &lck); + alarm(0); + if (rc == -1) { + int save_errno = errno; + pseudo_pwd_lck_close(); + errno = save_errno; + } + } + +/* return rc; + * } + */ diff --git a/ports/linux/guts/lstat.c b/ports/linux/guts/lstat.c new file mode 100644 index 0000000..19c202f --- /dev/null +++ b/ports/linux/guts/lstat.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int lstat(const char *path, struct stat *buf) + * int rc = -1; + */ + + rc = wrap___fxstatat(_STAT_VER, AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/lstat64.c b/ports/linux/guts/lstat64.c new file mode 100644 index 0000000..94eb60f --- /dev/null +++ b/ports/linux/guts/lstat64.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int lstat64(const char *path, struct stat *buf) + * int rc = -1; + */ + + rc = wrap___fxstatat64(_STAT_VER, AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/mkstemp64.c b/ports/linux/guts/mkstemp64.c new file mode 100644 index 0000000..48be612 --- /dev/null +++ b/ports/linux/guts/mkstemp64.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_mkstemp64(char *template) { + * int rc = -1; + */ + struct stat64 buf; + int save_errno; + size_t len; + char *tmp_template; + + if (!template) { + errno = EFAULT; + return 0; + } + + len = strlen(template); + tmp_template = PSEUDO_ROOT_PATH(AT_FDCWD, template, AT_SYMLINK_NOFOLLOW); + + if (!tmp_template) { + errno = ENOENT; + return -1; + } + + rc = real_mkstemp64(tmp_template); + + if (rc != -1) { + save_errno = errno; + + if (real___fxstat64(_STAT_VER, rc, &buf) != -1) { + real_fchmod(rc, PSEUDO_FS_MODE(0600, 0)); + pseudo_client_op(OP_CREAT, 0, -1, -1, tmp_template, &buf); + pseudo_client_op(OP_OPEN, PSA_READ | PSA_WRITE, rc, -1, tmp_template, &buf); + } else { + pseudo_debug(PDBGF_CONSISTENCY, "mkstemp (fd %d) succeeded, but fstat failed (%s).\n", + rc, strerror(errno)); + pseudo_client_op(OP_OPEN, PSA_READ | PSA_WRITE, rc, -1, tmp_template, 0); + } + errno = save_errno; + } + /* mkstemp only changes the XXXXXX at the end. */ + memcpy(template + len - 6, tmp_template + strlen(tmp_template) - 6, 6); +/* return rc; + * } + */ diff --git a/ports/linux/guts/nftw64.c b/ports/linux/guts/nftw64.c new file mode 100644 index 0000000..82571cd --- /dev/null +++ b/ports/linux/guts/nftw64.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_nftw64(const char *path, int (*fn)(const char *, const struct stat64 *, int, struct FTW *), int nopenfd, int flag) { + * int rc = -1; + */ + + rc = real_nftw64(path, fn, nopenfd, flag); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/open.c b/ports/linux/guts/open.c new file mode 100644 index 0000000..0a0596c --- /dev/null +++ b/ports/linux/guts/open.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_open(const char *path, int flags, ...mode_t mode) { + * int rc = -1; + */ + + return wrap_openat(AT_FDCWD, path, flags, mode); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/open64.c b/ports/linux/guts/open64.c new file mode 100644 index 0000000..8028ede --- /dev/null +++ b/ports/linux/guts/open64.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010,2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_open64(const char *path, int flags, ...mode_t mode) { + * int rc = -1; + */ + + rc = wrap_openat(AT_FDCWD, path, flags | O_LARGEFILE, mode); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/openat.c b/ports/linux/guts/openat.c new file mode 100644 index 0000000..eb7c0b5 --- /dev/null +++ b/ports/linux/guts/openat.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2008-2010, 2013 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_openat(int dirfd, const char *path, int flags, ...mode_t mode) { + * int rc = -1; + */ + struct stat64 buf; + int existed = 1; + int save_errno; + + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } +#endif + +#ifdef PSEUDO_FORCE_ASYNCH + /* Yes, I'm aware that every Linux system I've seen has + * DSYNC and RSYNC being the same value as SYNC. + */ + + flags &= ~(O_SYNC +#ifdef O_DIRECT + | O_DIRECT +#endif +#ifdef O_DSYNC + | O_DSYNC +#endif +#ifdef O_RSYNC + | O_RSYNC +#endif + ); +#endif + + /* if a creation has been requested, check whether file exists */ + if (flags & O_CREAT) { + save_errno = errno; +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real___xstat64(_STAT_VER, path, &buf); +#else + rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, 0); +#endif + existed = (rc != -1); + if (!existed) + pseudo_debug(PDBGF_FILE, "openat_creat: %s -> 0%o\n", path, mode); + errno = save_errno; + } + + /* because we are not actually root, secretly mask in 0600 to the + * underlying mode. The ", 0" is because the only time mode matters + * is if a file is going to be created, in which case it's + * not a directory. + */ +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real_open(path, flags, PSEUDO_FS_MODE(mode, 0)); +#else + rc = real_openat(dirfd, path, flags, PSEUDO_FS_MODE(mode, 0)); +#endif + save_errno = errno; + + if (rc != -1) { + int stat_rc; +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + stat_rc = real___xstat64(_STAT_VER, path, &buf); +#else + stat_rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, 0); +#endif + + if (stat_rc != -1) { + buf.st_mode = PSEUDO_DB_MODE(buf.st_mode, mode); + if (!existed) { + real_fchmod(rc, PSEUDO_FS_MODE(mode, 0)); + pseudo_client_op(OP_CREAT, 0, -1, dirfd, path, &buf); + } + pseudo_client_op(OP_OPEN, PSEUDO_ACCESS(flags), rc, dirfd, path, &buf); + } else { + pseudo_debug(PDBGF_FILE, "openat (fd %d, path %d/%s, flags %d) succeeded, but stat failed (%s).\n", + rc, dirfd, path, flags, strerror(errno)); + pseudo_client_op(OP_OPEN, PSEUDO_ACCESS(flags), rc, dirfd, path, 0); + } + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/ports/linux/guts/openat64.c b/ports/linux/guts/openat64.c new file mode 100644 index 0000000..8dedcbf --- /dev/null +++ b/ports/linux/guts/openat64.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010,2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_openat64(int dirfd, const char *path, int flags, ...mode_t mode) { + * int rc = -1; + */ + + rc = wrap_openat(dirfd, path, flags | O_LARGEFILE, mode); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/scandir.c b/ports/linux/guts/scandir.c new file mode 100644 index 0000000..afcebaf --- /dev/null +++ b/ports/linux/guts/scandir.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_scandir(const char *path, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)(const void *, const void *)) { + * int rc = -1; + */ + + rc = real_scandir(path, namelist, filter, compar); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/scandir64.c b/ports/linux/guts/scandir64.c new file mode 100644 index 0000000..1317b73 --- /dev/null +++ b/ports/linux/guts/scandir64.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_scandir64(const char *path, struct dirent64 ***namelist, int (*filter)(const struct dirent64 *), int (*compar)(const void *, const void *)) { + * int rc = -1; + */ + + rc = real_scandir64(path, namelist, filter, compar); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/setfsgid.c b/ports/linux/guts/setfsgid.c new file mode 100644 index 0000000..0e5a10b --- /dev/null +++ b/ports/linux/guts/setfsgid.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_setfsgid(gid_t fsgid) { + * int rc = -1; + */ + if (pseudo_euid == 0 || + pseudo_egid == fsgid || pseudo_rgid == fsgid || pseudo_sgid == fsgid) { + pseudo_fgid = fsgid; + rc = 0; + } else { + rc = -1; + errno = EPERM; + } +/* return rc; + * } + */ diff --git a/ports/linux/guts/setfsuid.c b/ports/linux/guts/setfsuid.c new file mode 100644 index 0000000..e52b65e --- /dev/null +++ b/ports/linux/guts/setfsuid.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_setfsuid(uid_t fsuid) { + * int rc = -1; + */ + if (pseudo_euid == 0 || + pseudo_euid == fsuid || pseudo_ruid == fsuid || pseudo_suid == fsuid) { + pseudo_fuid = fsuid; + rc = 0; + } else { + rc = -1; + errno = EPERM; + } +/* return rc; + * } + */ diff --git a/ports/linux/guts/setgroups.c b/ports/linux/guts/setgroups.c new file mode 100644 index 0000000..31b2b57 --- /dev/null +++ b/ports/linux/guts/setgroups.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_setgroups(size_t size, const gid_t *list) { + * int rc = -1; + */ + + /* let gcc know we're ignoring these */ + (void) size; + (void) list; + /* you always have all group privileges. we're like magic! */ + rc = 0; + +/* return rc; + * } + */ diff --git a/ports/linux/guts/setresgid.c b/ports/linux/guts/setresgid.c new file mode 100644 index 0000000..2a26405 --- /dev/null +++ b/ports/linux/guts/setresgid.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid) { + * int rc = -1; + */ + rc = 0; + if (pseudo_euid != 0 && rgid != (gid_t) -1 && + rgid != pseudo_egid && rgid != pseudo_rgid && rgid != pseudo_sgid) { + rc = -1; + errno = EPERM; + } + if (pseudo_euid != 0 && egid != (gid_t) -1 && + egid != pseudo_egid && egid != pseudo_rgid && egid != pseudo_sgid) { + rc = -1; + errno = EPERM; + } + if (pseudo_euid != 0 && sgid != (gid_t) -1 && + sgid != pseudo_egid && sgid != pseudo_rgid && sgid != pseudo_sgid) { + rc = -1; + errno = EPERM; + } + if (rc != -1) { + if (rgid != (gid_t) -1) + pseudo_rgid = rgid; + if (egid != (gid_t) -1) + pseudo_egid = egid; + if (sgid != (gid_t) -1) + pseudo_sgid = sgid; + pseudo_fgid = pseudo_egid; + pseudo_client_touchuid(); + } +/* return rc; + * } + */ diff --git a/ports/linux/guts/setresuid.c b/ports/linux/guts/setresuid.c new file mode 100644 index 0000000..a0a367f --- /dev/null +++ b/ports/linux/guts/setresuid.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_setresuid(uid_t ruid, uid_t euid, uid_t suid) { + * int rc = -1; + */ + rc = 0; + if (pseudo_euid != 0 && ruid != (uid_t) -1 && + ruid != pseudo_euid && ruid != pseudo_ruid && ruid != pseudo_suid) { + rc = -1; + errno = EPERM; + } + if (pseudo_euid != 0 && euid != (uid_t) -1 && + euid != pseudo_euid && euid != pseudo_ruid && euid != pseudo_suid) { + rc = -1; + errno = EPERM; + } + if (pseudo_euid != 0 && suid != (uid_t) -1 && + suid != pseudo_euid && suid != pseudo_ruid && suid != pseudo_suid) { + rc = -1; + errno = EPERM; + } + if (rc != -1) { + if (ruid != (uid_t) -1) + pseudo_ruid = ruid; + if (euid != (uid_t) -1) + pseudo_euid = euid; + if (suid != (uid_t) -1) + pseudo_suid = suid; + pseudo_fuid = pseudo_euid; + pseudo_client_touchuid(); + } +/* return rc; + * } + */ diff --git a/ports/linux/guts/stat.c b/ports/linux/guts/stat.c new file mode 100644 index 0000000..1fe800e --- /dev/null +++ b/ports/linux/guts/stat.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int stat(const char *path, struct stat *buf) + * int rc = -1; + */ + + rc = wrap___fxstatat(_STAT_VER, AT_FDCWD, path, buf, 0); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/stat64.c b/ports/linux/guts/stat64.c new file mode 100644 index 0000000..53dd156 --- /dev/null +++ b/ports/linux/guts/stat64.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int stat64(const char *path, struct stat *buf) + * int rc = -1; + */ + + rc = wrap___fxstatat64(_STAT_VER, AT_FDCWD, path, buf, 0); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/truncate64.c b/ports/linux/guts/truncate64.c new file mode 100644 index 0000000..a798984 --- /dev/null +++ b/ports/linux/guts/truncate64.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_truncate64(const char *path, off64_t length) { + * int rc = -1; + */ + + rc = real_truncate64(path, length); + +/* return rc; + * } + */ diff --git a/ports/linux/guts/ulckpwdf.c b/ports/linux/guts/ulckpwdf.c new file mode 100644 index 0000000..ed6a671 --- /dev/null +++ b/ports/linux/guts/ulckpwdf.c @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_ulckpwdf(void) { + * int rc = -1; + */ + + /* lock is cleared automatically on close */ + rc = pseudo_pwd_lck_close(); + +/* return rc; + * } + */ diff --git a/ports/linux/newclone/guts/clone.c b/ports/linux/newclone/guts/clone.c new file mode 100644 index 0000000..ee6fc09 --- /dev/null +++ b/ports/linux/newclone/guts/clone.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2008-2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * clone(...) { + * .... + */ + /* because clone() doesn't actually continue in this function, we + * can't check the return and fix up environment variables in the + * child. Instead, we have to create an intermediate function, + * wrap_clone_child, which does this fix up. + */ + + struct clone_args * myargs = malloc(sizeof(struct clone_args)); + + myargs->fn = fn; + myargs->flags = flags; + myargs->arg = arg; + + /* call the real syscall */ + rc = (*real_clone)(wrap_clone_child, child_stack, flags, myargs, pid, tls, ctid); + + /* If we're not sharing memory, we need to free myargs in the parent */ + if (!(flags & CLONE_VM)) + free(myargs); + +/* ... + * return rc; + * } + */ diff --git a/ports/linux/newclone/pseudo_wrappers.c b/ports/linux/newclone/pseudo_wrappers.c new file mode 100644 index 0000000..1fc6c59 --- /dev/null +++ b/ports/linux/newclone/pseudo_wrappers.c @@ -0,0 +1,92 @@ +static int +wrap_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, va_list +ap) { + /* unused */ + (void) fn; + (void) child_stack; + (void) flags; + (void) arg; + (void) ap; + return 0; +} + +struct clone_args { + int (*fn)(void *); + int flags; + void *arg; +}; + +int wrap_clone_child(void *args) { + struct clone_args *clargs = args; + + int (*fn)(void *) = clargs->fn; + int flags = clargs->flags; + void *arg = clargs->arg; + + /* We always free in the client */ + free(clargs); + + if (!(flags & CLONE_VM)) { + pseudo_setupenv(); + if (!pseudo_has_unload(NULL)) { + pseudo_reinit_libpseudo(); + } else { + pseudo_dropenv(); + } + } + + return fn(arg); +} + +int +clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...) { + sigset_t saved; + va_list ap; + pid_t *pid; + struct user_desc *tls; + pid_t *ctid; + + int rc = -1; + + if (!pseudo_check_wrappers() || !real_clone) { + /* rc was initialized to the "failure" value */ + pseudo_enosys("clone"); + return rc; + } + + va_start(ap, arg); + pid = va_arg(ap, pid_t *); + tls = va_arg(ap, struct user_desc *); + ctid = va_arg(ap, pid_t *); + va_end(ap); + + pseudo_debug(PDBGF_WRAPPER, "called: clone\n"); + pseudo_sigblock(&saved); + if (pseudo_getlock()) { + errno = EBUSY; + sigprocmask(SIG_SETMASK, &saved, NULL); + return -1; + } + + int save_errno; + int save_disabled = pseudo_disabled; + +#include "guts/clone.c" + + if (save_disabled != pseudo_disabled) { + if (pseudo_disabled) { + pseudo_disabled = 0; + pseudo_magic(); + } else { + pseudo_disabled = 1; + pseudo_antimagic(); + } + } + + save_errno = errno; + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(PDBGF_WRAPPER, "completed: clone\n"); + errno = save_errno; + return rc; +} diff --git a/ports/linux/newclone/wrapfuncs.in b/ports/linux/newclone/wrapfuncs.in new file mode 100644 index 0000000..8849310 --- /dev/null +++ b/ports/linux/newclone/wrapfuncs.in @@ -0,0 +1 @@ +int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...); /* hand_wrapped=1 */ diff --git a/ports/linux/noxattr/guts/fgetxattr.c b/ports/linux/noxattr/guts/fgetxattr.c new file mode 100644 index 0000000..9d33643 --- /dev/null +++ b/ports/linux/noxattr/guts/fgetxattr.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size) + * ssize_t rc = -1; + */ + + /* suppress warnings */ + (void) filedes; + (void) name; + (void) value; + (void) size; + errno = ENOTSUP; + +/* return rc; + * } + */ diff --git a/ports/linux/noxattr/guts/flistxattr.c b/ports/linux/noxattr/guts/flistxattr.c new file mode 100644 index 0000000..77db021 --- /dev/null +++ b/ports/linux/noxattr/guts/flistxattr.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t flistxattr(int filedes, char *list, size_t size) + * ssize_t rc = -1; + */ + + /* suppress warnings */ + (void) filedes; + (void) list; + (void) size; + errno = ENOTSUP; + +/* return rc; + * } + */ diff --git a/ports/linux/noxattr/guts/fremovexattr.c b/ports/linux/noxattr/guts/fremovexattr.c new file mode 100644 index 0000000..529a9de --- /dev/null +++ b/ports/linux/noxattr/guts/fremovexattr.c @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fremovexattr(int filedes, const char *name) + * int rc = -1; + */ + + /* suppress warnings */ + (void) filedes; + (void) name; + errno = ENOTSUP; + +/* return rc; + * } + */ diff --git a/ports/linux/noxattr/guts/fsetxattr.c b/ports/linux/noxattr/guts/fsetxattr.c new file mode 100644 index 0000000..3c56ddd --- /dev/null +++ b/ports/linux/noxattr/guts/fsetxattr.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags) + * int rc = -1; + */ + + /* suppress warnings */ + (void) filedes; + (void) name; + (void) value; + (void) size; + (void) flags; + errno = ENOTSUP; + +/* return rc; + * } + */ diff --git a/ports/linux/noxattr/guts/getxattr.c b/ports/linux/noxattr/guts/getxattr.c new file mode 100644 index 0000000..fe8912d --- /dev/null +++ b/ports/linux/noxattr/guts/getxattr.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t getxattr(const char *pathname, const char *name, void *value, size_t size) + * ssize_t rc = -1; + */ + + /* suppress warnings */ + (void) pathname; + (void) name; + (void) value; + (void) size; + errno = ENOTSUP; + +/* return rc; + * } + */ diff --git a/ports/linux/noxattr/guts/lgetxattr.c b/ports/linux/noxattr/guts/lgetxattr.c new file mode 100644 index 0000000..404211f --- /dev/null +++ b/ports/linux/noxattr/guts/lgetxattr.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t lgetxattr(const char *pathname, const char *name, void *value, size_t size) + * ssize_t rc = -1; + */ + + /* suppress warnings */ + (void) pathname; + (void) name; + (void) value; + (void) size; + errno = ENOTSUP; + +/* return rc; + * } + */ diff --git a/ports/linux/noxattr/guts/listxattr.c b/ports/linux/noxattr/guts/listxattr.c new file mode 100644 index 0000000..1b0b5e7 --- /dev/null +++ b/ports/linux/noxattr/guts/listxattr.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t listxattr(const char *pathname, char *list, size_t size) + * ssize_t rc = -1; + */ + + /* suppress warnings */ + (void) pathname; + (void) list; + (void) size; + errno = ENOTSUP; + +/* return rc; + * } + */ diff --git a/ports/linux/noxattr/guts/llistxattr.c b/ports/linux/noxattr/guts/llistxattr.c new file mode 100644 index 0000000..a33f970 --- /dev/null +++ b/ports/linux/noxattr/guts/llistxattr.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t llistxattr(const char *pathname, char *list, size_t size) + * ssize_t rc = -1; + */ + + /* suppress warnings */ + (void) pathname; + (void) list; + (void) size; + errno = ENOTSUP; + +/* return rc; + * } + */ diff --git a/ports/linux/noxattr/guts/lremovexattr.c b/ports/linux/noxattr/guts/lremovexattr.c new file mode 100644 index 0000000..38429da --- /dev/null +++ b/ports/linux/noxattr/guts/lremovexattr.c @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int lremovexattr(const char *pathname, const char *name) + * int rc = -1; + */ + + /* suppress warnings */ + (void) pathname; + (void) name; + errno = ENOTSUP; + +/* return rc; + * } + */ diff --git a/ports/linux/noxattr/guts/lsetxattr.c b/ports/linux/noxattr/guts/lsetxattr.c new file mode 100644 index 0000000..140ae8d --- /dev/null +++ b/ports/linux/noxattr/guts/lsetxattr.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int lsetxattr(const char *pathname, const char *name, const void *value, size_t size, int flags) + * int rc = -1; + */ + + /* suppress warnings */ + (void) pathname; + (void) name; + (void) value; + (void) size; + (void) flags; + errno = ENOTSUP; + +/* return rc; + * } + */ diff --git a/ports/linux/noxattr/guts/removexattr.c b/ports/linux/noxattr/guts/removexattr.c new file mode 100644 index 0000000..cd7f486 --- /dev/null +++ b/ports/linux/noxattr/guts/removexattr.c @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int removexattr(const char *pathname, const char *name) + * int rc = -1; + */ + + /* suppress warnings */ + (void) pathname; + (void) name; + errno = ENOTSUP; + +/* return rc; + * } + */ diff --git a/ports/linux/noxattr/guts/setxattr.c b/ports/linux/noxattr/guts/setxattr.c new file mode 100644 index 0000000..de2de98 --- /dev/null +++ b/ports/linux/noxattr/guts/setxattr.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int setxattr(const char *pathname, const char *name, const void *value, size_t size, int flags) + * int rc = -1; + */ + + /* suppress warnings */ + (void) pathname; + (void) name; + (void) value; + (void) size; + (void) flags; + errno = ENOTSUP; + +/* return rc; + * } + */ diff --git a/ports/linux/noxattr/wrapfuncs.in b/ports/linux/noxattr/wrapfuncs.in new file mode 100644 index 0000000..de22ae1 --- /dev/null +++ b/ports/linux/noxattr/wrapfuncs.in @@ -0,0 +1,14 @@ +# we use "pathname" to avoid canonicalizing paths, because these functions are +# unimplemented +ssize_t getxattr(const char *pathname, const char *name, void *value, size_t size); +ssize_t lgetxattr(const char *pathname, const char *name, void *value, size_t size); +ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size); +ssize_t listxattr(const char *pathname, char *list, size_t size); +ssize_t llistxattr(const char *pathname, char *list, size_t size); +ssize_t flistxattr(int filedes, char *list, size_t size); +int setxattr(const char *pathname, const char *name, const void *value, size_t size, int flags); +int lsetxattr(const char *pathname, const char *name, const void *value, size_t size, int flags); +int fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags); +int removexattr(const char *pathname, const char *name); +int lremovexattr(const char *pathname, const char *name); +int fremovexattr(int filedes, const char *name); diff --git a/ports/linux/oldclone/guts/clone.c b/ports/linux/oldclone/guts/clone.c new file mode 100644 index 0000000..c6771e5 --- /dev/null +++ b/ports/linux/oldclone/guts/clone.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2008-2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * clone(...) { + * .... + */ + /* because clone() doesn't actually continue in this function, we + * can't check the return and fix up environment variables in the + * child. Instead, we have to create an intermediate function, + * wrap_clone_child, which does this fix up. + */ + + struct clone_args * myargs = malloc(sizeof(struct clone_args)); + + myargs->fn = fn; + myargs->flags = flags; + myargs->arg = arg; + + /* call the real syscall */ + rc = (*real_clone)(wrap_clone_child, child_stack, flags, myargs); + + /* If we're not sharing memory, we need to free myargs in the parent */ + if (!(flags & CLONE_VM)) + free(myargs); + +/* ... + * return rc; + * } + */ diff --git a/ports/linux/oldclone/pseudo_wrappers.c b/ports/linux/oldclone/pseudo_wrappers.c new file mode 100644 index 0000000..1720dfb --- /dev/null +++ b/ports/linux/oldclone/pseudo_wrappers.c @@ -0,0 +1,76 @@ +static int +wrap_clone(int (*fn)(void *), void *child_stack, int flags, void *arg) { + /* unused */ + return 0; +} + +struct clone_args { + int (*fn)(void *); + int flags; + void *arg; +}; + +int wrap_clone_child(void *args) { + struct clone_args *clargs = args; + + int (*fn)(void *) = clargs->fn; + int flags = clargs->flags; + void *arg = clargs->arg; + + /* We always free in the client */ + free(clargs); + + if (!(flags & CLONE_VM)) { + pseudo_setupenv(); + if (!pseudo_has_unload(NULL)) { + pseudo_reinit_libpseudo(); + } else { + pseudo_dropenv(); + } + } + + return fn(arg); +} + +int +clone(int (*fn)(void *), void *child_stack, int flags, void *arg) { + sigset_t saved; + + int rc = -1; + + if (!pseudo_check_wrappers() || !real_clone) { + /* rc was initialized to the "failure" value */ + pseudo_enosys("clone"); + return rc; + } + + pseudo_debug(PDBGF_WRAPPER, "called: clone\n"); + pseudo_sigblock(&saved); + if (pseudo_getlock()) { + errno = EBUSY; + sigprocmask(SIG_SETMASK, &saved, NULL); + return -1; + } + + int save_errno; + int save_disabled = pseudo_disabled; + +#include "guts/clone.c" + + if (save_disabled != pseudo_disabled) { + if (pseudo_disabled) { + pseudo_disabled = 0; + pseudo_magic(); + } else { + pseudo_disabled = 1; + pseudo_antimagic(); + } + } + + save_errno = errno; + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(PDBGF_WRAPPER, "completed: clone\n"); + errno = save_errno; + return rc; +} diff --git a/ports/linux/oldclone/wrapfuncs.in b/ports/linux/oldclone/wrapfuncs.in new file mode 100644 index 0000000..c915376 --- /dev/null +++ b/ports/linux/oldclone/wrapfuncs.in @@ -0,0 +1 @@ +int clone(int (*fn)(void *), void *child_stack, int flags, void *arg); /* hand_wrapped=1 */ diff --git a/ports/linux/portdefs.h b/ports/linux/portdefs.h new file mode 100644 index 0000000..f0a0e40 --- /dev/null +++ b/ports/linux/portdefs.h @@ -0,0 +1,27 @@ +#define PRELINK_LIBRARIES "LD_PRELOAD" +#define PRELINK_PATH "LD_LIBRARY_PATH" +#define PSEUDO_STATBUF_64 1 +#define PSEUDO_STATBUF struct stat64 +#define PSEUDO_LINKPATH_SEPARATOR " " +/* Linux NEVER follows symlinks for link(2)... except on old kernels + * I don't care about. + */ +#undef PSEUDO_LINK_SYMLINK_BEHAVIOR +/* Note: 0, here, really means AT_SYMLINK_NOFOLLOW, but specifying that + * causes errors; you have to leave it empty or specify AT_SYMLINK_FOLLOW. + */ +#define PSEUDO_LINK_SYMLINK_BEHAVIOR 0 + +/* There were symbol changes that can cause the linker to request + * newer versions of glibc, which causes problems occasionally on + * older hosts if pseudo is built against a newer glibc and then + * run with an older one. Sometimes we can just avoid the symbols, + * but memcpy's pretty hard to get away from. + */ +#define GLIBC_COMPAT_SYMBOL(sym, ver) __asm(".symver " #sym "," #sym "@GLIBC_" #ver) + +#ifdef __amd64__ +GLIBC_COMPAT_SYMBOL(memcpy,2.2.5); +#elif defined(__i386__) +GLIBC_COMPAT_SYMBOL(memcpy,2.0); +#endif diff --git a/ports/linux/preports b/ports/linux/preports new file mode 100755 index 0000000..a996c69 --- /dev/null +++ b/ports/linux/preports @@ -0,0 +1,2 @@ +#!/bin/sh +echo "unix" "uids_generic" diff --git a/ports/linux/pseudo_wrappers.c b/ports/linux/pseudo_wrappers.c new file mode 100644 index 0000000..26b29b0 --- /dev/null +++ b/ports/linux/pseudo_wrappers.c @@ -0,0 +1,33 @@ +/* the unix port wants to know that real_stat() and + * friends exist. So they do. And because the Linux + * port really uses stat64 for those... + */ +int +pseudo_stat(const char *path, struct stat *buf) { + return real___xstat(_STAT_VER, path, buf); +} + +int +pseudo_lstat(const char *path, struct stat *buf) { + return real___lxstat(_STAT_VER, path, buf); +} + +int +pseudo_fstat(int fd, struct stat *buf) { + return real___fxstat(_STAT_VER, fd, buf); +} + +int +pseudo_stat64(const char *path, struct stat64 *buf) { + return real___xstat64(_STAT_VER, path, buf); +} + +int +pseudo_lstat64(const char *path, struct stat64 *buf) { + return real___lxstat64(_STAT_VER, path, buf); +} + +int +pseudo_fstat64(int fd, struct stat64 *buf) { + return real___fxstat64(_STAT_VER, fd, buf); +} diff --git a/ports/linux/subports b/ports/linux/subports new file mode 100755 index 0000000..507794e --- /dev/null +++ b/ports/linux/subports @@ -0,0 +1,43 @@ +#!/bin/sh +found=false +printf >&2 "Checking for old/new clone mechanics... " +cat > dummy.c <<EOF +#include <sched.h> +int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...) { return 0; } +EOF +if ${CC} -c -o dummy.o dummy.c >/dev/null 2>&1; then + rm -f dummy.c dummy.o + echo >&2 "New clone." + echo "linux/newclone" + found=true +fi +cat > dummy.c <<EOF +#include <sched.h> +int clone(int (*fn)(void *), void *child_stack, int flags, void *arg) { return 0; } +EOF +if ! $found && ${CC} -c -o dummy.o dummy.c >/dev/null 2>&1; then + rm -f dummy.c dummy.o + echo >&2 "Old clone." + echo "linux/oldclone" + found=true +fi +rm -f dummy.c dummy.o +if ! $found; then + echo >&2 "Can't tell, omitting clone(2) support." +fi + +if $port_xattr; then + cat > dummy.c <<EOF +#include <sys/types.h> +#include <attr/xattr.h> +int i; +EOF + if ! ${CC} -c -o dummy.o dummy.c >/dev/null 2>&1; then + echo >&2 "Warning: Can't compile trivial program using <attr/xattr.h>". + echo >&2 " xattr support will require that header." + fi + echo "linux/xattr" +else + echo "linux/noxattr" +fi +rm -f dummy.c dummy.o diff --git a/ports/linux/wrapfuncs.in b/ports/linux/wrapfuncs.in new file mode 100644 index 0000000..3b8955a --- /dev/null +++ b/ports/linux/wrapfuncs.in @@ -0,0 +1,53 @@ +int open(const char *path, int flags, ...{mode_t mode}); /* flags=0 */ +char *get_current_dir_name(void); +int __xstat(int ver, const char *path, struct stat *buf); +int __lxstat(int ver, const char *path, struct stat *buf); /* flags=AT_SYMLINK_NOFOLLOW */ +int __fxstat(int ver, int fd, struct stat *buf); +int lchown(const char *path, uid_t owner, gid_t group); /* flags=AT_SYMLINK_NOFOLLOW */ +int __fxstatat(int ver, int dirfd, const char *path, struct stat *buf, int flags); +int openat(int dirfd, const char *path, int flags, ...{mode_t mode}); +int __openat_2(int dirfd, const char *path, int flags); +int __xmknod(int ver, const char *path, mode_t mode, dev_t *dev); /* flags=AT_SYMLINK_NOFOLLOW */ +int __xmknodat(int ver, int dirfd, const char *path, mode_t mode, dev_t *dev); /* flags=AT_SYMLINK_NOFOLLOW */ +int fcntl(int fd, int cmd, ...{struct flock *lock}); +# just so we know the inums of symlinks +char *canonicalize_file_name(const char *filename); +int eaccess(const char *path, int mode); +int open64(const char *path, int flags, ...{mode_t mode}); /* flags=0 */ +int openat64(int dirfd, const char *path, int flags, ...{mode_t mode}); /* flags=0 */ +int __openat64_2(int dirfd, const char *path, int flags); /* flags=0 */ +int creat64(const char *path, mode_t mode); +int stat(const char *path, struct stat *buf); /* real_func=pseudo_stat */ +int lstat(const char *path, struct stat *buf); /* real_func=pseudo_lstat, flags=AT_SYMLINK_NOFOLLOW */ +int fstat(int fd, struct stat *buf); /* real_func=pseudo_fstat */ +int stat64(const char *path, struct stat64 *buf); /* real_func=pseudo_stat64 */ +int lstat64(const char *path, struct stat64 *buf); /* real_func=pseudo_lstat64, flags=AT_SYMLINK_NOFOLLOW */ +int fstat64(int fd, struct stat64 *buf); /* real_func=pseudo_fstat64 */ +int __xstat64(int ver, const char *path, struct stat64 *buf); +int __lxstat64(int ver, const char *path, struct stat64 *buf); /* flags=AT_SYMLINK_NOFOLLOW */ +int __fxstat64(int ver, int fd, struct stat64 *buf); +int __fxstatat64(int ver, int dirfd, const char *path, struct stat64 *buf, int flags); +FILE *fopen64(const char *path, const char *mode); +int nftw64(const char *path, int (*fn)(const char *, const struct stat64 *, int, struct FTW *), int nopenfd, int flag); +FILE *freopen64(const char *path, const char *mode, FILE *stream); +int ftw64(const char *path, int (*fn)(const char *, const struct stat64 *, int), int nopenfd); +int glob64(const char *pattern, int flags, int (*errfunc)(const char *, int), glob64_t *pglob); +int scandir64(const char *path, struct dirent64 ***namelist, int (*filter)(const struct dirent64 *), int (*compar)()); +int truncate64(const char *path, off64_t length); +int mkstemp64(char *template); /* flags=AT_SYMLINK_NOFOLLOW */ +int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups); +int setgroups(size_t size, const gid_t *list); +int setfsgid(gid_t fsgid); +int setfsuid(uid_t fsuid); +int setresgid(gid_t rgid, gid_t egid, gid_t sgid); +int setresuid(uid_t ruid, uid_t euid, uid_t suid); +int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); +int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); +int scandir(const char *path, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)()); +int getgroups(int size, gid_t *list); +int lckpwdf(void); +int ulckpwdf(void); +int euidaccess(const char *path, int mode); +int getpw(uid_t uid, char *buf); +int getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp); +int getgrent_r(struct group *gbuf, char *buf, size_t buflen, struct group **gbufp); diff --git a/ports/linux/xattr/guts/fgetxattr.c b/ports/linux/xattr/guts/fgetxattr.c new file mode 100644 index 0000000..ae8c3a3 --- /dev/null +++ b/ports/linux/xattr/guts/fgetxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size) + * ssize_t rc = -1; + */ + rc = shared_getxattr(NULL, filedes, name, value, size); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/flistxattr.c b/ports/linux/xattr/guts/flistxattr.c new file mode 100644 index 0000000..cdd9454 --- /dev/null +++ b/ports/linux/xattr/guts/flistxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t flistxattr(int filedes, char *list, size_t size) + * ssize_t rc = -1; + */ + rc = shared_listxattr(NULL, filedes, list, size); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/fremovexattr.c b/ports/linux/xattr/guts/fremovexattr.c new file mode 100644 index 0000000..a029d2c --- /dev/null +++ b/ports/linux/xattr/guts/fremovexattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fremovexattr(int filedes, const char *name) + * int rc = -1; + */ + rc = shared_removexattr(NULL, filedes, name); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/fsetxattr.c b/ports/linux/xattr/guts/fsetxattr.c new file mode 100644 index 0000000..376cf08 --- /dev/null +++ b/ports/linux/xattr/guts/fsetxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fsetxattr(int filedes, const char *name, const void *value, size_t size, int xflags) + * int rc = -1; + */ + rc = shared_setxattr(NULL, filedes, name, value, size, xflags); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/getxattr.c b/ports/linux/xattr/guts/getxattr.c new file mode 100644 index 0000000..7bd2bf5 --- /dev/null +++ b/ports/linux/xattr/guts/getxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t getxattr(const char *path, const char *name, void *value, size_t size) + * ssize_t rc = -1; + */ + rc = shared_getxattr(path, -1, name, value, size); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/lgetxattr.c b/ports/linux/xattr/guts/lgetxattr.c new file mode 100644 index 0000000..675d3da --- /dev/null +++ b/ports/linux/xattr/guts/lgetxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size) + * ssize_t rc = -1; + */ + rc = shared_getxattr(path, -1, name, value, size); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/listxattr.c b/ports/linux/xattr/guts/listxattr.c new file mode 100644 index 0000000..0decf71 --- /dev/null +++ b/ports/linux/xattr/guts/listxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t listxattr(const char *path, char *list, size_t size) + * ssize_t rc = -1; + */ + rc = shared_listxattr(path, -1, list, size); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/llistxattr.c b/ports/linux/xattr/guts/llistxattr.c new file mode 100644 index 0000000..9934256 --- /dev/null +++ b/ports/linux/xattr/guts/llistxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t llistxattr(const char *path, char *list, size_t size) + * ssize_t rc = -1; + */ + rc = shared_listxattr(path, -1, list, size); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/lremovexattr.c b/ports/linux/xattr/guts/lremovexattr.c new file mode 100644 index 0000000..1f39788 --- /dev/null +++ b/ports/linux/xattr/guts/lremovexattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int lremovexattr(const char *path, const char *name) + * int rc = -1; + */ + rc = shared_removexattr(path, -1, name); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/lsetxattr.c b/ports/linux/xattr/guts/lsetxattr.c new file mode 100644 index 0000000..9fe35bc --- /dev/null +++ b/ports/linux/xattr/guts/lsetxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int lsetxattr(const char *path, const char *name, const void *value, size_t size, int xflags) + * int rc = -1; + */ + rc = shared_setxattr(path, -1, name, value, size, xflags); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/removexattr.c b/ports/linux/xattr/guts/removexattr.c new file mode 100644 index 0000000..0d4d8e3 --- /dev/null +++ b/ports/linux/xattr/guts/removexattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int removexattr(const char *path, const char *name) + * int rc = -1; + */ + rc = shared_removexattr(path, -1, name); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/setxattr.c b/ports/linux/xattr/guts/setxattr.c new file mode 100644 index 0000000..bace0d8 --- /dev/null +++ b/ports/linux/xattr/guts/setxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int setxattr(const char *path, const char *name, const void *value, size_t size, int xflags) + * int rc = -1; + */ + rc = shared_setxattr(path, -1, name, value, size, xflags); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/portdefs.h b/ports/linux/xattr/portdefs.h new file mode 100644 index 0000000..367ca60 --- /dev/null +++ b/ports/linux/xattr/portdefs.h @@ -0,0 +1,2 @@ +#include <attr/xattr.h> +#include <stdint.h> diff --git a/ports/linux/xattr/pseudo_wrappers.c b/ports/linux/xattr/pseudo_wrappers.c new file mode 100644 index 0000000..46bc053 --- /dev/null +++ b/ports/linux/xattr/pseudo_wrappers.c @@ -0,0 +1,233 @@ +/* shared functionality for the xattr code */ +/* Each of these functions is expecting to get an optional name, and + * a populated statbuf to use for sending messages to the server. + */ + +/* to avoid namespace pollution and such, we now duplicate the + * basic functionality of a POSIX ACL list, as used by libacl or + * the kernel. Documentation was obtained from the headers of libacl + * and from a page or two of _The Linux Programming Interface_, by + * Michael Kerrisk. + */ + +typedef struct { + uint16_t tag; + uint16_t perm; + uint32_t id; +} acl_entry; + +typedef struct { + uint32_t version; + acl_entry entries[]; +} acl_header; + +enum acl_tags { + ACL_UNDEFINED = 0x0, + ACL_USER_OBJ = 0x1, + ACL_USER = 0x2, + ACL_GROUP_OBJ = 0x4, + ACL_GROUP = 0x8, + ACL_MASK = 0x10, + ACL_OTHER = 0x20, +}; + +static const int endian_test = 1; +static const char *endian_tester = (char *) &endian_test; + +static inline int +le16(int x16) { + if (*endian_tester) { + return x16; + } else { + return ((x16 & 0xff) << 8) | ((x16 & 0xff00) >> 8); + } +} + +static inline int +le32(int x32) { + if (*endian_tester) { + return x32; + } else { + return ((x32 & 0xff) << 24) | ((x32 & 0xff00) << 8) | + ((x32 & 0xff0000) >> 8) | ((x32 & 0xff000000) >> 24); + } +} + +/* set mode to match the contents of header. Return non-zero on error. + * On a zero return, mode is a valid posix mode, and *extra is set to + * 1 if any of the entries are not reflected by that mode. On a non-zero + * return, no promises are made about *extra or *mode. + */ +static int +posix_permissions(const acl_header *header, int entries, int *extra, int *mode) { + int acl_seen = 0; + if (le32(header->version) != 2) { + pseudo_diag("Fatal: ACL support no available for header version %d.\n", + le32(header->version)); + return 1; + } + *mode = 0; + *extra = 0; + for (int i = 0; i < entries; ++i) { + const acl_entry *e = &header->entries[i]; + int tag = le16(e->tag); + int perm = le16(e->perm); + acl_seen |= tag; + switch (tag) { + case ACL_USER_OBJ: + *mode = *mode | (perm << 6); + break; + case ACL_GROUP_OBJ: + *mode = *mode | (perm << 3); + break; + case ACL_OTHER: + *mode = *mode | perm; + break; + case ACL_USER: + case ACL_GROUP: + case ACL_MASK: + *extra = *extra + 1; + break; + default: + pseudo_debug(PDBGF_XATTR, "Unknown tag in ACL: 0x%x.\n", + tag); + return 1; + } + } + return 0; +} + +#define RC_AND_BUF \ + int rc; \ + PSEUDO_STATBUF buf; \ + if (path) { \ + rc = base_lstat(path, &buf); \ + } else { \ + rc = base_fstat(fd, &buf); \ + } \ + if (rc == -1) { \ + return rc; \ + } + +static ssize_t shared_getxattr(const char *path, int fd, const char *name, void *value, size_t size) { + RC_AND_BUF + + pseudo_debug(PDBGF_XATTR, "getxattr(%s [fd %d], %s)\n", + path ? path : "<no path>", fd, name); + pseudo_msg_t *result = pseudo_client_op(OP_GET_XATTR, 0, fd, -1, path, &buf, name); + if (result->result != RESULT_SUCCEED) { + errno = ENOATTR; + return -1; + } + + if (value) { + pseudo_debug(PDBGF_XATTR, "returned attributes: '%s' (%d bytes)\n", + result->path, result->pathlen); + if (size >= result->pathlen) { + memcpy(value, result->path, result->pathlen); + } else { + memcpy(value, result->path, size); + errno = ERANGE; + } + } + return result->pathlen; +} + +static int shared_setxattr(const char *path, int fd, const char *name, const void *value, size_t size, int flags) { + RC_AND_BUF + pseudo_op_t op; + + pseudo_debug(PDBGF_XATTR, "setxattr(%s [fd %d], %s => '%.*s')\n", + path ? path : "<no path>", fd, name, (int) size, (char *) value); + + /* this may be a plain chmod */ + if (!strcmp(name, "system.posix_acl_access")) { + int extra; + int mode; + int entries = (size - sizeof(acl_header)) / sizeof(acl_entry); + if (!posix_permissions(value, entries, &extra, &mode)) { + pseudo_debug(PDBGF_XATTR, "posix_acl_access translated to mode %04o. Remaining attribute(s): %d.\n", + mode, extra); + buf.st_mode = mode; + /* we want to actually issue a corresponding chmod, + * as well, or else the file ends up 0600 on the + * host. Using the slightly-less-efficient wrap_chmod + * avoids possible misalignment. + */ + if (path) { + wrap_chmod(path, mode); + } else { + wrap_fchmod(fd, mode); + } + /* we are sneaky, and do not actually record this using + * extended attributes. */ + if (!extra) { + return 0; + } + } + } + if (!strcmp(name, "user.pseudo_data")) { + pseudo_debug(PDBGF_XATTR | PDBGF_XATTRDB, "user.pseudo_data xattribute does not get to go in database.\n"); + return -1; + } + + switch (flags) { + case XATTR_CREATE: + op = OP_CREATE_XATTR; + break; + case XATTR_REPLACE: + op = OP_REPLACE_XATTR; + break; + default: + op = OP_SET_XATTR; + break; + } + + pseudo_msg_t *result = pseudo_client_op(op, 0, fd, -1, path, &buf, name, value, size); + + /* we automatically assume success */ + if (op == OP_SET_XATTR) { + return 0; + } + + /* CREATE/REPLACE operations can report failure */ + if (!result || result->result == RESULT_FAIL) { + return -1; + } + + return 0; +} + +static ssize_t shared_listxattr(const char *path, int fd, char *list, size_t size) { + RC_AND_BUF + pseudo_msg_t *result = pseudo_client_op(OP_LIST_XATTR, 0, fd, -1, path, &buf); + if (result->result != RESULT_SUCCEED) { + pseudo_debug(PDBGF_XATTR, "listxattr: no success.\n"); + errno = ENOATTR; + return -1; + } + if (list) { + pseudo_debug(PDBGF_XATTR, "listxattr: %d bytes of names, starting '%.*s'\n", + (int) result->pathlen, (int) result->pathlen, result->path); + if (size >= result->pathlen) { + memcpy(list, result->path, result->pathlen); + } else { + memcpy(list, result->path, size); + errno = ERANGE; + } + } + return result->pathlen; +} + +static int shared_removexattr(const char *path, int fd, const char *name) { + RC_AND_BUF + pseudo_msg_t *result = pseudo_client_op(OP_REMOVE_XATTR, 0, fd, -1, path, &buf, name); + + if (result->result != RESULT_SUCCEED) { + /* docs say ENOATTR, but I don't have one */ + errno = ENOENT; + return -1; + } + return 0; +} + diff --git a/ports/linux/xattr/wrapfuncs.in b/ports/linux/xattr/wrapfuncs.in new file mode 100644 index 0000000..c37f78a --- /dev/null +++ b/ports/linux/xattr/wrapfuncs.in @@ -0,0 +1,12 @@ +ssize_t getxattr(const char *path, const char *name, void *value, size_t size); /* flags=0 */ +ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size); /* flags=AT_SYMLINK_NOFOLLOW */ +ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size); +int setxattr(const char *path, const char *name, const void *value, size_t size, int xflags); /* flags=0 */ +int lsetxattr(const char *path, const char *name, const void *value, size_t size, int xflags); /* flags=AT_SYMLINK_NOFOLLOW */ +int fsetxattr(int filedes, const char *name, const void *value, size_t size, int xflags); +ssize_t listxattr(const char *path, char *list, size_t size); /* flags=0 */ +ssize_t llistxattr(const char *path, char *list, size_t size); /* flags=AT_SYMLINK_NOFOLLOW */ +ssize_t flistxattr(int filedes, char *list, size_t size); +int removexattr(const char *path, const char *name); /* flags=0 */ +int lremovexattr(const char *path, const char *name); /* flags=AT_SYMLINK_NOFOLLOW */ +int fremovexattr(int filedes, const char *name); diff --git a/ports/uids_generic/guts/COPYRIGHT b/ports/uids_generic/guts/COPYRIGHT new file mode 100644 index 0000000..c96e1b1 --- /dev/null +++ b/ports/uids_generic/guts/COPYRIGHT @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the Lesser GNU General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * version 2.1 along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ diff --git a/ports/uids_generic/guts/endgrent.c b/ports/uids_generic/guts/endgrent.c new file mode 100644 index 0000000..843cad0 --- /dev/null +++ b/ports/uids_generic/guts/endgrent.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static void + * wrap_endgrent(void) { + * + */ + + pseudo_grp_close(); + +/* return; + * } + */ diff --git a/ports/uids_generic/guts/endpwent.c b/ports/uids_generic/guts/endpwent.c new file mode 100644 index 0000000..f76cf10 --- /dev/null +++ b/ports/uids_generic/guts/endpwent.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static void + * wrap_endpwent(void) { + * + */ + + pseudo_pwd_close(); + +/* return; + * } + */ diff --git a/ports/uids_generic/guts/getegid.c b/ports/uids_generic/guts/getegid.c new file mode 100644 index 0000000..7c14f48 --- /dev/null +++ b/ports/uids_generic/guts/getegid.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static gid_t + * wrap_getegid(void) { + * gid_t rc = 0; + */ + + rc = pseudo_egid; + +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/geteuid.c b/ports/uids_generic/guts/geteuid.c new file mode 100644 index 0000000..1745e13 --- /dev/null +++ b/ports/uids_generic/guts/geteuid.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static uid_t + * wrap_geteuid(void) { + * uid_t rc = 0; + */ + + rc = pseudo_euid; + +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/getgid.c b/ports/uids_generic/guts/getgid.c new file mode 100644 index 0000000..ca8bad3 --- /dev/null +++ b/ports/uids_generic/guts/getgid.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static gid_t + * wrap_getgid(void) { + * gid_t rc = 0; + */ + + rc = pseudo_rgid; + +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/getgrent.c b/ports/uids_generic/guts/getgrent.c new file mode 100644 index 0000000..e8e07f5 --- /dev/null +++ b/ports/uids_generic/guts/getgrent.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static struct group * + * wrap_getgrent(void) { + * struct group * rc = NULL; + */ + static struct group grp; + static char grbuf[PSEUDO_PWD_MAX]; + int r_rc; + + r_rc = wrap_getgrent_r(&grp, grbuf, PSEUDO_PWD_MAX, &rc); + /* different error return conventions */ + if (r_rc != 0) { + errno = r_rc; + } + +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/getgrgid.c b/ports/uids_generic/guts/getgrgid.c new file mode 100644 index 0000000..c1824e7 --- /dev/null +++ b/ports/uids_generic/guts/getgrgid.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static struct group * + * wrap_getgrgid(gid_t gid) { + * struct group * rc = NULL; + */ + static struct group grp; + static char grbuf[PSEUDO_PWD_MAX]; + int r_rc; + + r_rc = wrap_getgrgid_r(gid, &grp, grbuf, PSEUDO_PWD_MAX, &rc); + /* different error return conventions */ + if (r_rc != 0) { + errno = r_rc; + } + +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/getgrgid_r.c b/ports/uids_generic/guts/getgrgid_r.c new file mode 100644 index 0000000..b043995 --- /dev/null +++ b/ports/uids_generic/guts/getgrgid_r.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_getgrgid_r(gid_t gid, struct group *gbuf, char *buf, size_t buflen, struct group **gbufp) { + * int rc = -1; + */ + + setgrent(); + while ((rc = wrap_getgrent_r(gbuf, buf, buflen, gbufp)) == 0) { + /* 0 means no error occurred, and *gbufp == gbuf */ + if (gbuf->gr_gid == gid) { + pseudo_debug(PDBGF_CLIENT, "found group gid %d, name %s\n", + gbuf->gr_gid, gbuf->gr_name); + endgrent(); + return rc; + } + } + endgrent(); + /* we never found a match; rc is 0 if there was no error, or + * non-zero if an error occurred. Either way, set the + * pwbufp pointer to NULL to indicate that we didn't find + * something, and leave rc alone. + */ + *gbufp = NULL; + +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/getgrnam.c b/ports/uids_generic/guts/getgrnam.c new file mode 100644 index 0000000..0e26444 --- /dev/null +++ b/ports/uids_generic/guts/getgrnam.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static struct group * + * wrap_getgrnam(const char *name) { + * struct group * rc = NULL; + */ + + static struct group grp; + static char grbuf[PSEUDO_PWD_MAX]; + int r_rc; + + r_rc = wrap_getgrnam_r(name, &grp, grbuf, PSEUDO_PWD_MAX, &rc); + /* different error return conventions */ + if (r_rc != 0) { + errno = r_rc; + } + + +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/getgrnam_r.c b/ports/uids_generic/guts/getgrnam_r.c new file mode 100644 index 0000000..39de641 --- /dev/null +++ b/ports/uids_generic/guts/getgrnam_r.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_getgrnam_r(const char *name, struct group *gbuf, char *buf, size_t buflen, struct group **gbufp) { + * int rc = -1; + */ + + setgrent(); + while ((rc = wrap_getgrent_r(gbuf, buf, buflen, gbufp)) == 0) { + /* 0 means no error occurred, and *gbufp == gbuf */ + if (gbuf->gr_name && !strcmp(gbuf->gr_name, name)) { + endgrent(); + return rc; + } + } + endgrent(); + /* we never found a match; rc is 0 if there was no error, or + * non-zero if an error occurred. Either way, set the + * pwbufp pointer to NULL to indicate that we didn't find + * something, and leave rc alone. + */ + *gbufp = NULL; + + +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/getpwent.c b/ports/uids_generic/guts/getpwent.c new file mode 100644 index 0000000..3b1f837 --- /dev/null +++ b/ports/uids_generic/guts/getpwent.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static struct passwd * + * wrap_getpwent(void) { + * struct passwd * rc = NULL; + */ + static struct passwd pwd; + static char pwbuf[PSEUDO_PWD_MAX]; + int r_rc; + + r_rc = wrap_getpwent_r(&pwd, pwbuf, PSEUDO_PWD_MAX, &rc); + /* different error return conventions */ + if (r_rc != 0) { + errno = r_rc; + } + +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/getpwnam.c b/ports/uids_generic/guts/getpwnam.c new file mode 100644 index 0000000..024b3d8 --- /dev/null +++ b/ports/uids_generic/guts/getpwnam.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static struct passwd * + * wrap_getpwnam(const char *name) { + * struct passwd * rc = NULL; + */ + static struct passwd pwd; + static char pwbuf[PSEUDO_PWD_MAX]; + int r_rc; + + r_rc = wrap_getpwnam_r(name, &pwd, pwbuf, PSEUDO_PWD_MAX, &rc); + /* different error return conventions */ + if (r_rc != 0) { + errno = r_rc; + } + +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/getpwnam_r.c b/ports/uids_generic/guts/getpwnam_r.c new file mode 100644 index 0000000..5d7a4ea --- /dev/null +++ b/ports/uids_generic/guts/getpwnam_r.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_getpwnam_r(const char *name, struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp) { + * int rc = -1; + */ + + setpwent(); + while ((rc = wrap_getpwent_r(pwbuf, buf, buflen, pwbufp)) == 0) { + /* 0 means no error occurred, and *pwbufp == pwbuf */ + if (pwbuf->pw_name && !strcmp(pwbuf->pw_name, name)) { + endpwent(); + return rc; + } + } + endpwent(); + /* we never found a match; rc is 0 if there was no error, or + * non-zero if an error occurred. Either way, set the + * pwbufp pointer to NULL to indicate that we didn't find + * something, and leave rc alone. + */ + *pwbufp = NULL; + +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/getpwuid.c b/ports/uids_generic/guts/getpwuid.c new file mode 100644 index 0000000..11142de --- /dev/null +++ b/ports/uids_generic/guts/getpwuid.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static struct passwd * + * wrap_getpwuid(uid_t uid) { + * struct passwd * rc = NULL; + */ + static struct passwd pwd; + static char pwbuf[PSEUDO_PWD_MAX]; + int r_rc; + + r_rc = wrap_getpwuid_r(uid, &pwd, pwbuf, PSEUDO_PWD_MAX, &rc); + /* different error return conventions */ + if (r_rc != 0) { + errno = r_rc; + } + +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/getpwuid_r.c b/ports/uids_generic/guts/getpwuid_r.c new file mode 100644 index 0000000..06b920e --- /dev/null +++ b/ports/uids_generic/guts/getpwuid_r.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_getpwuid_r(uid_t uid, struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp) { + * int rc = -1; + */ + + setpwent(); + while ((rc = wrap_getpwent_r(pwbuf, buf, buflen, pwbufp)) == 0) { + /* 0 means no error occurred, and *pwbufp == pwbuf */ + if (pwbuf->pw_uid == uid) { + endpwent(); + return rc; + } + } + endpwent(); + /* we never found a match; rc is 0 if there was no error, or + * non-zero if an error occurred. Either way, set the + * pwbufp pointer to NULL to indicate that we didn't find + * something, and leave rc alone. + */ + *pwbufp = NULL; + +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/getuid.c b/ports/uids_generic/guts/getuid.c new file mode 100644 index 0000000..e783cc8 --- /dev/null +++ b/ports/uids_generic/guts/getuid.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static uid_t + * wrap_getuid(void) { + * uid_t rc = 0; + */ + + rc = pseudo_ruid; + +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/setegid.c b/ports/uids_generic/guts/setegid.c new file mode 100644 index 0000000..ff777a0 --- /dev/null +++ b/ports/uids_generic/guts/setegid.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_setegid(gid_t egid) { + * int rc = -1; + */ + if (pseudo_euid == 0 || egid == pseudo_egid || egid == pseudo_rgid || egid == pseudo_sgid) { + pseudo_egid = egid; + pseudo_fgid = egid; + pseudo_client_touchgid(); + rc = 0; + } else { + rc = -1; + errno = EPERM; + } +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/seteuid.c b/ports/uids_generic/guts/seteuid.c new file mode 100644 index 0000000..430768f --- /dev/null +++ b/ports/uids_generic/guts/seteuid.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_seteuid(uid_t euid) { + * int rc = -1; + */ + if (pseudo_euid == 0 || euid == pseudo_euid || euid == pseudo_ruid || euid == pseudo_suid) { + pseudo_euid = euid; + pseudo_fuid = euid; + pseudo_client_touchuid(); + rc = 0; + } else { + rc = -1; + errno = EPERM; + } +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/setgid.c b/ports/uids_generic/guts/setgid.c new file mode 100644 index 0000000..b94db1a --- /dev/null +++ b/ports/uids_generic/guts/setgid.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_setgid(gid_t gid) { + * int rc = -1; + */ + if (pseudo_euid == 0) { + pseudo_rgid = gid; + pseudo_egid = gid; + pseudo_sgid = gid; + pseudo_fgid = gid; + pseudo_client_touchgid(); + rc = 0; + } else if (pseudo_egid == gid || pseudo_sgid == gid || pseudo_rgid == gid) { + pseudo_egid = gid; + pseudo_fgid = gid; + pseudo_client_touchgid(); + rc = 0; + } else { + rc = -1; + errno = EPERM; + } +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/setgrent.c b/ports/uids_generic/guts/setgrent.c new file mode 100644 index 0000000..75aab61 --- /dev/null +++ b/ports/uids_generic/guts/setgrent.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static void + * wrap_setgrent(void) { + * + */ + + pseudo_grp_open(); + +/* return; + * } + */ diff --git a/ports/uids_generic/guts/setpwent.c b/ports/uids_generic/guts/setpwent.c new file mode 100644 index 0000000..fb35e07 --- /dev/null +++ b/ports/uids_generic/guts/setpwent.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static void + * wrap_setpwent(void) { + * + */ + + pseudo_pwd_open(); + +/* return; + * } + */ diff --git a/ports/uids_generic/guts/setregid.c b/ports/uids_generic/guts/setregid.c new file mode 100644 index 0000000..78b2037 --- /dev/null +++ b/ports/uids_generic/guts/setregid.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_setregid(gid_t rgid, gid_t egid) { + * int rc = -1; + */ + rc = 0; + if (pseudo_euid != 0 && rgid != (gid_t) -1 && + rgid != pseudo_egid && rgid != pseudo_rgid && rgid != pseudo_sgid) { + rc = -1; + errno = EPERM; + } + if (pseudo_euid != 0 && egid != (gid_t) -1 && + egid != pseudo_egid && egid != pseudo_rgid && egid != pseudo_sgid) { + rc = -1; + errno = EPERM; + } + if (rc != -1) { + if (rgid != (gid_t) -1) + pseudo_rgid = rgid; + if (egid != (gid_t) -1) + pseudo_egid = egid; + pseudo_fgid = pseudo_egid; + pseudo_client_touchuid(); + } +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/setreuid.c b/ports/uids_generic/guts/setreuid.c new file mode 100644 index 0000000..3ff82ab --- /dev/null +++ b/ports/uids_generic/guts/setreuid.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_setreuid(uid_t ruid, uid_t euid) { + * int rc = -1; + */ + rc = 0; + if (pseudo_euid != 0 && ruid != (uid_t) -1 && + ruid != pseudo_euid && ruid != pseudo_ruid && ruid != pseudo_suid) { + rc = -1; + errno = EPERM; + } + if (pseudo_euid != 0 && euid != (uid_t) -1 && + euid != pseudo_euid && euid != pseudo_ruid && euid != pseudo_suid) { + rc = -1; + errno = EPERM; + } + if (rc != -1) { + if (ruid != (uid_t) -1) + pseudo_ruid = ruid; + if (euid != (uid_t) -1) + pseudo_euid = euid; + pseudo_fuid = pseudo_euid; + pseudo_client_touchuid(); + } +/* return rc; + * } + */ diff --git a/ports/uids_generic/guts/setuid.c b/ports/uids_generic/guts/setuid.c new file mode 100644 index 0000000..6bfdf6c --- /dev/null +++ b/ports/uids_generic/guts/setuid.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_setuid(uid_t uid) { + * int rc = -1; + */ + if (pseudo_euid == 0) { + pseudo_ruid = uid; + pseudo_euid = uid; + pseudo_suid = uid; + pseudo_fuid = uid; + pseudo_client_touchuid(); + rc = 0; + } else if (pseudo_euid == uid || pseudo_suid == uid || pseudo_ruid == uid) { + pseudo_euid = uid; + pseudo_fuid = uid; + pseudo_client_touchuid(); + rc = 0; + } else { + rc = -1; + errno = EPERM; + } +/* return rc; + * } + */ diff --git a/ports/uids_generic/wrapfuncs.in b/ports/uids_generic/wrapfuncs.in new file mode 100644 index 0000000..38aa558 --- /dev/null +++ b/ports/uids_generic/wrapfuncs.in @@ -0,0 +1,25 @@ +# I bet you never knew there were this many of these! +gid_t getegid(void); +gid_t getgid(void); +int getgrgid_r(gid_t gid, struct group *gbuf, char *buf, size_t buflen, struct group **gbufp); +int getgrnam_r(const char *name, struct group *gbuf, char *buf, size_t buflen, struct group **gbufp); +int getpwnam_r(const char *name, struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp); +int getpwuid_r(uid_t uid, struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp); +int setegid(gid_t egid); +int seteuid(uid_t euid); +int setgid(gid_t gid); +int setregid(gid_t rgid, gid_t egid); +int setreuid(uid_t ruid, uid_t euid); +int setuid(uid_t uid); +struct group *getgrent(void); +struct group *getgrgid(gid_t gid); +struct group *getgrnam(const char *name); +struct passwd *getpwent(void); +struct passwd *getpwnam(const char *name); +struct passwd *getpwuid(uid_t uid); +uid_t geteuid(void); +uid_t getuid(void); +void endgrent(void); +void endpwent(void); +void setgrent(void); +void setpwent(void); diff --git a/ports/unix/guts/COPYRIGHT b/ports/unix/guts/COPYRIGHT new file mode 100644 index 0000000..c96e1b1 --- /dev/null +++ b/ports/unix/guts/COPYRIGHT @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the Lesser GNU General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * version 2.1 along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ diff --git a/ports/unix/guts/access.c b/ports/unix/guts/access.c new file mode 100644 index 0000000..0093a3b --- /dev/null +++ b/ports/unix/guts/access.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010, 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_access(const char *path, int mode) { + * int rc = -1; + */ + PSEUDO_STATBUF buf; + + /* note: no attempt to handle the case where user isn't + * root. + */ + rc = base_stat(path, &buf); + if (rc == -1) + return rc; + + if (mode & X_OK) { + if (buf.st_mode & 0111) { + return 0; + } else { + errno = EPERM; + return -1; + } + } else { + return 0; + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/acct.c b/ports/unix/guts/acct.c new file mode 100644 index 0000000..b8dca5d --- /dev/null +++ b/ports/unix/guts/acct.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_acct(const char *path) { + * int rc = -1; + */ + + rc = real_acct(path); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/chdir.c b/ports/unix/guts/chdir.c new file mode 100644 index 0000000..9e30348 --- /dev/null +++ b/ports/unix/guts/chdir.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_chdir(const char *path) { + * int rc = -1; + */ + pseudo_debug(PDBGF_CLIENT, "chdir: '%s'\n", + path ? path : "<nil>"); + + if (!path) { + errno = EFAULT; + return -1; + } + rc = real_chdir(path); + + if (rc != -1) { + pseudo_client_op(OP_CHDIR, 0, -1, -1, path, 0); + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/chmod.c b/ports/unix/guts/chmod.c new file mode 100644 index 0000000..a157335 --- /dev/null +++ b/ports/unix/guts/chmod.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_chmod(const char *path, mode_t mode) { + * int rc = -1; + */ + + rc = wrap_fchmodat(AT_FDCWD, path, mode, 0); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/chown.c b/ports/unix/guts/chown.c new file mode 100644 index 0000000..4fcbdda --- /dev/null +++ b/ports/unix/guts/chown.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_chown(const char *path, uid_t owner, gid_t group) { + * int rc = -1; + */ + + rc = wrap_fchownat(AT_FDCWD, path, owner, group, 0); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/chroot.c b/ports/unix/guts/chroot.c new file mode 100644 index 0000000..ac24955 --- /dev/null +++ b/ports/unix/guts/chroot.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_chroot(const char *path) { + * int rc = -1; + */ + pseudo_debug(PDBGF_CLIENT | PDBGF_CHROOT, "chroot: %s\n", path); + if (!pseudo_client_op(OP_CHROOT, 0, -1, -1, path, 0)) { + pseudo_debug(PDBGF_OP | PDBGF_CHROOT, "chroot failed: %s\n", strerror(errno)); + rc = -1; + } else { + rc = 0; + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/close.c b/ports/unix/guts/close.c new file mode 100644 index 0000000..09c73e6 --- /dev/null +++ b/ports/unix/guts/close.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_close(int fd) { + * int rc = -1; + */ + /* this cleans up an internal table, and shouldn't even + * make it to the server. + */ + pseudo_client_op(OP_CLOSE, 0, fd, -1, 0, 0); + rc = real_close(fd); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/closedir.c b/ports/unix/guts/closedir.c new file mode 100644 index 0000000..1085361 --- /dev/null +++ b/ports/unix/guts/closedir.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_closedir(DIR *dirp) { + * int rc = -1; + */ + if (!dirp) { + errno = EFAULT; + return -1; + } + + int fd = dirfd(dirp); + pseudo_client_op(OP_CLOSE, 0, fd, -1, 0, 0); + rc = real_closedir(dirp); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/creat.c b/ports/unix/guts/creat.c new file mode 100644 index 0000000..8593cd4 --- /dev/null +++ b/ports/unix/guts/creat.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_creat(const char *path, mode_t mode) { + * int rc = -1; + */ + + rc = wrap_open(path, O_CREAT|O_WRONLY|O_TRUNC, mode); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/dup.c b/ports/unix/guts/dup.c new file mode 100644 index 0000000..f03c2ad --- /dev/null +++ b/ports/unix/guts/dup.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_dup(int fd) { + * int rc = -1; + */ + int save_errno; + + rc = real_dup(fd); + save_errno = errno; + pseudo_debug(PDBGF_CLIENT, "dup: %d->%d\n", fd, rc); + pseudo_client_op(OP_DUP, 0, fd, rc, 0, 0); + + errno = save_errno; +/* return rc; + * } + */ diff --git a/ports/unix/guts/dup2.c b/ports/unix/guts/dup2.c new file mode 100644 index 0000000..cd335ac --- /dev/null +++ b/ports/unix/guts/dup2.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_dup2(int oldfd, int newfd) { + * int rc = -1; + */ + int save_errno; + + /* close existing one first - this also causes the socket to the + * server to get moved around if someone tries to overwrite it. */ + pseudo_debug(PDBGF_CLIENT, "dup2: %d->%d\n", oldfd, newfd); + pseudo_client_op(OP_CLOSE, 0, newfd, -1, 0, 0); + rc = real_dup2(oldfd, newfd); + save_errno = errno; + pseudo_client_op(OP_DUP, 0, oldfd, newfd, 0, 0); + errno = save_errno; + +/* return rc; + * } + */ diff --git a/ports/unix/guts/fchdir.c b/ports/unix/guts/fchdir.c new file mode 100644 index 0000000..ba77ebf --- /dev/null +++ b/ports/unix/guts/fchdir.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_fchdir(int dirfd) { + * int rc = -1; + */ + + rc = real_fchdir(dirfd); + + if (rc != -1) { + pseudo_client_op(OP_CHDIR, 0, -1, dirfd, 0, 0); + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/fchmod.c b/ports/unix/guts/fchmod.c new file mode 100644 index 0000000..e2301e3 --- /dev/null +++ b/ports/unix/guts/fchmod.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008-2010, 2012, 2013 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_fchmod(int fd, mode_t mode) { + * int rc = -1; + */ + PSEUDO_STATBUF buf; + int save_errno = errno; + + if (base_fstat(fd, &buf) == -1) { + /* can't stat it, can't chmod it */ + return -1; + } + buf.st_mode = (buf.st_mode & ~07777) | (mode & 07777); + pseudo_client_op(OP_FCHMOD, 0, fd, -1, 0, &buf); + real_fchmod(fd, PSEUDO_FS_MODE(mode, S_ISDIR(buf.st_mode))); + /* just pretend we worked */ + errno = save_errno; + rc = 0; + +/* return rc; + * } + */ diff --git a/ports/unix/guts/fchmodat.c b/ports/unix/guts/fchmodat.c new file mode 100644 index 0000000..0506794 --- /dev/null +++ b/ports/unix/guts/fchmodat.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2008-2010, 2012, 2013 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_fchmodat(int dirfd, const char *path, mode_t mode, int flags) { + * int rc = -1; + */ + PSEUDO_STATBUF buf; + int save_errno = errno; + + if (flags & AT_SYMLINK_NOFOLLOW) { + errno = ENOTSUP; + return -1; + } +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + rc = base_stat(path, &buf); +#else + rc = base_fstatat(dirfd, path, &buf, flags); +#endif + if (rc == -1) { + return rc; + } + if (S_ISLNK(buf.st_mode)) { + /* we don't really support chmod of a symlink */ + errno = ENOSYS; + return -1; + } + save_errno = errno; + +#if 0 + pseudo_msg_t *msg; + /* purely for debugging purposes: check whether file + * is already in database. We don't need the resulting + * information for anything. This is currently ifdefed + * out because it's only useful when trying to track where + * files are coming from. + */ + msg = pseudo_client_op(OP_STAT, 0, -1, -1, path, &buf); + if (!msg || msg->result != RESULT_SUCCEED) { + pseudo_debug(PDBGF_FILE, "chmodat to 0%o on %d/%s, ino %llu, new file.\n", + mode, dirfd, path, (unsigned long long) buf.st_ino); + + } +#endif + + /* user bits added so "root" can always access files. */ +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + /* note: if path was a symlink, and AT_SYMLINK_NOFOLLOW was + * specified, we already bailed previously. */ + real_chmod(path, PSEUDO_FS_MODE(mode, S_ISDIR(buf.st_mode))); +#else + rc = real_fchmodat(dirfd, path, PSEUDO_FS_MODE(mode, S_ISDIR(buf.st_mode)), flags); +#endif + /* we otherwise ignore failures from underlying fchmod, because pseudo + * may believe you are permitted to change modes that the filesystem + * doesn't. Note that we also don't need to know whether the + * file might be a (pseudo) block device or some such; pseudo + * will only modify permission bits based on an OP_CHMOD, and does + * not care about device/file type mismatches, only directory/file + * or symlink/file. + */ + + buf.st_mode = (buf.st_mode & ~07777) | (mode & 07777); + pseudo_client_op(OP_CHMOD, 0, -1, dirfd, path, &buf); + /* don't change errno from what it was originally */ + errno = save_errno; + rc = 0; + +/* return rc; + * } + */ diff --git a/ports/unix/guts/fchown.c b/ports/unix/guts/fchown.c new file mode 100644 index 0000000..89cabe2 --- /dev/null +++ b/ports/unix/guts/fchown.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008-2010, 2012, 2013 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_fchown(int fd, uid_t owner, gid_t group) { + * int rc = -1; + */ + pseudo_msg_t *msg; + PSEUDO_STATBUF buf; + int save_errno = errno; + + if (base_fstat(fd, &buf) == -1) { + save_errno = errno; + pseudo_debug(PDBGF_CONSISTENCY, "fchown failing because fstat failed: %s\n", + strerror(errno)); + errno = save_errno; + return -1; + } + if (owner == (uid_t) -1 || group == (gid_t) -1) { + msg = pseudo_client_op(OP_STAT, 0, fd, -1, NULL, &buf); + /* copy in any existing values... */ + if (msg && msg->result == RESULT_SUCCEED) { + pseudo_stat_msg(&buf, msg); + } else { + pseudo_debug(PDBGF_FILE, "fchown fd %d, ino %llu, unknown file.\n", + fd, (unsigned long long) buf.st_ino); + } + } + /* now override with arguments */ + if (owner != (uid_t) -1) { + buf.st_uid = owner; + } + if (group != (gid_t) -1) { + buf.st_gid = group; + } + pseudo_debug(PDBGF_OP, "fchown, fd %d: %d:%d -> %d:%d\n", + fd, owner, group, buf.st_uid, buf.st_gid); + pseudo_client_op(OP_FCHOWN, 0, fd, -1, 0, &buf); + /* pretend we worked, errno should be unchanged */ + errno = save_errno; + rc = 0; + +/* return rc; + * } + */ diff --git a/ports/unix/guts/fchownat.c b/ports/unix/guts/fchownat.c new file mode 100644 index 0000000..2888087 --- /dev/null +++ b/ports/unix/guts/fchownat.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2008-2010, 2012, 2013 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_fchownat(int dirfd, const char *path, uid_t owner, gid_t group, int flags) { + * int rc = -1; + */ + pseudo_msg_t *msg; + PSEUDO_STATBUF buf; + int save_errno = errno; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + if (flags & AT_SYMLINK_NOFOLLOW) { + rc = base_lstat(path, &buf); + } else { + rc = base_stat(path, &buf); + } +#else + rc = base_fstatat(dirfd, path, &buf, flags); +#endif + if (rc == -1) { + return rc; + } + save_errno = errno; + + if (owner == (uid_t) -1 || group == (gid_t) -1) { + msg = pseudo_client_op(OP_STAT, 0, -1, -1, path, &buf); + /* copy in any existing values... */ + if (msg && msg->result == RESULT_SUCCEED) { + pseudo_stat_msg(&buf, msg); + } else { + pseudo_debug(PDBGF_FILE, "chownat to %d:%d on %d/%s, ino %llu, new file.\n", + owner, group, dirfd, path, + (unsigned long long) buf.st_ino); + } + } + /* now override with arguments */ + if (owner != (uid_t) -1) { + buf.st_uid = owner; + } + if (group != (gid_t) -1) { + buf.st_gid = group; + } + pseudo_client_op(OP_CHOWN, 0, -1, dirfd, path, &buf); + /* just pretend we worked */ + errno = save_errno; + rc = 0; + +/* return rc; + * } + */ diff --git a/ports/unix/guts/fclose.c b/ports/unix/guts/fclose.c new file mode 100644 index 0000000..4469f5b --- /dev/null +++ b/ports/unix/guts/fclose.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_fclose(FILE *fp) { + * int rc = -1; + */ + + if (!fp) { + errno = EFAULT; + return -1; + } + int fd = fileno(fp); + pseudo_client_op(OP_CLOSE, 0, fd, -1, 0, 0); + rc = real_fclose(fp); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/fdatasync.c b/ports/unix/guts/fdatasync.c new file mode 100644 index 0000000..4aa77a8 --- /dev/null +++ b/ports/unix/guts/fdatasync.c @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2013 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fdatasync(int fd) + * int rc = -1; + */ + + /* note: wrapper will never call this if PSEUDO_FORCE_ASYNC + * is defined. + */ + rc = real_fdatasync(fd); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/fopen.c b/ports/unix/guts/fopen.c new file mode 100644 index 0000000..87c7d78 --- /dev/null +++ b/ports/unix/guts/fopen.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008-2010, 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static FILE * + * wrap_fopen(const char *path, const char *mode) { + * FILE * rc = 0; + */ + PSEUDO_STATBUF buf; + int save_errno; + int existed = (base_stat(path, &buf) != -1); + + rc = real_fopen(path, mode); + save_errno = errno; + + if (rc) { + int fd = fileno(rc); + + pseudo_debug(PDBGF_OP, "fopen '%s': fd %d <FILE %p>\n", path, fd, (void *) rc); + if (base_fstat(fd, &buf) != -1) { + if (!existed) { + real_fchmod(fd, PSEUDO_FS_MODE(0666 & ~pseudo_umask, 0)); + pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf); + } + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, &buf); + } else { + pseudo_debug(PDBGF_CONSISTENCY, "fopen (fd %d) succeeded, but fstat failed (%s).\n", + fd, strerror(errno)); + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, 0); + } + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/freopen.c b/ports/unix/guts/freopen.c new file mode 100644 index 0000000..e706d9f --- /dev/null +++ b/ports/unix/guts/freopen.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static FILE * + * wrap_freopen(const char *path, const char *mode, FILE *stream) { + * FILE * rc = NULL; + */ + PSEUDO_STATBUF buf; + int save_errno; + int existed = (base_stat(path, &buf) != -1); + + rc = real_freopen(path, mode, stream); + save_errno = errno; + + if (rc) { + int fd = fileno(rc); + + pseudo_debug(PDBGF_OP, "freopen '%s': fd %d\n", path, fd); + if (base_fstat(fd, &buf) != -1) { + if (!existed) { + real_fchmod(fd, PSEUDO_FS_MODE(0666 & ~pseudo_umask, 0)); + pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf); + } + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, &buf); + } else { + pseudo_debug(PDBGF_OP, "fopen (fd %d) succeeded, but stat failed (%s).\n", + fd, strerror(errno)); + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, 0); + } + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/fsync.c b/ports/unix/guts/fsync.c new file mode 100644 index 0000000..6c87a56 --- /dev/null +++ b/ports/unix/guts/fsync.c @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2013 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fsync(int fd) + * int rc = -1; + */ + + /* note: wrapper will never call this if PSEUDO_FORCE_ASYNC + * is defined. + */ + rc = real_fsync(fd); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/fts_open.c b/ports/unix/guts/fts_open.c new file mode 100644 index 0000000..964314e --- /dev/null +++ b/ports/unix/guts/fts_open.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static FTS * + * wrap_fts_open(char * const *path_argv, int options, int (*compar)(const FTSENT **, const FTSENT **)) { + * FTS * rc = NULL; + */ + char **rpath_argv; + int args = 0; + int errored = 0; + int i; + + if (!path_argv) { + errno = EFAULT; + return NULL; + } + /* count args */ + for (i = 0; path_argv[i]; ++i) { + ++args; + } + rpath_argv = malloc((args + 1) * sizeof(*rpath_argv)); + if (!rpath_argv) { + errno = ENOMEM; + return NULL; + } + + for (i = 0; i < args; ++i) { + rpath_argv[i] = PSEUDO_ROOT_PATH(AT_FDCWD, path_argv[i], AT_SYMLINK_NOFOLLOW); + if (!rpath_argv[i]) + errored = 1; + else + rpath_argv[i] = strdup(rpath_argv[i]); + } + + if (errored) { + errno = ENOMEM; + rc = NULL; + } else { + rc = real_fts_open(path_argv, options, compar); + } + for (i = 0; i < args; ++i) + free(rpath_argv[i]); + free(rpath_argv); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/ftw.c b/ports/unix/guts/ftw.c new file mode 100644 index 0000000..0861194 --- /dev/null +++ b/ports/unix/guts/ftw.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_ftw(const char *path, int (*fn)(const char *, const struct stat *, int), int nopenfd) { + * int rc = -1; + */ + + rc = real_ftw(path, fn, nopenfd); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/getcwd.c b/ports/unix/guts/getcwd.c new file mode 100644 index 0000000..2915a18 --- /dev/null +++ b/ports/unix/guts/getcwd.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static char * + * wrap_getcwd(char *buf, size_t size) { + * char * rc = NULL; + */ + pseudo_debug(PDBGF_CLIENT, "wrap_getcwd: %p, %lu\n", + (void *) buf, (unsigned long) size); + if (!pseudo_cwd) { + pseudo_diag("Asked for CWD, but don't have it!\n"); + errno = EACCES; + return NULL; + } + /* emulate Linux semantics in case of non-Linux systems. */ + if (!buf) { + /* if we don't have a cwd, something's very wrong... */ + if (!size) { + size = pseudo_cwd_len + 1; + if (pseudo_chroot_len && size >= pseudo_chroot_len && + !memcmp(pseudo_cwd, pseudo_chroot, pseudo_chroot_len)) { + size -= pseudo_chroot_len; + /* if cwd is precisely the same as chroot, we + * actually want a /, not an empty string + */ + if (size < 2) + size = 2; + } + } + if (size) { + buf = malloc(size); + } else { + pseudo_diag("can't figure out CWD: length %ld + 1 - %ld => %ld\n", + (unsigned long) pseudo_cwd_len, + (unsigned long) pseudo_chroot_len, + (unsigned long) size); + } + if (!buf) { + pseudo_diag("couldn't allocate requested CWD buffer - need %ld byes\n", + (unsigned long) size); + errno = ENOMEM; + return NULL; + } + } + if (pseudo_cwd_len - (pseudo_cwd_rel - pseudo_cwd) >= size) { + pseudo_debug(PDBGF_CLIENT, "only %ld bytes available, need %ld (%ld + 1 - %ld)\n", + (unsigned long) size, + (unsigned long) pseudo_cwd_len + 1 - pseudo_chroot_len, + (unsigned long) pseudo_cwd_len, + (unsigned long) pseudo_chroot_len); + errno = ERANGE; + return NULL; + } + rc = buf; + pseudo_debug(PDBGF_CLIENT, "getcwd: copying %d (%d + 1 - %d) characters from <%s>.\n", + (int) ((pseudo_cwd_len + 1) - pseudo_chroot_len), + (int) pseudo_cwd_len, (int) pseudo_chroot_len, + pseudo_cwd_rel); + memcpy(buf, pseudo_cwd_rel, (pseudo_cwd_len + 1) - (pseudo_cwd_rel - pseudo_cwd)); + if (!*buf) { + strcpy(buf, "/"); + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/getwd.c b/ports/unix/guts/getwd.c new file mode 100644 index 0000000..b1bcf90 --- /dev/null +++ b/ports/unix/guts/getwd.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static char * + * wrap_getwd(char *buf) { + * char * rc = NULL; + */ + + pseudo_debug(PDBGF_CLIENT, "getwd (getcwd)\n"); + rc = wrap_getcwd(buf, pseudo_path_max()); + /* because it would violate everything we have ever known about + * UNIX for these functions to have the same errno semantics, + * that's why. + */ + if (rc == NULL && errno == ERANGE ) + errno = ENAMETOOLONG; + +/* return rc; + * } + */ diff --git a/ports/unix/guts/glob.c b/ports/unix/guts/glob.c new file mode 100644 index 0000000..0012179 --- /dev/null +++ b/ports/unix/guts/glob.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_glob(const char *pattern, int flags, int (*errfunc)(const char *, int), glob_t *pglob) { + * int rc = -1; + */ + char *rpattern = NULL; + int alloced = 0; + + /* note: no canonicalization */ + if (pattern && (*pattern == '/') && pseudo_chroot_len) { + size_t len = strlen(pattern) + pseudo_chroot_len + 2; + rpattern = malloc(len); + if (!rpattern) { + errno = ENOMEM; + return GLOB_NOSPACE; + } + snprintf(rpattern, len, "%s/%s", pseudo_chroot, pattern); + alloced = 1; + } + + rc = real_glob(alloced ? rpattern : pattern, flags, errfunc, pglob); + + free(rpattern); + + if (rc == 0) { + unsigned int i; + for (i = 0; i < pglob->gl_pathc; ++i) { + pseudo_dechroot(pglob->gl_pathv[i], (size_t) -1); + } + } +/* return rc; + * } + */ diff --git a/ports/unix/guts/lchown.c b/ports/unix/guts/lchown.c new file mode 100644 index 0000000..60727d0 --- /dev/null +++ b/ports/unix/guts/lchown.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2008,2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int lchown(const char *path, uid_t owner, gid_t group) + * int rc = -1; + */ + + rc = wrap_chown(path, owner, group); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/link.c b/ports/unix/guts/link.c new file mode 100644 index 0000000..3b340ee --- /dev/null +++ b/ports/unix/guts/link.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2010, 2012, 2013 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_link(const char *oldname, const char *newname) { + * int rc = -1; + */ + /* since 2.6.18 or so, linkat supports AT_SYMLINK_FOLLOW, which + * provides the behavior link() has on most non-Linux systems, + * but the default is not to follow symlinks. Better yet, it + * does NOT support AT_SYMLINK_NOFOLLOW! So define this in + * your port's portdefs.h or hope the default works for you. + */ + rc = wrap_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, + PSEUDO_LINK_SYMLINK_BEHAVIOR); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/linkat.c b/ports/unix/guts/linkat.c new file mode 100644 index 0000000..ec27e47 --- /dev/null +++ b/ports/unix/guts/linkat.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2012, 2013 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int linkat(int olddirfd, const char *oldname, int newdirfd, const char *newname, int flags) + * int rc = -1; + */ + + int rc2, rflags, save_errno; + pseudo_msg_t *msg; + char *oldpath = NULL, *newpath = NULL; + PSEUDO_STATBUF buf; + + /* This is gratuitously complicated. On Linux 2.6.18 and later, + * flags may contain AT_SYMLINK_FOLLOW, which implies following + * symlinks; otherwise, linkat() will *not* follow symlinks. FreeBSD + * appears to use the same semantics. + * + * So on Darwin, always pass AT_SYMLINK_FOLLOW, because the + * alternative doesn't work. And never pass AT_SYMLINK_NOFOLLOW + * because that's not a valid flag to linkat(). + * + * So we need a flag for path resolution which is AT_SYMLINK_NOFOLLOW + * unless AT_SYMLINK_FOLLOW was specified, in which case it's 0. + */ + + rflags = (flags & AT_SYMLINK_FOLLOW) ? 0 : AT_SYMLINK_NOFOLLOW; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (olddirfd != AT_FDCWD || newdirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } +#endif + oldpath = pseudo_root_path(__func__, __LINE__, olddirfd, oldname, rflags); + newpath = pseudo_root_path(__func__, __LINE__, newdirfd, newname, AT_SYMLINK_NOFOLLOW); + rc = real_link(oldpath, newpath); + save_errno = errno; + if (rc == -1) { + errno = save_errno; + return rc; + } + + /* if we got this far, the link succeeded, and oldpath and newpath + * are the newly-allocated canonical paths. If OS, filesystem, or + * the flags value prevent hard linking to symlinks, the resolved + * path should be the target's path anyway, so lstat is safe here. + */ + /* find the target: */ + rc2 = base_lstat(oldpath, &buf); + if (rc2 == -1) { + pseudo_diag("Fatal: Tried to stat '%s' after linking it, but failed: %s.\n", + oldpath, strerror(errno)); + errno = ENOENT; + return rc; + } + msg = pseudo_client_op(OP_STAT, 0, -1, -1, oldpath, &buf); + if (msg && msg->result == RESULT_SUCCEED) { + pseudo_stat_msg(&buf, msg); + } + /* Long story short: I am pretty sure we still want OP_LINK even + * if the thing linked is a symlink. + */ + pseudo_client_op(OP_LINK, 0, -1, -1, newpath, &buf); + + errno = save_errno; + +/* return rc; + * } + */ diff --git a/ports/unix/guts/lutimes.c b/ports/unix/guts/lutimes.c new file mode 100644 index 0000000..cdadbbd --- /dev/null +++ b/ports/unix/guts/lutimes.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_lutimes(const char *path, const struct timeval *tv) { + * int rc = -1; + */ + + rc = real_lutimes(path, tv); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/mkdir.c b/ports/unix/guts/mkdir.c new file mode 100644 index 0000000..9f116e2 --- /dev/null +++ b/ports/unix/guts/mkdir.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_mkdir(const char *path, mode_t mode) { + * int rc = -1; + */ + + rc = wrap_mkdirat(AT_FDCWD, path, mode); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/mkdirat.c b/ports/unix/guts/mkdirat.c new file mode 100644 index 0000000..ef2e3a1 --- /dev/null +++ b/ports/unix/guts/mkdirat.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008-2010, 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_mkdirat(int dirfd, const char *path, mode_t mode) { + * int rc = -1; + */ + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + + rc = real_mkdir(path, PSEUDO_FS_MODE(mode, 1)); +#else + rc = real_mkdirat(dirfd, path, PSEUDO_FS_MODE(mode, 1)); +#endif + if (rc != -1) { + PSEUDO_STATBUF buf; + int stat_rc; + int save_errno = errno; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + stat_rc = base_lstat(path, &buf); +#else + stat_rc = base_fstatat(dirfd, path, &buf, AT_SYMLINK_NOFOLLOW); +#endif + if (stat_rc != -1) { + buf.st_mode = PSEUDO_DB_MODE(buf.st_mode, mode); + pseudo_client_op(OP_MKDIR, 0, -1, dirfd, path, &buf); +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + real_fchmod(path, PSEUDO_FS_MODE(mode, 1)); +#else + real_fchmodat(dirfd, path, PSEUDO_FS_MODE(mode, 1), 0); +#endif + } else { + pseudo_debug(PDBGF_OP, "mkdir of %s succeeded, but stat failed: %s\n", + path, strerror(errno)); + } + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/mkdtemp.c b/ports/unix/guts/mkdtemp.c new file mode 100644 index 0000000..5337661 --- /dev/null +++ b/ports/unix/guts/mkdtemp.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2010, 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static char * + * wrap_mkdtemp(char *template) { + * char * rc = NULL; + */ + PSEUDO_STATBUF buf; + int save_errno; + size_t len; + char *tmp_template; + + if (!template) { + errno = EFAULT; + return NULL; + } + + len = strlen(template); + tmp_template = PSEUDO_ROOT_PATH(AT_FDCWD, template, AT_SYMLINK_NOFOLLOW); + + if (!tmp_template) { + errno = ENOENT; + return NULL; + } + + rc = real_mkdtemp(tmp_template); + + if (rc != NULL) { + save_errno = errno; + + if (base_stat(rc, &buf) != -1) { + pseudo_client_op(OP_CREAT, 0, -1, -1, tmp_template, &buf); + } else { + pseudo_debug(PDBGF_CONSISTENCY, "mkdtemp (path %s) succeeded, but fstat failed (%s).\n", + rc, strerror(errno)); + } + errno = save_errno; + } + /* mkdtemp only changes the XXXXXX at the end. */ + memcpy(template + len - 6, tmp_template + strlen(tmp_template) - 6, 6); + rc = template; +/* return rc; + * } + */ diff --git a/ports/unix/guts/mkfifo.c b/ports/unix/guts/mkfifo.c new file mode 100644 index 0000000..32f79fb --- /dev/null +++ b/ports/unix/guts/mkfifo.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_mkfifo(const char *path, mode_t mode) { + * int rc = -1; + */ + + rc = wrap_mkfifoat(AT_FDCWD, path, mode); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/mkfifoat.c b/ports/unix/guts/mkfifoat.c new file mode 100644 index 0000000..6947e70 --- /dev/null +++ b/ports/unix/guts/mkfifoat.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_mkfifoat(int dirfd, const char *path, mode_t mode) { + * int rc = -1; + */ + + pseudo_msg_t *msg; + PSEUDO_STATBUF buf; + int save_errno = errno; + + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + rc = base_stat(path, &buf); +#else + rc = base_fstatat(dirfd, path, &buf, AT_SYMLINK_NOFOLLOW); +#endif + if (rc != -1) { + /* if we can stat the file, you can't mkfifo it */ + errno = EEXIST; + return -1; + } +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real_mkfifo(path, PSEUDO_FS_MODE(mode, 0)); + if (rc == -1) { + return -1; + } + save_errno = errno; + rc = base_stat(path, &buf); + real_chmod(path, PSEUDO_FS_MODE(mode, 0)); +#else + rc = real_mkfifoat(dirfd, path, PSEUDO_FS_MODE(mode, 0)); + if (rc == -1) { + return -1; + } + save_errno = errno; + rc = base_fstatat(dirfd, path, &buf, AT_SYMLINK_NOFOLLOW); + real_fchmodat(dirfd, path, PSEUDO_FS_MODE(mode, 0), 0); +#endif + /* if the stat failed, we are going to give up and nuke + * any file we may have created, and hope for the best. + */ + if (rc == 0) { + buf.st_mode = PSEUDO_DB_MODE(buf.st_mode, mode); + /* mkfifo/mknod are the same op, in that they create a file + * with a non-file type. + */ + msg = pseudo_client_op(OP_MKNOD, 0, -1, dirfd, path, &buf); + if (msg && msg->result != RESULT_SUCCEED) { + errno = EPERM; + rc = -1; + } else { + /* just pretend we worked */ + errno = save_errno; + rc = 0; + } + } + if (rc == -1) { + save_errno = errno; +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + real_unlink(path); +#else + real_unlinkat(dirfd, path, AT_SYMLINK_NOFOLLOW); +#endif + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/mknod.c b/ports/unix/guts/mknod.c new file mode 100644 index 0000000..eeca65d --- /dev/null +++ b/ports/unix/guts/mknod.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2011,2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int mknod(const char *path, mode_t mode, dev_t dev) + * int rc = -1; + */ + + rc = wrap_mknodat(AT_FDCWD, path, mode, dev); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/mknodat.c b/ports/unix/guts/mknodat.c new file mode 100644 index 0000000..76e4dd9 --- /dev/null +++ b/ports/unix/guts/mknodat.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev) + * int rc = -1; + */ + + pseudo_msg_t *msg; + PSEUDO_STATBUF buf; + int save_errno = errno; + + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + rc = base_stat(path, &buf); +#else + rc = base_fstatat(dirfd, path, &buf, AT_SYMLINK_NOFOLLOW); +#endif + if (rc != -1) { + /* if we can stat the file, you can't mknod it */ + errno = EEXIST; + return -1; + } +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real_open(path, O_CREAT | O_WRONLY | O_EXCL, + PSEUDO_FS_MODE(mode, 0)); +#else + rc = real_openat(dirfd, path, O_CREAT | O_WRONLY | O_EXCL, + PSEUDO_FS_MODE(mode, 0)); +#endif + if (rc == -1) { + return -1; + } + real_fchmod(rc, PSEUDO_FS_MODE(mode, 0)); + base_fstat(rc, &buf); + /* mknod does not really open the file. We don't have + * to use wrap_close because we've never exposed this file + * descriptor to the client code. + */ + real_close(rc); + + /* mask in the mode type bits again */ + buf.st_mode = (PSEUDO_DB_MODE(buf.st_mode, mode) & 07777) | + (mode & ~07777); + buf.st_rdev = dev; + msg = pseudo_client_op(OP_MKNOD, 0, -1, dirfd, path, &buf); + if (msg && msg->result != RESULT_SUCCEED) { + errno = EPERM; + rc = -1; + } else { + /* just pretend we worked */ + errno = save_errno; + rc = 0; + } + if (rc == -1) { + save_errno = errno; +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + real_unlink(path); +#else + real_unlinkat(dirfd, path, AT_SYMLINK_NOFOLLOW); +#endif + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/mkstemp.c b/ports/unix/guts/mkstemp.c new file mode 100644 index 0000000..1e2b026 --- /dev/null +++ b/ports/unix/guts/mkstemp.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2008-2010, 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_mkstemp(char *template) { + * int rc = -1; + */ + PSEUDO_STATBUF buf; + int save_errno; + size_t len; + char *tmp_template; + + if (!template) { + errno = EFAULT; + return 0; + } + + len = strlen(template); + tmp_template = PSEUDO_ROOT_PATH(AT_FDCWD, template, AT_SYMLINK_NOFOLLOW); + + if (!tmp_template) { + errno = ENOENT; + return -1; + } + + rc = real_mkstemp(tmp_template); + + if (rc != -1) { + save_errno = errno; + + if (base_fstat(rc, &buf) != -1) { + real_fchmod(rc, PSEUDO_FS_MODE(0600, 0)); + pseudo_client_op(OP_CREAT, 0, -1, -1, tmp_template, &buf); + pseudo_client_op(OP_OPEN, PSA_READ | PSA_WRITE, rc, -1, tmp_template, &buf); + } else { + pseudo_debug(PDBGF_CONSISTENCY, "mkstemp (fd %d) succeeded, but fstat failed (%s).\n", + rc, strerror(errno)); + pseudo_client_op(OP_OPEN, PSA_READ | PSA_WRITE, rc, -1, tmp_template, 0); + } + errno = save_errno; + } + /* mkstemp only changes the XXXXXX at the end. */ + memcpy(template + len - 6, tmp_template + strlen(tmp_template) - 6, 6); +/* return rc; + * } + */ diff --git a/ports/unix/guts/mktemp.c b/ports/unix/guts/mktemp.c new file mode 100644 index 0000000..a39d1b7 --- /dev/null +++ b/ports/unix/guts/mktemp.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static char * + * wrap_mktemp(char *template) { + * char * rc = NULL; + */ + size_t len; + char *tmp_template; + + if (!template) { + errno = EFAULT; + return NULL; + } + + len = strlen(template); + tmp_template = PSEUDO_ROOT_PATH(AT_FDCWD, template, AT_SYMLINK_NOFOLLOW); + + if (!tmp_template) { + errno = ENOENT; + return NULL; + } + + rc = real_mktemp(tmp_template); + + /* mktemp only changes the XXXXXX at the end, and never created + * a file -- note the race condition implied here. + */ + memcpy(template + len - 6, tmp_template + strlen(tmp_template) - 6, 6); + rc = template; + +/* return rc; + * } + */ diff --git a/ports/unix/guts/msync.c b/ports/unix/guts/msync.c new file mode 100644 index 0000000..fbc5e26 --- /dev/null +++ b/ports/unix/guts/msync.c @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2013 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int msync(void *addr, size_t length, int flags) + * int rc = -1; + */ + + /* note: wrapper will never call this if PSEUDO_FORCE_ASYNC + * is defined. + */ + rc = real_msync(addr, length, flags); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/nftw.c b/ports/unix/guts/nftw.c new file mode 100644 index 0000000..73daec8 --- /dev/null +++ b/ports/unix/guts/nftw.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_nftw(const char *path, int (*fn)(const char *, const struct stat *, int, struct FTW *), int nopenfd, int flag) { + * int rc = -1; + */ + + rc = real_nftw(path, fn, nopenfd, flag); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/opendir.c b/ports/unix/guts/opendir.c new file mode 100644 index 0000000..c8a78f8 --- /dev/null +++ b/ports/unix/guts/opendir.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010, 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static DIR * + * wrap_opendir(const char *path) { + * DIR * rc = NULL; + */ + PSEUDO_STATBUF buf; + int save_errno; + + rc = real_opendir(path); + if (rc) { + int fd; + save_errno = errno; + fd = dirfd(rc); + if (base_fstat(fd, &buf) == -1) { + pseudo_debug(PDBGF_CONSISTENCY, "diropen (fd %d) succeeded, but fstat failed (%s).\n", + fd, strerror(errno)); + pseudo_client_op(OP_OPEN, PSA_READ, fd, -1, path, 0); + } else { + pseudo_client_op(OP_OPEN, PSA_READ, fd, -1, path, &buf); + } + + + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/pathconf.c b/ports/unix/guts/pathconf.c new file mode 100644 index 0000000..c6caa34 --- /dev/null +++ b/ports/unix/guts/pathconf.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static long + * wrap_pathconf(const char *path, int name) { + * long rc = -1; + */ + + rc = real_pathconf(path, name); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/popen.c b/ports/unix/guts/popen.c new file mode 100644 index 0000000..5d44c0e --- /dev/null +++ b/ports/unix/guts/popen.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * FILE *popen(const char *command, const char *mode) + * FILE *rc = NULL; + */ + /* on at least some systems, popen() calls fork and exec + * in ways that avoid our usual enforcement of the environment. + */ + pseudo_setupenv(); + if (pseudo_has_unload(NULL)) + pseudo_dropenv(); + + rc = real_popen(command, mode); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/readlink.c b/ports/unix/guts/readlink.c new file mode 100644 index 0000000..18d9dc7 --- /dev/null +++ b/ports/unix/guts/readlink.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static ssize_t + * wrap_readlink(const char *path, char *buf, size_t bufsiz) { + * ssize_t rc = -1; + */ + + rc = wrap_readlinkat(AT_FDCWD, path, buf, bufsiz); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/readlinkat.c b/ports/unix/guts/readlinkat.c new file mode 100644 index 0000000..5282e2b --- /dev/null +++ b/ports/unix/guts/readlinkat.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static ssize_t + * wrap_readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) { + * ssize_t rc = -1; + */ +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + rc = real_readlink(path, buf, bufsiz); +#else + rc = real_readlinkat(dirfd, path, buf, bufsiz); +#endif + + if (rc > 0) { + rc = pseudo_dechroot(buf, rc); + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/realpath.c b/ports/unix/guts/realpath.c new file mode 100644 index 0000000..a59808d --- /dev/null +++ b/ports/unix/guts/realpath.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static char * + * wrap_realpath(const char *name, char *resolved_name) { + * char * rc = NULL; + */ + char *rname = PSEUDO_ROOT_PATH(AT_FDCWD, name, 0); + ssize_t len; + if (!rname) { + errno = ENAMETOOLONG; + return NULL; + } + if ((len = strlen(rname)) >= pseudo_sys_path_max()) { + errno = ENAMETOOLONG; + return NULL; + } + if (resolved_name) { + memcpy(resolved_name, rname, len + 1); + rc = resolved_name; + } else { + rc = strdup(rname); + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/remove.c b/ports/unix/guts/remove.c new file mode 100644 index 0000000..4e2cecb --- /dev/null +++ b/ports/unix/guts/remove.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2008-2010, 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_remove(const char *path) { + * int rc = -1; + */ + PSEUDO_STATBUF buf; + if (base_lstat(path, &buf) == -1) { + errno = ENOENT; + return -1; + } + if (S_ISDIR(buf.st_mode)) { + rc = wrap_rmdir(path); + } else { + rc = wrap_unlink(path); + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/rename.c b/ports/unix/guts/rename.c new file mode 100644 index 0000000..b8ee8b0 --- /dev/null +++ b/ports/unix/guts/rename.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2008-2010, 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_rename(const char *oldpath, const char *newpath) { + * int rc = -1; + */ + pseudo_msg_t *msg; + PSEUDO_STATBUF oldbuf, newbuf; + int oldrc, newrc; + int save_errno; + int old_db_entry = 0; + int may_unlinked = 0; + + pseudo_debug(PDBGF_OP, "rename: %s->%s\n", + oldpath ? oldpath : "<nil>", + newpath ? newpath : "<nil>"); + + if (!oldpath || !newpath) { + errno = EFAULT; + return -1; + } + + save_errno = errno; + + newrc = base_lstat(newpath, &newbuf); + oldrc = base_lstat(oldpath, &oldbuf); + + errno = save_errno; + + /* newpath must be removed. */ + /* as with unlink, we have to mark that the file may get deleted */ + msg = pseudo_client_op(OP_MAY_UNLINK, 0, -1, -1, newpath, newrc ? NULL : &newbuf); + if (msg && msg->result == RESULT_SUCCEED) + may_unlinked = 1; + msg = pseudo_client_op(OP_STAT, 0, -1, -1, oldpath, oldrc ? NULL : &oldbuf); + if (msg && msg->result == RESULT_SUCCEED) + old_db_entry = 1; + rc = real_rename(oldpath, newpath); + save_errno = errno; + if (may_unlinked) { + if (rc == -1) { + /* since we failed, that wasn't really unlinked -- put + * it back. + */ + pseudo_client_op(OP_CANCEL_UNLINK, 0, -1, -1, newpath, &newbuf); + } else { + /* confirm that the file was removed */ + pseudo_client_op(OP_DID_UNLINK, 0, -1, -1, newpath, &newbuf); + } + } + if (rc == -1) { + /* and we're done. */ + errno = save_errno; + return rc; + } + save_errno = errno; + /* nothing to do for a "rename" of a link to itself */ + if (newrc != -1 && oldrc != -1 && + newbuf.st_dev == oldbuf.st_dev && + newbuf.st_ino == oldbuf.st_ino) { + return rc; + } + + /* rename(3) is not mv(1). rename(file, dir) fails; you must provide + * the corrected path yourself. You can rename over a directory only + * if the source is a directory. Symlinks are simply removed. + * + * If we got here, the real rename call succeeded. That means newpath + * has been unlinked and oldpath has been linked to it. + * + * There are a ton of special cases to error check. I don't check + * for any of them, because in every such case, the underlying rename + * failed, and there is nothing to do. + * The only tricky part is that, because we used to ignore symlinks, + * we may have to rename or remove directory trees even though in + * theory rename can never destroy a directory tree. + */ + if (!old_db_entry) { + /* create an entry under the old name, which will then be + * renamed; this way, children would get renamed too, if there + * were any. + */ + if (newrc == 0) { + if (newbuf.st_dev != oldbuf.st_dev) { + oldbuf.st_dev = newbuf.st_dev; + oldbuf.st_ino = newbuf.st_ino; + } + } + pseudo_debug(PDBGF_FILE, "creating new '%s' [%llu] to rename\n", + oldpath, (unsigned long long) oldbuf.st_ino); + pseudo_client_op(OP_LINK, 0, -1, -1, oldpath, &oldbuf); + } + pseudo_client_op(OP_RENAME, 0, -1, -1, newpath, &oldbuf, oldpath); + + errno = save_errno; +/* return rc; + * } + */ diff --git a/ports/unix/guts/renameat.c b/ports/unix/guts/renameat.c new file mode 100644 index 0000000..ade0509 --- /dev/null +++ b/ports/unix/guts/renameat.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2008-2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { + * int rc = -1; + */ + pseudo_msg_t *msg; + PSEUDO_STATBUF oldbuf, newbuf; + int oldrc, newrc; + int save_errno; + int old_db_entry = 0; + + pseudo_debug(PDBGF_FILE, "renameat: %d,%s->%d,%s\n", + olddirfd, oldpath ? oldpath : "<nil>", + newdirfd, newpath ? newpath : "<nil>"); + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (olddirfd != AT_FDCWD || newdirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } +#endif + + if (!oldpath || !newpath) { + errno = EFAULT; + return -1; + } + + save_errno = errno; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + newrc = base_lstat(newpath, &newbuf); + oldrc = base_lstat(oldpath, &oldbuf); +#else + oldrc = base_fstatat(olddirfd, oldpath, &oldbuf, AT_SYMLINK_NOFOLLOW); + newrc = base_fstatat(newdirfd, newpath, &newbuf, AT_SYMLINK_NOFOLLOW); +#endif + + errno = save_errno; + + /* newpath must be removed. */ + /* as with unlink, we have to mark that the file may get deleted */ + msg = pseudo_client_op(OP_MAY_UNLINK, 0, -1, newdirfd, newpath, newrc ? NULL : &newbuf); + if (msg && msg->result == RESULT_SUCCEED) + old_db_entry = 1; + rc = real_renameat(olddirfd, oldpath, newdirfd, newpath); + save_errno = errno; + if (old_db_entry) { + if (rc == -1) { + /* since we failed, that wasn't really unlinked -- put + * it back. + */ + pseudo_client_op(OP_CANCEL_UNLINK, 0, -1, newdirfd, newpath, &newbuf); + } else { + /* confirm that the file was removed */ + pseudo_client_op(OP_DID_UNLINK, 0, -1, newdirfd, newpath, &newbuf); + } + } + if (rc == -1) { + /* and we're done. */ + errno = save_errno; + return rc; + } + save_errno = errno; + /* nothing to do for a "rename" of a link to itself */ + if (newrc != -1 && oldrc != -1 && + newbuf.st_dev == oldbuf.st_dev && + newbuf.st_ino == oldbuf.st_ino) { + return rc; + } + + /* rename(3) is not mv(1). rename(file, dir) fails; you must provide + * the corrected path yourself. You can rename over a directory only + * if the source is a directory. Symlinks are simply removed. + * + * If we got here, the real rename call succeeded. That means newpath + * has been unlinked and oldpath has been linked to it. + * + * There are a ton of special cases to error check. I don't check + * for any of them, because in every such case, the underlying rename + * failed, and there is nothing to do. + * The only tricky part is that, because we used to ignore symlinks, + * we may have to rename or remove directory trees even though in + * theory rename can never destroy a directory tree. + */ + if (!old_db_entry) { + /* create an entry under the old name, which will then be + * renamed; this way, children would get renamed too, if there + * were any. + */ + if (newrc == 0) { + if (newbuf.st_dev != oldbuf.st_dev) { + oldbuf.st_dev = newbuf.st_dev; + oldbuf.st_ino = newbuf.st_ino; + } + } + pseudo_debug(PDBGF_OP, "creating new '%s' [%llu] to rename\n", + oldpath, (unsigned long long) oldbuf.st_ino); + pseudo_client_op(OP_LINK, 0, -1, olddirfd, oldpath, &oldbuf); + } + /* special case: use 'fd' for olddirfd, because + * we know it has no other meaning for RENAME + */ + pseudo_client_op(OP_RENAME, 0, olddirfd, newdirfd, newpath, &oldbuf, oldpath); + + errno = save_errno; +/* return rc; + * } + */ diff --git a/ports/unix/guts/rmdir.c b/ports/unix/guts/rmdir.c new file mode 100644 index 0000000..ebc522a --- /dev/null +++ b/ports/unix/guts/rmdir.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008-2010, 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_rmdir(const char *path) { + * int rc = -1; + */ + pseudo_msg_t *msg; + PSEUDO_STATBUF buf; + int save_errno; + int old_db_entry = 0; + + rc = base_lstat(path, &buf); + if (rc == -1) { + return rc; + } + msg = pseudo_client_op(OP_MAY_UNLINK, 0, -1, -1, path, &buf); + if (msg && msg->result == RESULT_SUCCEED) + old_db_entry = 1; + rc = real_rmdir(path); + if (old_db_entry) { + if (rc == -1) { + save_errno = errno; + pseudo_client_op(OP_CANCEL_UNLINK, 0, -1, -1, path, &buf); + errno = save_errno; + } else { + pseudo_client_op(OP_DID_UNLINK, 0, -1, -1, path, &buf); + } + } else { + pseudo_debug(PDBGF_FILE, "rmdir on <%s>, not in database, no effect.\n", path); + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/symlink.c b/ports/unix/guts/symlink.c new file mode 100644 index 0000000..487c135 --- /dev/null +++ b/ports/unix/guts/symlink.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_symlink(const char *oldname, const char *newpath) { + * int rc = -1; + */ + + rc = wrap_symlinkat(oldname, AT_FDCWD, newpath); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/symlinkat.c b/ports/unix/guts/symlinkat.c new file mode 100644 index 0000000..1346db1 --- /dev/null +++ b/ports/unix/guts/symlinkat.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008-2010, 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_symlinkat(const char *oldname, int dirfd, const char *newpath) { + * int rc = -1; + */ + PSEUDO_STATBUF buf; + char *roldname = 0; + + if (oldname[0] == '/' && pseudo_chroot_len && !pseudo_nosymlinkexp) { + size_t len = pseudo_chroot_len + strlen(oldname) + 1; + roldname = malloc(len); + snprintf(roldname, len, "%s%s", pseudo_chroot, oldname); + } + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + rc = real_symlink(roldname ? roldname : oldname, newpath); +#else + rc = real_symlinkat(roldname ? roldname : oldname, dirfd, newpath); +#endif + + if (rc == -1) { + free(roldname); + return rc; + } +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = base_lstat(newpath, &buf); +#else + rc = base_fstatat(dirfd, newpath, &buf, AT_SYMLINK_NOFOLLOW); +#endif + if (rc == -1) { + int save_errno = errno; + pseudo_diag("symlinkat: couldn't stat '%s' even though symlink creation succeeded (%s).\n", + newpath, strerror(errno)); + errno = save_errno; + free(roldname); + return rc; + } + /* just record the entry */ + pseudo_client_op(OP_SYMLINK, 0, -1, dirfd, newpath, &buf); + + free(roldname); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/sync.c b/ports/unix/guts/sync.c new file mode 100644 index 0000000..c5d9554 --- /dev/null +++ b/ports/unix/guts/sync.c @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2013 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * void sync(void) + * + */ + + /* note: wrapper will never call this if PSEUDO_FORCE_ASYNC + * is defined. + */ + (void) real_sync(); + +/* return; + * } + */ diff --git a/ports/unix/guts/sync_file_range.c b/ports/unix/guts/sync_file_range.c new file mode 100644 index 0000000..03cfc6c --- /dev/null +++ b/ports/unix/guts/sync_file_range.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2013 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags) + * int rc = -1; + */ + + rc = real_sync_file_range(fd, offset, nbytes, flags); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/syncfs.c b/ports/unix/guts/syncfs.c new file mode 100644 index 0000000..2c9a685 --- /dev/null +++ b/ports/unix/guts/syncfs.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2013 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int syncfs(int fd) + * int rc = -1; + */ + + rc = real_syncfs(fd); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/system.c b/ports/unix/guts/system.c new file mode 100644 index 0000000..6351592 --- /dev/null +++ b/ports/unix/guts/system.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011, 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int system(const char *command) + * int rc = -1; + */ + if (!command) + return 1; + + pseudo_setupenv(); + if (pseudo_has_unload(NULL)) + pseudo_dropenv(); + + rc = real_system(command); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/tempnam.c b/ports/unix/guts/tempnam.c new file mode 100644 index 0000000..9b0257f --- /dev/null +++ b/ports/unix/guts/tempnam.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static char * + * wrap_tempnam(const char *template, const char *pfx) { + * char * rc = NULL; + */ + /* let gcc know we ignored these on purpose */ + (void) template; + (void) pfx; + pseudo_diag("tempnam() is so ludicrously insecure as to defy implementation."); + errno = ENOMEM; + rc = NULL; + +/* return rc; + * } + */ diff --git a/ports/unix/guts/tmpnam.c b/ports/unix/guts/tmpnam.c new file mode 100644 index 0000000..3fece57 --- /dev/null +++ b/ports/unix/guts/tmpnam.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static char * + * wrap_tmpnam(char *s) { + * char * rc = NULL; + */ + + /* let gcc know we're ignoring this */ + (void) s; + pseudo_diag("tmpnam() is so ludicrously insecure as to defy implementation."); + errno = ENOMEM; + rc = NULL; + +/* return rc; + * } + */ diff --git a/ports/unix/guts/truncate.c b/ports/unix/guts/truncate.c new file mode 100644 index 0000000..6a19a50 --- /dev/null +++ b/ports/unix/guts/truncate.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_truncate(const char *path, off_t length) { + * int rc = -1; + */ + + rc = real_truncate(path, length); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/umask.c b/ports/unix/guts/umask.c new file mode 100644 index 0000000..6b060d3 --- /dev/null +++ b/ports/unix/guts/umask.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * mode_t umask(mode_t mask) + * mode_t rc = 0; + */ + + pseudo_umask = mask; + rc = real_umask(mask); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/unlink.c b/ports/unix/guts/unlink.c new file mode 100644 index 0000000..d8a5d01 --- /dev/null +++ b/ports/unix/guts/unlink.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_unlink(const char *path) { + * int rc = -1; + */ + + rc = wrap_unlinkat(AT_FDCWD, path, 0); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/unlinkat.c b/ports/unix/guts/unlinkat.c new file mode 100644 index 0000000..e723a01 --- /dev/null +++ b/ports/unix/guts/unlinkat.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008-2010, 2012 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_unlinkat(int dirfd, const char *path, int rflags) { + * int rc = -1; + */ + pseudo_msg_t *msg; + int save_errno; + PSEUDO_STATBUF buf; + int old_db_entry = 0; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + if (rflags) { + /* the only supported flag is AT_REMOVEDIR. We'd never call + * with that flag unless the real AT functions exist, so + * something must have gone horribly wrong.... + */ + pseudo_diag("wrap_unlinkat called with flags (0x%x), path '%s'\n", + rflags, path ? path : "<nil>"); + errno = ENOSYS; + return -1; + } +#endif + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = base_lstat(path, &buf); +#else + rc = base_fstatat(dirfd, path, &buf, AT_SYMLINK_NOFOLLOW); +#endif + if (rc == -1) { + return rc; + } + msg = pseudo_client_op(OP_MAY_UNLINK, 0, -1, dirfd, path, &buf); + if (msg && msg->result == RESULT_SUCCEED) + old_db_entry = 1; +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real_unlink(path); +#else + rc = real_unlinkat(dirfd, path, rflags); +#endif + if (old_db_entry) { + if (rc == -1) { + save_errno = errno; + pseudo_client_op(OP_CANCEL_UNLINK, 0, -1, -1, path, &buf); + errno = save_errno; + } else { + pseudo_client_op(OP_DID_UNLINK, 0, -1, -1, path, &buf); + } + } else { + pseudo_debug(PDBGF_FILE, "unlink on <%s>, not in database, no effect.\n", path); + } + +/* return rc; + * } + */ diff --git a/ports/unix/guts/utime.c b/ports/unix/guts/utime.c new file mode 100644 index 0000000..ff65237 --- /dev/null +++ b/ports/unix/guts/utime.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_utime(const char *path, const struct utimbuf *buf) { + * int rc = -1; + */ + rc = real_utime(path, buf); + +/* return rc; + * } + */ diff --git a/ports/unix/guts/utimes.c b/ports/unix/guts/utimes.c new file mode 100644 index 0000000..69ad949 --- /dev/null +++ b/ports/unix/guts/utimes.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2010 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * static int + * wrap_utimes(const char *path, const struct timeval *times) { + * int rc = -1; + */ + rc = real_utimes(path, times); + +/* return rc; + * } + */ diff --git a/ports/unix/pseudo_wrappers.c b/ports/unix/pseudo_wrappers.c new file mode 100644 index 0000000..b825d56 --- /dev/null +++ b/ports/unix/pseudo_wrappers.c @@ -0,0 +1,50 @@ +FILE * +popen(const char *command, const char *mode) { + sigset_t saved; + + FILE *rc = NULL; + + if (!pseudo_check_wrappers() || !real_popen) { + /* rc was initialized to the "failure" value */ + pseudo_enosys("popen"); + return rc; + } + + pseudo_debug(PDBGF_WRAPPER, "called: popen\n"); + pseudo_sigblock(&saved); + if (pseudo_getlock()) { + errno = EBUSY; + sigprocmask(SIG_SETMASK, &saved, NULL); + return NULL; + } + + int save_errno; + /* exec*() use this to restore the sig mask */ + pseudo_saved_sigmask = saved; + rc = wrap_popen(command, mode); + + save_errno = errno; + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); +#if 0 +/* This can cause hangs on some recentish systems which use locale + * stuff for strerror... + */ + pseudo_debug(PDBGF_WRAPPER, "completed: popen (maybe: %s)\n", strerror(save_errno)); +#endif + pseudo_debug(PDBGF_WRAPPER, "completed: popen (errno: %d)\n", save_errno); + errno = save_errno; + return rc; +} + +static FILE * +wrap_popen(const char *command, const char *mode) { + FILE *rc = NULL; + + + +#include "guts/popen.c" + + return rc; +} + diff --git a/ports/unix/wrapfuncs.in b/ports/unix/wrapfuncs.in new file mode 100644 index 0000000..5f30ae6 --- /dev/null +++ b/ports/unix/wrapfuncs.in @@ -0,0 +1,70 @@ +int creat(const char *path, mode_t mode); +char *getcwd(char *buf, size_t size); +char *getwd(char *buf); +int close(int fd); +int fchmod(int fd, mode_t mode); +int fchown(int fd, uid_t owner, gid_t group); +int lchown(const char *path, uid_t owner, gid_t group); /* flags=AT_SYMLINK_NOFOLLOW */ +int dup2(int oldfd, int newfd); +int dup(int fd); +int chdir(const char *path); +int fchdir(int dirfd); +int access(const char *path, int mode); +FTS *fts_open(char * const *path_argv, int options, int (*compar)(const FTSENT **, const FTSENT **)); /* inode64=1 */ +int ftw(const char *path, int (*fn)(const char *, const struct stat *, int), int nopenfd); +int nftw(const char *path, int (*fn)(const char *, const struct stat *, int, struct FTW *), int nopenfd, int flag); +int glob(const char *pattern, int flags, int (*errfunc)(const char *, int), glob_t *pglob); +int lutimes(const char *path, const struct timeval *tv); /* flags=AT_SYMLINK_NOFOLLOW */ +char *mkdtemp(char *template); +char *mktemp(char *template); +long pathconf(const char *path, int name); +char *realpath(const char *name, char *resolved_name); /* version="GLIBC_2.3" */ +int remove(const char *path); /* flags=AT_SYMLINK_NOFOLLOW */ +DIR *opendir(const char *path); +int closedir(DIR *dirp); +char *tempnam(const char *template, const char *pfx); +char *tmpnam(char *s); +int truncate(const char *path, off_t length); +int utime(const char *path, const struct utimbuf *buf); +int utimes(const char *path, const struct timeval *times); +# needed because libc stdio does horrible things with inline asm syscalls +FILE *fopen(const char *path, const char *mode); +int fclose(FILE *fp); +FILE *freopen(const char *path, const char *mode, FILE *stream); +int chroot(const char *path); +int acct(const char *path); +int chmod(const char *path, mode_t mode); +int chown(const char *path, uid_t owner, gid_t group); +int fchmodat(int dirfd, const char *path, mode_t mode, int flags); +int fchownat(int dirfd, const char *path, uid_t owner, gid_t group, int flags); +int link(const char *oldname, const char *newname); /* flags=AT_SYMLINK_NOFOLLOW */ +int linkat(int olddirfd, const char *oldname, int newdirfd, const char *newname, int flags); +int mkdir(const char *path, mode_t mode); /* flags=AT_SYMLINK_NOFOLLOW */ +int mkdirat(int dirfd, const char *path, mode_t mode); /* flags=AT_SYMLINK_NOFOLLOW */ +int mkfifo(const char *path, mode_t mode); /* flags=AT_SYMLINK_NOFOLLOW */ +int mkfifoat(int dirfd, const char *path, mode_t mode); /* flags=AT_SYMLINK_NOFOLLOW */ +int mknod(const char *path, mode_t mode, dev_t dev); /* flags=AT_SYMLINK_NOFOLLOW */ +int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev); /* flags=AT_SYMLINK_NOFOLLOW */ +int mkstemp(char *template); /* flags=AT_SYMLINK_NOFOLLOW */ +int rename(const char *oldpath, const char *newpath); /* flags=AT_SYMLINK_NOFOLLOW */ +int renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); /* flags=AT_SYMLINK_NOFOLLOW */ +int rmdir(const char *path); /* flags=AT_SYMLINK_NOFOLLOW */ +int symlink(const char *oldname, const char *newpath); /* flags=AT_SYMLINK_NOFOLLOW */ +int symlinkat(const char *oldname, int dirfd, const char *newpath); /* flags=AT_SYMLINK_NOFOLLOW */ +int unlink(const char *path); /* flags=AT_SYMLINK_NOFOLLOW */ +int unlinkat(int dirfd, const char *path, int rflags); /* flags=AT_SYMLINK_NOFOLLOW */ +# primarily for use with chroot() +ssize_t readlink(const char *path, char *buf, size_t bufsiz); /* flags=AT_SYMLINK_NOFOLLOW */ +ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz); /* flags=AT_SYMLINK_NOFOLLOW */ +int system(const char *command); +FILE *popen(const char *command, const char *mode); /* hand_wrapped=1 */ +# Based on experiments by Richard Purdie: Allow pseudo to eliminate +# sync-type operations globally, mostly relevant for performance reasons +# during filesystem assembly. +int fsync(int fd); /* async_skip=0 */ +int fdatasync(int fd); /* async_skip=0 */ +void sync(void); /* async_skip= */ +int syncfs(int fd); /* async_skip=0 */ +int sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags); /* async_skip=0 */ +int msync(void *addr, size_t length, int flags); /* async_skip=0 */ +mode_t umask(mode_t mask); |