aboutsummaryrefslogtreecommitdiffstats
path: root/guts
diff options
context:
space:
mode:
Diffstat (limited to 'guts')
-rw-r--r--guts/README93
-rw-r--r--guts/access.c28
-rw-r--r--guts/acct.c11
-rw-r--r--guts/canonicalize_file_name.c11
-rw-r--r--guts/chroot.c16
-rw-r--r--guts/eaccess.c11
-rw-r--r--guts/euidaccess.c11
-rw-r--r--guts/freopen64.c32
-rw-r--r--guts/fts_open.c43
-rw-r--r--guts/ftw.c11
-rw-r--r--guts/ftw64.c11
-rw-r--r--guts/getcwd.c36
-rw-r--r--guts/glob.c11
-rw-r--r--guts/glob64.c11
-rw-r--r--guts/lutimes.c11
-rw-r--r--guts/mkdtemp.c42
-rw-r--r--guts/mkfifo.c11
-rw-r--r--guts/mkfifoat.c11
-rw-r--r--guts/mktemp.c32
-rw-r--r--guts/nftw.c11
-rw-r--r--guts/nftw64.c11
-rw-r--r--guts/opendir.c11
-rw-r--r--guts/pathconf.c11
-rw-r--r--guts/readlink.c11
-rw-r--r--guts/readlinkat.c25
-rw-r--r--guts/realpath.c27
-rw-r--r--guts/remove.c19
-rw-r--r--guts/scandir.c11
-rw-r--r--guts/scandir64.c11
-rw-r--r--guts/symlinkat.c6
-rw-r--r--guts/tempnam.c12
-rw-r--r--guts/tmpnam.c13
-rw-r--r--guts/truncate.c11
-rw-r--r--guts/truncate64.c11
-rw-r--r--guts/utime.c10
-rw-r--r--guts/utimes.c10
36 files changed, 636 insertions, 28 deletions
diff --git a/guts/README b/guts/README
index be00d30..277f712 100644
--- a/guts/README
+++ b/guts/README
@@ -28,26 +28,32 @@ some difference -- the structure they manipulate is not the same.
The following table shows which functions are merely wrappers around
other functions:
- chmod: fchmodat
- chown: fchownat
- creat64: openat
- creat: openat
- __fxstatat: __fxstatat64
- __fxstat: __fxstat64
- __lxstat64: __fxstatat64
- __lxstat: __fxstatat
- mkdir: mkdirat
- open64: openat
- __openat_2: openat
- __openat64_2: openat
- openat64: openat
- open: openat
- rename: renameat
- symlink: symlinkat
- unlink: unlinkat
- __xmknod: __xmknodat
- __xstat64: __fxstatat64
- __xstat: __fxstatat
+ canonicalize_file_name: realpath
+ chmod: fchmodat
+ chown: fchownat
+ creat64: openat
+ creat: openat
+ __fxstatat: __fxstatat64
+ __fxstat: __fxstat64
+ get_current_dir_name: getcwd
+ getwd: getcwd
+ __lxstat64: __fxstatat64
+ __lxstat: __fxstatat
+ mkdir: mkdirat
+ mkfifoat: __xmknodat
+ mkfifo: mkfifoat
+ open64: openat
+ __openat_2: openat
+ __openat64_2: openat
+ openat64: openat
+ open: openat
+ remove: unlink or rmdir
+ rename: renameat
+ symlink: symlinkat
+ unlink: unlinkat
+ __xmknod: __xmknodat
+ __xstat64: __fxstatat64
+ __xstat: __fxstatat
The following functions are full implementations:
@@ -59,10 +65,10 @@ The following functions are full implementations:
fchownat
__fxstat64
__fxstatat64
+ getcwd
lchown
mkdirat
openat
- renameat
rmdir
symlinkat
unlinkat
@@ -71,7 +77,7 @@ The following functions are full implementations:
The following functions provide only partial implementations, to trap special
cases, to track internal data structures (for instance, close() is tracked so
that the path to a file descriptor can be dropped when the file descriptor
-is closed), or to handle functions which may not use the underlying syscall
+is closed), or to handle functions which may not use the underlying syscall
wrappers:
close
@@ -81,6 +87,7 @@ wrappers:
fopen
fopen64
freopen
+ freopen64
mkstemp
fcntl
fork
@@ -107,3 +114,45 @@ but are used to simulate the permissions system:
getresuid
setfsuid
setresuid
+
+The following functions are present only to allow filename mangling
+for chroot(2) implementation. Most of them have no logic beyond
+calling the underlying routine.
+
+ access
+ acct
+ chroot
+ eaccess
+ euidaccess
+ fts_open
+ ftw64
+ ftw
+ glob64
+ glob
+ lutimes
+ mkdtemp
+ mktemp
+ nftw64
+ nftw
+ opendir
+ pathconf
+ readlinkat
+ readlink
+ realpath
+ scandir64
+ scandir
+ truncate64
+ truncate
+ utime
+ utimes
+
+The following functions are unimplemented. renameat could be done now (it
+would have been hard previously due to file name mangling issues), but
+since it's never come up, we haven't done it. The tempnam() functions are
+fairly hard to get right, and perhaps more imporantly, extremely
+dangerous. Since there's no evidence that they're in use anymore, I've
+dummied them out:
+
+ renameat
+ tempnam
+ tmpnam
diff --git a/guts/access.c b/guts/access.c
new file mode 100644
index 0000000..761ae66
--- /dev/null
+++ b/guts/access.c
@@ -0,0 +1,28 @@
+/*
+ * static int
+ * wrap_access(const char *path, int mode) {
+ * int rc = -1;
+ */
+ struct stat64 buf;
+
+ /* note: no attempt to handle the case where user isn't
+ * root.
+ */
+ rc = wrap___fxstatat64(_STAT_VER, AT_FDCWD, path, &buf, 0);
+ 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/guts/acct.c b/guts/acct.c
new file mode 100644
index 0000000..422aa9f
--- /dev/null
+++ b/guts/acct.c
@@ -0,0 +1,11 @@
+/*
+ * static int
+ * wrap_acct(const char *path) {
+ * int rc = -1;
+ */
+
+ rc = real_acct(path);
+
+/* return rc;
+ * }
+ */
diff --git a/guts/canonicalize_file_name.c b/guts/canonicalize_file_name.c
new file mode 100644
index 0000000..198f5fb
--- /dev/null
+++ b/guts/canonicalize_file_name.c
@@ -0,0 +1,11 @@
+/*
+ * static char *
+ * wrap_canonicalize_file_name(const char *filename) {
+ * char * rc = NULL;
+ */
+
+ rc = wrap_realpath(filename, NULL);
+
+/* return rc;
+ * }
+ */
diff --git a/guts/chroot.c b/guts/chroot.c
new file mode 100644
index 0000000..5f68482
--- /dev/null
+++ b/guts/chroot.c
@@ -0,0 +1,16 @@
+/*
+ * static int
+ * wrap_chroot(const char *path) {
+ * int rc = -1;
+ */
+ pseudo_debug(2, "chroot: %s\n", path);
+ if (!pseudo_client_op(OP_CHROOT, -1, -1, path, 0)) {
+ pseudo_debug(1, "chroot failed: %s\n", strerror(errno));
+ rc = -1;
+ } else {
+ rc = 0;
+ }
+
+/* return rc;
+ * }
+ */
diff --git a/guts/eaccess.c b/guts/eaccess.c
new file mode 100644
index 0000000..6c9d2cc
--- /dev/null
+++ b/guts/eaccess.c
@@ -0,0 +1,11 @@
+/*
+ * static int
+ * wrap_eaccess(const char *path, int mode) {
+ * int rc = -1;
+ */
+
+ rc = wrap_access(path, mode);
+
+/* return rc;
+ * }
+ */
diff --git a/guts/euidaccess.c b/guts/euidaccess.c
new file mode 100644
index 0000000..c69a7f1
--- /dev/null
+++ b/guts/euidaccess.c
@@ -0,0 +1,11 @@
+/*
+ * static int
+ * wrap_euidaccess(const char *path, int mode) {
+ * int rc = -1;
+ */
+
+ rc = wrap_access(path, mode);
+
+/* return rc;
+ * }
+ */
diff --git a/guts/freopen64.c b/guts/freopen64.c
new file mode 100644
index 0000000..1f83b07
--- /dev/null
+++ b/guts/freopen64.c
@@ -0,0 +1,32 @@
+/*
+ * 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(2, "freopen64 '%s': fd %d\n", path, fd);
+ if (real___fxstat64(_STAT_VER, fd, &buf) != -1) {
+ if (!existed) {
+ pseudo_client_op(OP_CREAT, -1, -1, path, &buf);
+ }
+ pseudo_client_op(OP_OPEN, fd, -1, path, &buf);
+ } else {
+ pseudo_debug(1, "fopen (fd %d) succeeded, but stat failed (%s).\n",
+ fd, strerror(errno));
+ pseudo_client_op(OP_OPEN, fd, -1, path, 0);
+ }
+ errno = save_errno;
+ }
+
+/* return rc;
+ * }
+ */
diff --git a/guts/fts_open.c b/guts/fts_open.c
new file mode 100644
index 0000000..d244861
--- /dev/null
+++ b/guts/fts_open.c
@@ -0,0 +1,43 @@
+/*
+ * static FTS *
+ * wrap_fts_open(char * const *path_argv, int options, int (*compar)(const FTSENT **, const FTSENT **)) {
+ * FTS * rc = NULL;
+ */
+ char **rpath_argv;
+ size_t 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;
+ }
+
+ 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/guts/ftw.c b/guts/ftw.c
new file mode 100644
index 0000000..7b298dd
--- /dev/null
+++ b/guts/ftw.c
@@ -0,0 +1,11 @@
+/*
+ * 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/guts/ftw64.c b/guts/ftw64.c
new file mode 100644
index 0000000..10bcdaf
--- /dev/null
+++ b/guts/ftw64.c
@@ -0,0 +1,11 @@
+/*
+ * 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/guts/getcwd.c b/guts/getcwd.c
index d8f4d36..f6a8521 100644
--- a/guts/getcwd.c
+++ b/guts/getcwd.c
@@ -3,7 +3,7 @@
* wrap_getcwd(char *buf, size_t size) {
* char * rc = NULL;
*/
- pseudo_debug(2, "wrap_getcwd: %p, %lu\n",
+ pseudo_debug(3, "wrap_getcwd: %p, %lu\n",
(void *) buf, (unsigned long) size);
if (!pseudo_cwd) {
pseudo_diag("Asked for CWD, but don't have it!\n");
@@ -12,15 +12,26 @@
}
/* emulate Linux semantics in case of non-Linux systems. */
if (!buf) {
- /* if we don't have one, something's very wrong... */
+ /* if we don't have a cwd, something's very wrong... */
if (!size) {
- size = pseudo_cwd_len;
+ 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\n",
- (unsigned long) pseudo_cwd_len);
+ 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",
@@ -29,8 +40,21 @@
return NULL;
}
}
+ if (pseudo_cwd_len - (pseudo_cwd_rel - pseudo_cwd) >= size) {
+ pseudo_diag("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 = ENAMETOOLONG;
+ return NULL;
+ }
rc = buf;
- memcpy(buf, pseudo_cwd, pseudo_cwd_len + 1);
+ pseudo_debug(3, "getcwd: copying %d (%d + 1 - %d) characters from <%s>.\n",
+ (int) ((pseudo_cwd_len + 1) - pseudo_chroot_len),
+ pseudo_cwd_len, pseudo_chroot_len,
+ pseudo_cwd_rel);
+ memcpy(buf, pseudo_cwd_rel, (pseudo_cwd_len + 1) - (pseudo_cwd_rel - pseudo_cwd));
if (!*buf) {
strcpy(buf, "/");
}
diff --git a/guts/glob.c b/guts/glob.c
new file mode 100644
index 0000000..7a12dbe
--- /dev/null
+++ b/guts/glob.c
@@ -0,0 +1,11 @@
+/*
+ * static int
+ * wrap_glob(const char *pattern, int flags, int (*errfunc)(const char *, int), glob_t *pglob) {
+ * int rc = -1;
+ */
+
+ rc = real_glob(pattern, flags, errfunc, pglob);
+
+/* return rc;
+ * }
+ */
diff --git a/guts/glob64.c b/guts/glob64.c
new file mode 100644
index 0000000..80571b0
--- /dev/null
+++ b/guts/glob64.c
@@ -0,0 +1,11 @@
+/*
+ * static int
+ * wrap_glob64(const char *pattern, int flags, int (*errfunc)(const char *, int), glob64_t *pglob) {
+ * int rc = -1;
+ */
+
+ rc = real_glob64(pattern, flags, errfunc, pglob);
+
+/* return rc;
+ * }
+ */
diff --git a/guts/lutimes.c b/guts/lutimes.c
new file mode 100644
index 0000000..fcbf363
--- /dev/null
+++ b/guts/lutimes.c
@@ -0,0 +1,11 @@
+/*
+ * static int
+ * wrap_lutimes(const char *path, const struct timeval *tv) {
+ * int rc = -1;
+ */
+
+ rc = real_lutimes(path, tv);
+
+/* return rc;
+ * }
+ */
diff --git a/guts/mkdtemp.c b/guts/mkdtemp.c
new file mode 100644
index 0000000..32fe4ef
--- /dev/null
+++ b/guts/mkdtemp.c
@@ -0,0 +1,42 @@
+/*
+ * static char *
+ * wrap_mkdtemp(char *template) {
+ * char * rc = NULL;
+ */
+ struct stat64 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 (real___xstat64(_STAT_VER, rc, &buf) != -1) {
+ pseudo_client_op(OP_CREAT, -1, -1, tmp_template, &buf);
+ } else {
+ pseudo_debug(1, "mkstemp (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);
+ free(tmp_template);
+/* return rc;
+ * }
+ */
diff --git a/guts/mkfifo.c b/guts/mkfifo.c
new file mode 100644
index 0000000..1a8b54e
--- /dev/null
+++ b/guts/mkfifo.c
@@ -0,0 +1,11 @@
+/*
+ * 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/guts/mkfifoat.c b/guts/mkfifoat.c
new file mode 100644
index 0000000..c52ac21
--- /dev/null
+++ b/guts/mkfifoat.c
@@ -0,0 +1,11 @@
+/*
+ * static int
+ * wrap_mkfifoat(int dirfd, const char *path, mode_t mode) {
+ * int rc = -1;
+ */
+
+ rc = wrap___xmknodat(_STAT_VER, dirfd, path, (mode & 07777) | S_IFIFO, 0);
+
+/* return rc;
+ * }
+ */
diff --git a/guts/mktemp.c b/guts/mktemp.c
new file mode 100644
index 0000000..e59cb28
--- /dev/null
+++ b/guts/mktemp.c
@@ -0,0 +1,32 @@
+/*
+ * 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);
+ free(tmp_template);
+
+/* return rc;
+ * }
+ */
diff --git a/guts/nftw.c b/guts/nftw.c
new file mode 100644
index 0000000..8d535b7
--- /dev/null
+++ b/guts/nftw.c
@@ -0,0 +1,11 @@
+/*
+ * 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/guts/nftw64.c b/guts/nftw64.c
new file mode 100644
index 0000000..e0471f0
--- /dev/null
+++ b/guts/nftw64.c
@@ -0,0 +1,11 @@
+/*
+ * 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/guts/opendir.c b/guts/opendir.c
new file mode 100644
index 0000000..19efa84
--- /dev/null
+++ b/guts/opendir.c
@@ -0,0 +1,11 @@
+/*
+ * static DIR *
+ * wrap_opendir(const char *path) {
+ * DIR * rc = NULL;
+ */
+
+ rc = real_opendir(path);
+
+/* return rc;
+ * }
+ */
diff --git a/guts/pathconf.c b/guts/pathconf.c
new file mode 100644
index 0000000..2a59eab
--- /dev/null
+++ b/guts/pathconf.c
@@ -0,0 +1,11 @@
+/*
+ * static long
+ * wrap_pathconf(const char *path, int name) {
+ * long rc = -1;
+ */
+
+ rc = real_pathconf(path, name);
+
+/* return rc;
+ * }
+ */
diff --git a/guts/readlink.c b/guts/readlink.c
new file mode 100644
index 0000000..98931c6
--- /dev/null
+++ b/guts/readlink.c
@@ -0,0 +1,11 @@
+/*
+ * 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/guts/readlinkat.c b/guts/readlinkat.c
new file mode 100644
index 0000000..13eeeb2
--- /dev/null
+++ b/guts/readlinkat.c
@@ -0,0 +1,25 @@
+/*
+ * static ssize_t
+ * wrap_readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) {
+ * ssize_t rc = -1;
+ */
+ rc = real_readlinkat(dirfd, path, buf, bufsiz);
+
+ if (rc > 0) {
+ /* strip out a leading chrooted part */
+ if (pseudo_chroot_len &&
+ !memcmp(buf, pseudo_chroot, pseudo_chroot_len)) {
+ if (buf[pseudo_chroot_len] == '/') {
+ memmove(buf, buf + pseudo_chroot_len, rc - pseudo_chroot_len);
+ rc -= pseudo_chroot_len;
+ } else if (buf[pseudo_chroot_len] == '\0') {
+ buf[0] = '/';
+ rc = 1;
+ }
+ /* otherwise, it's not really a match... */
+ }
+ }
+
+/* return rc;
+ * }
+ */
diff --git a/guts/realpath.c b/guts/realpath.c
new file mode 100644
index 0000000..5b1a5f8
--- /dev/null
+++ b/guts/realpath.c
@@ -0,0 +1,27 @@
+/*
+ * static char *
+ * wrap_realpath(const char *name, char *resolved_name) {
+ * char * rc = NULL;
+ */
+ char *rname = PSEUDO_ROOT_PATH(AT_FDCWD, name, 0);
+ size_t len;
+ if (!rname) {
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+ if ((len = strlen(rname)) >= pseudo_sys_path_max()) {
+ free(rname);
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+ if (resolved_name) {
+ memcpy(resolved_name, rname, len + 1);
+ free(rname);
+ rc = resolved_name;
+ } else {
+ rc = rname;
+ }
+
+/* return rc;
+ * }
+ */
diff --git a/guts/remove.c b/guts/remove.c
new file mode 100644
index 0000000..da6ecc3
--- /dev/null
+++ b/guts/remove.c
@@ -0,0 +1,19 @@
+/*
+ * static int
+ * wrap_remove(const char *path) {
+ * int rc = -1;
+ */
+ struct stat buf;
+ if (real___lxstat(_STAT_VER, 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/guts/scandir.c b/guts/scandir.c
new file mode 100644
index 0000000..d44d60e
--- /dev/null
+++ b/guts/scandir.c
@@ -0,0 +1,11 @@
+/*
+ * 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/guts/scandir64.c b/guts/scandir64.c
new file mode 100644
index 0000000..9a7f0d8
--- /dev/null
+++ b/guts/scandir64.c
@@ -0,0 +1,11 @@
+/*
+ * 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/guts/symlinkat.c b/guts/symlinkat.c
index df1df06..577b1e7 100644
--- a/guts/symlinkat.c
+++ b/guts/symlinkat.c
@@ -6,6 +6,12 @@
struct stat64 buf;
char *roldname = 0;
+ if (oldname[0] == '/' && pseudo_chroot_len) {
+ 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;
diff --git a/guts/tempnam.c b/guts/tempnam.c
new file mode 100644
index 0000000..4da3c83
--- /dev/null
+++ b/guts/tempnam.c
@@ -0,0 +1,12 @@
+/*
+ * static char *
+ * wrap_tempnam(const char *template, const char *pfx) {
+ * char * rc = NULL;
+ */
+ pseudo_diag("tempnam() is so ludicrously insecure as to defy implementation.");
+ errno = ENOMEM;
+ rc = 0;
+
+/* return rc;
+ * }
+ */
diff --git a/guts/tmpnam.c b/guts/tmpnam.c
new file mode 100644
index 0000000..3e1aab2
--- /dev/null
+++ b/guts/tmpnam.c
@@ -0,0 +1,13 @@
+/*
+ * static char *
+ * wrap_tmpnam(char *s) {
+ * char * rc = NULL;
+ */
+
+ pseudo_diag("tmpnam() is so ludicrously insecure as to defy implementation.");
+ errno = ENOMEM;
+ rc = 0;
+
+/* return rc;
+ * }
+ */
diff --git a/guts/truncate.c b/guts/truncate.c
new file mode 100644
index 0000000..b82c578
--- /dev/null
+++ b/guts/truncate.c
@@ -0,0 +1,11 @@
+/*
+ * static int
+ * wrap_truncate(const char *path, off_t length) {
+ * int rc = -1;
+ */
+
+ rc = real_truncate(path, length);
+
+/* return rc;
+ * }
+ */
diff --git a/guts/truncate64.c b/guts/truncate64.c
new file mode 100644
index 0000000..e79b15a
--- /dev/null
+++ b/guts/truncate64.c
@@ -0,0 +1,11 @@
+/*
+ * static int
+ * wrap_truncate64(const char *path, off64_t length) {
+ * int rc = -1;
+ */
+
+ rc = real_truncate64(path, length);
+
+/* return rc;
+ * }
+ */
diff --git a/guts/utime.c b/guts/utime.c
new file mode 100644
index 0000000..78a01b6
--- /dev/null
+++ b/guts/utime.c
@@ -0,0 +1,10 @@
+/*
+ * static int
+ * wrap_utime(const char *path, const struct utimbuf *buf) {
+ * int rc = -1;
+ */
+ rc = real_utime(path, buf);
+
+/* return rc;
+ * }
+ */
diff --git a/guts/utimes.c b/guts/utimes.c
new file mode 100644
index 0000000..0ca14d4
--- /dev/null
+++ b/guts/utimes.c
@@ -0,0 +1,10 @@
+/*
+ * static int
+ * wrap_utimes(const char *path, const struct timeval *times) {
+ * int rc = -1;
+ */
+ rc = real_utimes(path, times);
+
+/* return rc;
+ * }
+ */