summaryrefslogtreecommitdiff
path: root/ports
diff options
context:
space:
mode:
Diffstat (limited to 'ports')
-rw-r--r--ports/common/guts/execl.c18
-rw-r--r--ports/common/guts/execle.c18
-rw-r--r--ports/common/guts/execlp.c18
-rw-r--r--ports/common/guts/execv.c32
-rw-r--r--ports/common/guts/execve.c33
-rw-r--r--ports/common/guts/execvp.c33
-rw-r--r--ports/common/guts/fork.c23
-rw-r--r--ports/common/pseudo_wrappers.c408
-rwxr-xr-xports/common/subports8
-rw-r--r--ports/common/wrapfuncs.in7
-rw-r--r--ports/darwin/guts/COPYRIGHT17
-rw-r--r--ports/darwin/guts/fcntl.c44
-rw-r--r--ports/darwin/guts/fgetgrent_r.c13
-rw-r--r--ports/darwin/guts/fgetpwent_r.c13
-rw-r--r--ports/darwin/guts/fgetxattr.c13
-rw-r--r--ports/darwin/guts/flistxattr.c13
-rw-r--r--ports/darwin/guts/fremovexattr.c13
-rw-r--r--ports/darwin/guts/fsetxattr.c13
-rw-r--r--ports/darwin/guts/fstat.c27
-rw-r--r--ports/darwin/guts/getgrent_r.c13
-rw-r--r--ports/darwin/guts/getgrouplist.c42
-rw-r--r--ports/darwin/guts/getgroups.c22
-rw-r--r--ports/darwin/guts/getpwent_r.c13
-rw-r--r--ports/darwin/guts/getxattr.c13
-rw-r--r--ports/darwin/guts/listxattr.c13
-rw-r--r--ports/darwin/guts/lstat.c27
-rw-r--r--ports/darwin/guts/open.c58
-rw-r--r--ports/darwin/guts/removexattr.c13
-rw-r--r--ports/darwin/guts/scandir.c14
-rw-r--r--ports/darwin/guts/setxattr.c13
-rw-r--r--ports/darwin/guts/stat.c31
-rw-r--r--ports/darwin/guts/sync_file_range.c13
-rw-r--r--ports/darwin/portdefs.h13
-rwxr-xr-xports/darwin/preports2
-rw-r--r--ports/darwin/pseudo_wrappers.c606
-rwxr-xr-xports/darwin/subports3
-rw-r--r--ports/darwin/wrapfuncs.in27
-rw-r--r--ports/linux/guts/COPYRIGHT17
-rw-r--r--ports/linux/guts/__fxstat.c20
-rw-r--r--ports/linux/guts/__fxstat64.c30
-rw-r--r--ports/linux/guts/__fxstatat.c32
-rw-r--r--ports/linux/guts/__fxstatat64.c58
-rw-r--r--ports/linux/guts/__lxstat.c14
-rw-r--r--ports/linux/guts/__lxstat64.c14
-rw-r--r--ports/linux/guts/__openat64_2.c14
-rw-r--r--ports/linux/guts/__openat_2.c14
-rw-r--r--ports/linux/guts/__xmknod.c14
-rw-r--r--ports/linux/guts/__xmknodat.c78
-rw-r--r--ports/linux/guts/__xstat.c14
-rw-r--r--ports/linux/guts/__xstat64.c13
-rw-r--r--ports/linux/guts/canonicalize_file_name.c14
-rw-r--r--ports/linux/guts/creat64.c14
-rw-r--r--ports/linux/guts/eaccess.c14
-rw-r--r--ports/linux/guts/euidaccess.c14
-rw-r--r--ports/linux/guts/fcntl.c71
-rw-r--r--ports/linux/guts/fopen64.c37
-rw-r--r--ports/linux/guts/freopen64.c36
-rw-r--r--ports/linux/guts/fstat.c13
-rw-r--r--ports/linux/guts/fstat64.c13
-rw-r--r--ports/linux/guts/ftw64.c14
-rw-r--r--ports/linux/guts/get_current_dir_name.c17
-rw-r--r--ports/linux/guts/getgrent_r.c21
-rw-r--r--ports/linux/guts/getgrouplist.c42
-rw-r--r--ports/linux/guts/getgroups.c22
-rw-r--r--ports/linux/guts/getpw.c33
-rw-r--r--ports/linux/guts/getpwent_r.c21
-rw-r--r--ports/linux/guts/getresgid.c23
-rw-r--r--ports/linux/guts/getresuid.c23
-rw-r--r--ports/linux/guts/glob64.c36
-rw-r--r--ports/linux/guts/lchown.c13
-rw-r--r--ports/linux/guts/lckpwdf.c32
-rw-r--r--ports/linux/guts/lstat.c13
-rw-r--r--ports/linux/guts/lstat64.c13
-rw-r--r--ports/linux/guts/mkstemp64.c47
-rw-r--r--ports/linux/guts/nftw64.c14
-rw-r--r--ports/linux/guts/open.c14
-rw-r--r--ports/linux/guts/open64.c14
-rw-r--r--ports/linux/guts/openat.c92
-rw-r--r--ports/linux/guts/openat64.c14
-rw-r--r--ports/linux/guts/scandir.c14
-rw-r--r--ports/linux/guts/scandir64.c14
-rw-r--r--ports/linux/guts/setfsgid.c19
-rw-r--r--ports/linux/guts/setfsuid.c19
-rw-r--r--ports/linux/guts/setgroups.c18
-rw-r--r--ports/linux/guts/setresgid.c37
-rw-r--r--ports/linux/guts/setresuid.c37
-rw-r--r--ports/linux/guts/stat.c13
-rw-r--r--ports/linux/guts/stat64.c13
-rw-r--r--ports/linux/guts/truncate64.c14
-rw-r--r--ports/linux/guts/ulckpwdf.c15
-rw-r--r--ports/linux/newclone/guts/clone.c31
-rw-r--r--ports/linux/newclone/pseudo_wrappers.c92
-rw-r--r--ports/linux/newclone/wrapfuncs.in1
-rw-r--r--ports/linux/noxattr/guts/fgetxattr.c18
-rw-r--r--ports/linux/noxattr/guts/flistxattr.c17
-rw-r--r--ports/linux/noxattr/guts/fremovexattr.c16
-rw-r--r--ports/linux/noxattr/guts/fsetxattr.c19
-rw-r--r--ports/linux/noxattr/guts/getxattr.c18
-rw-r--r--ports/linux/noxattr/guts/lgetxattr.c18
-rw-r--r--ports/linux/noxattr/guts/listxattr.c17
-rw-r--r--ports/linux/noxattr/guts/llistxattr.c17
-rw-r--r--ports/linux/noxattr/guts/lremovexattr.c16
-rw-r--r--ports/linux/noxattr/guts/lsetxattr.c19
-rw-r--r--ports/linux/noxattr/guts/removexattr.c16
-rw-r--r--ports/linux/noxattr/guts/setxattr.c19
-rw-r--r--ports/linux/noxattr/wrapfuncs.in14
-rw-r--r--ports/linux/oldclone/guts/clone.c31
-rw-r--r--ports/linux/oldclone/pseudo_wrappers.c76
-rw-r--r--ports/linux/oldclone/wrapfuncs.in1
-rw-r--r--ports/linux/portdefs.h27
-rwxr-xr-xports/linux/preports2
-rw-r--r--ports/linux/pseudo_wrappers.c33
-rwxr-xr-xports/linux/subports43
-rw-r--r--ports/linux/wrapfuncs.in53
-rw-r--r--ports/linux/xattr/guts/fgetxattr.c12
-rw-r--r--ports/linux/xattr/guts/flistxattr.c12
-rw-r--r--ports/linux/xattr/guts/fremovexattr.c12
-rw-r--r--ports/linux/xattr/guts/fsetxattr.c12
-rw-r--r--ports/linux/xattr/guts/getxattr.c12
-rw-r--r--ports/linux/xattr/guts/lgetxattr.c12
-rw-r--r--ports/linux/xattr/guts/listxattr.c12
-rw-r--r--ports/linux/xattr/guts/llistxattr.c12
-rw-r--r--ports/linux/xattr/guts/lremovexattr.c12
-rw-r--r--ports/linux/xattr/guts/lsetxattr.c12
-rw-r--r--ports/linux/xattr/guts/removexattr.c12
-rw-r--r--ports/linux/xattr/guts/setxattr.c12
-rw-r--r--ports/linux/xattr/portdefs.h2
-rw-r--r--ports/linux/xattr/pseudo_wrappers.c233
-rw-r--r--ports/linux/xattr/wrapfuncs.in12
-rw-r--r--ports/uids_generic/guts/COPYRIGHT17
-rw-r--r--ports/uids_generic/guts/endgrent.c14
-rw-r--r--ports/uids_generic/guts/endpwent.c14
-rw-r--r--ports/uids_generic/guts/getegid.c14
-rw-r--r--ports/uids_generic/guts/geteuid.c14
-rw-r--r--ports/uids_generic/guts/getgid.c14
-rw-r--r--ports/uids_generic/guts/getgrent.c21
-rw-r--r--ports/uids_generic/guts/getgrgid.c21
-rw-r--r--ports/uids_generic/guts/getgrgid_r.c30
-rw-r--r--ports/uids_generic/guts/getgrnam.c23
-rw-r--r--ports/uids_generic/guts/getgrnam_r.c29
-rw-r--r--ports/uids_generic/guts/getpwent.c21
-rw-r--r--ports/uids_generic/guts/getpwnam.c21
-rw-r--r--ports/uids_generic/guts/getpwnam_r.c28
-rw-r--r--ports/uids_generic/guts/getpwuid.c21
-rw-r--r--ports/uids_generic/guts/getpwuid_r.c28
-rw-r--r--ports/uids_generic/guts/getuid.c14
-rw-r--r--ports/uids_generic/guts/setegid.c20
-rw-r--r--ports/uids_generic/guts/seteuid.c20
-rw-r--r--ports/uids_generic/guts/setgid.c27
-rw-r--r--ports/uids_generic/guts/setgrent.c14
-rw-r--r--ports/uids_generic/guts/setpwent.c14
-rw-r--r--ports/uids_generic/guts/setregid.c30
-rw-r--r--ports/uids_generic/guts/setreuid.c30
-rw-r--r--ports/uids_generic/guts/setuid.c27
-rw-r--r--ports/uids_generic/wrapfuncs.in25
-rw-r--r--ports/unix/guts/COPYRIGHT17
-rw-r--r--ports/unix/guts/access.c31
-rw-r--r--ports/unix/guts/acct.c14
-rw-r--r--ports/unix/guts/chdir.c24
-rw-r--r--ports/unix/guts/chmod.c14
-rw-r--r--ports/unix/guts/chown.c14
-rw-r--r--ports/unix/guts/chroot.c19
-rw-r--r--ports/unix/guts/close.c17
-rw-r--r--ports/unix/guts/closedir.c20
-rw-r--r--ports/unix/guts/creat.c14
-rw-r--r--ports/unix/guts/dup.c19
-rw-r--r--ports/unix/guts/dup2.c22
-rw-r--r--ports/unix/guts/fchdir.c18
-rw-r--r--ports/unix/guts/fchmod.c25
-rw-r--r--ports/unix/guts/fchmodat.c76
-rw-r--r--ports/unix/guts/fchown.c46
-rw-r--r--ports/unix/guts/fchownat.c56
-rw-r--r--ports/unix/guts/fclose.c20
-rw-r--r--ports/unix/guts/fdatasync.c16
-rw-r--r--ports/unix/guts/fopen.c36
-rw-r--r--ports/unix/guts/freopen.c36
-rw-r--r--ports/unix/guts/fsync.c16
-rw-r--r--ports/unix/guts/fts_open.c48
-rw-r--r--ports/unix/guts/ftw.c14
-rw-r--r--ports/unix/guts/getcwd.c67
-rw-r--r--ports/unix/guts/getwd.c21
-rw-r--r--ports/unix/guts/glob.c36
-rw-r--r--ports/unix/guts/lchown.c13
-rw-r--r--ports/unix/guts/link.c20
-rw-r--r--ports/unix/guts/linkat.c70
-rw-r--r--ports/unix/guts/lutimes.c14
-rw-r--r--ports/unix/guts/mkdir.c14
-rw-r--r--ports/unix/guts/mkdirat.c48
-rw-r--r--ports/unix/guts/mkdtemp.c45
-rw-r--r--ports/unix/guts/mkfifo.c14
-rw-r--r--ports/unix/guts/mkfifoat.c78
-rw-r--r--ports/unix/guts/mknod.c13
-rw-r--r--ports/unix/guts/mknodat.c73
-rw-r--r--ports/unix/guts/mkstemp.c47
-rw-r--r--ports/unix/guts/mktemp.c35
-rw-r--r--ports/unix/guts/msync.c16
-rw-r--r--ports/unix/guts/nftw.c14
-rw-r--r--ports/unix/guts/opendir.c31
-rw-r--r--ports/unix/guts/pathconf.c14
-rw-r--r--ports/unix/guts/popen.c19
-rw-r--r--ports/unix/guts/readlink.c14
-rw-r--r--ports/unix/guts/readlinkat.c25
-rw-r--r--ports/unix/guts/realpath.c28
-rw-r--r--ports/unix/guts/remove.c22
-rw-r--r--ports/unix/guts/rename.c100
-rw-r--r--ports/unix/guts/renameat.c111
-rw-r--r--ports/unix/guts/rmdir.c36
-rw-r--r--ports/unix/guts/symlink.c14
-rw-r--r--ports/unix/guts/symlinkat.c52
-rw-r--r--ports/unix/guts/sync.c16
-rw-r--r--ports/unix/guts/sync_file_range.c13
-rw-r--r--ports/unix/guts/syncfs.c13
-rw-r--r--ports/unix/guts/system.c19
-rw-r--r--ports/unix/guts/tempnam.c18
-rw-r--r--ports/unix/guts/tmpnam.c18
-rw-r--r--ports/unix/guts/truncate.c14
-rw-r--r--ports/unix/guts/umask.c14
-rw-r--r--ports/unix/guts/unlink.c14
-rw-r--r--ports/unix/guts/unlinkat.c61
-rw-r--r--ports/unix/guts/utime.c13
-rw-r--r--ports/unix/guts/utimes.c13
-rw-r--r--ports/unix/pseudo_wrappers.c50
-rw-r--r--ports/unix/wrapfuncs.in70
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);