aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Seebach <seebs@eee12.(none)>2010-03-24 19:29:36 -0500
committerPeter Seebach <seebs@eee12.(none)>2010-03-24 19:41:34 -0500
commit4b555b46b36ccd50a1130238e02a2e2d41b50366 (patch)
treee57959bf8c75dd3baf7c6cde38b20318d55cd328
parent32a8cbe898ad06272ad5252a6574bb55ad35e66c (diff)
downloadpseudo-4b555b46b36ccd50a1130238e02a2e2d41b50366.tar.gz
pseudo-4b555b46b36ccd50a1130238e02a2e2d41b50366.tar.bz2
pseudo-4b555b46b36ccd50a1130238e02a2e2d41b50366.zip
Prep for chroot handling:
* Improve makewrappers handling of function pointer arguments. * Regenerate wrappers when makewrappers is touched. * Move path resolution from pseudo_client_op into wrapper functions. * Eliminate dependency on PATH_MAX. * Related cleanup, such as tracking CWD better, and using the tracked value for getcwd().
-rw-r--r--ChangeLog.txt6
-rw-r--r--Makefile.in2
-rw-r--r--guts/__fxstat64.c2
-rw-r--r--guts/__fxstatat64.c2
-rw-r--r--guts/__xmknodat.c5
-rw-r--r--guts/chdir.c10
-rw-r--r--guts/close.c2
-rw-r--r--guts/dup.c2
-rw-r--r--guts/dup2.c4
-rw-r--r--guts/fchdir.c2
-rw-r--r--guts/fchmod.c2
-rw-r--r--guts/fchmodat.c4
-rw-r--r--guts/fchown.c4
-rw-r--r--guts/fchownat.c4
-rw-r--r--guts/fclose.c2
-rw-r--r--guts/fcntl.c2
-rw-r--r--guts/fopen.c6
-rw-r--r--guts/fopen64.c7
-rw-r--r--guts/freopen.c6
-rw-r--r--guts/get_current_dir_name.c15
-rw-r--r--guts/getcwd.c40
-rw-r--r--guts/getwd.c18
-rw-r--r--guts/lchown.c11
-rw-r--r--guts/link.c4
-rw-r--r--guts/mkdirat.c2
-rw-r--r--guts/mkstemp.c27
-rw-r--r--guts/openat.c6
-rw-r--r--guts/rename.c10
-rw-r--r--guts/rmdir.c2
-rw-r--r--guts/symlink.c4
-rw-r--r--guts/symlinkat.c13
-rw-r--r--guts/unlinkat.c11
-rwxr-xr-xmakewrappers111
-rw-r--r--pseudo.c8
-rw-r--r--pseudo.h2
-rw-r--r--pseudo_client.c130
-rw-r--r--pseudo_client.h9
-rw-r--r--pseudo_util.c82
-rw-r--r--wrapfuncs.in31
-rw-r--r--wrapfuncs64.in2
40 files changed, 455 insertions, 157 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt
index 9e26e5f..cc7083b 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -1,3 +1,9 @@
+2010-03-24:
+ * (seebs) regenerate wrappers when makewrappers is changed.
+ * (seebs) begin prep for chroot
+ * (seebs) standardize path expansion
+ * (seebs) extend makewrappers to handle function pointer args
+
2010-03-17:
* (seebs) fixup help options
* (seebs) use strerror() in a couple more places
diff --git a/Makefile.in b/Makefile.in
index 8852802..9f9e67e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -94,7 +94,7 @@ pseudo_server.o: pseudo_server.h
pseudo_wrappers.o: $(GUTS)
-wrappers: wrapfuncs.in $(USE_64)
+wrappers: wrapfuncs.in $(USE_64) makewrappers
./makewrappers wrapfuncs.in $(USE_64)
.SECONDARY: wrappers
diff --git a/guts/__fxstat64.c b/guts/__fxstat64.c
index 59f8a59..2e7919c 100644
--- a/guts/__fxstat64.c
+++ b/guts/__fxstat64.c
@@ -16,7 +16,7 @@
errno = save_errno;
return rc;
}
- msg = pseudo_client_op(OP_FSTAT, 0, fd, -1, 0, buf);
+ msg = pseudo_client_op(OP_FSTAT, fd, -1, 0, buf);
if (msg) {
if (msg->result == RESULT_SUCCEED)
pseudo_stat_msg(buf, msg);
diff --git a/guts/__fxstatat64.c b/guts/__fxstatat64.c
index 3edd8c7..b8054f2 100644
--- a/guts/__fxstatat64.c
+++ b/guts/__fxstatat64.c
@@ -56,7 +56,7 @@
* 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, flags, -1, dirfd, path, buf);
+ msg = pseudo_client_op(OP_STAT, -1, dirfd, path, buf);
if (msg) {
pseudo_stat_msg(buf, msg);
if (save_mode) {
diff --git a/guts/__xmknodat.c b/guts/__xmknodat.c
index a86d6aa..6bd0761 100644
--- a/guts/__xmknodat.c
+++ b/guts/__xmknodat.c
@@ -30,8 +30,9 @@
rc = real_openat(dirfd, path, O_CREAT | O_WRONLY | O_EXCL,
PSEUDO_FS_MODE(mode));
#endif
- if (rc == -1)
+ if (rc == -1) {
return -1;
+ }
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
@@ -43,7 +44,7 @@
buf.st_mode = (PSEUDO_DB_MODE(buf.st_mode, mode) & 07777) |
(mode & ~07777);
buf.st_rdev = *dev;
- msg = pseudo_client_op(OP_MKNOD, AT_SYMLINK_NOFOLLOW, -1, dirfd, path, &buf);
+ msg = pseudo_client_op(OP_MKNOD, -1, dirfd, path, &buf);
if (!msg) {
errno = ENOSYS;
rc = -1;
diff --git a/guts/chdir.c b/guts/chdir.c
index b910060..ca48738 100644
--- a/guts/chdir.c
+++ b/guts/chdir.c
@@ -3,11 +3,17 @@
* wrap_chdir(const char *path) {
* int rc = -1;
*/
- pseudo_debug(3, "chdir: %s\n", path ? path : "<nil>");
+ pseudo_debug(2, "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);
+ pseudo_client_op(OP_CHDIR, -1, -1, path, 0);
}
/* return rc;
diff --git a/guts/close.c b/guts/close.c
index 8edbee9..34b279e 100644
--- a/guts/close.c
+++ b/guts/close.c
@@ -6,7 +6,7 @@
/* 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);
+ pseudo_client_op(OP_CLOSE, fd, -1, 0, 0);
rc = real_close(fd);
/* return rc;
diff --git a/guts/dup.c b/guts/dup.c
index 941a5d9..51ba15f 100644
--- a/guts/dup.c
+++ b/guts/dup.c
@@ -8,7 +8,7 @@
rc = real_dup(fd);
save_errno = errno;
pseudo_debug(2, "dup: %d->%d\n", fd, rc);
- pseudo_client_op(OP_DUP, 0, fd, rc, 0, 0);
+ pseudo_client_op(OP_DUP, fd, rc, 0, 0);
errno = save_errno;
/* return rc;
diff --git a/guts/dup2.c b/guts/dup2.c
index 360c3ad..59d5293 100644
--- a/guts/dup2.c
+++ b/guts/dup2.c
@@ -8,10 +8,10 @@
/* close existing one first - this also causes the socket to the
* server to get moved around if someone tries to overwrite it. */
pseudo_debug(2, "dup2: %d->%d\n", oldfd, newfd);
- pseudo_client_op(OP_CLOSE, 0, newfd, -1, 0, 0);
+ pseudo_client_op(OP_CLOSE, newfd, -1, 0, 0);
rc = real_dup2(oldfd, newfd);
save_errno = errno;
- pseudo_client_op(OP_DUP, 0, oldfd, newfd, 0, 0);
+ pseudo_client_op(OP_DUP, oldfd, newfd, 0, 0);
errno = save_errno;
/* return rc;
diff --git a/guts/fchdir.c b/guts/fchdir.c
index 5289f4c..b255511 100644
--- a/guts/fchdir.c
+++ b/guts/fchdir.c
@@ -7,7 +7,7 @@
rc = real_fchdir(dirfd);
if (rc != -1) {
- pseudo_client_op(OP_CHDIR, 0, -1, dirfd, 0, 0);
+ pseudo_client_op(OP_CHDIR, -1, dirfd, 0, 0);
}
/* return rc;
diff --git a/guts/fchmod.c b/guts/fchmod.c
index df2f9e9..663a026 100644
--- a/guts/fchmod.c
+++ b/guts/fchmod.c
@@ -12,7 +12,7 @@
return -1;
}
buf.st_mode = (buf.st_mode & ~07777) | (mode & 07777);
- msg = pseudo_client_op(OP_FCHMOD, 0, fd, -1, 0, &buf);
+ msg = pseudo_client_op(OP_FCHMOD, fd, -1, 0, &buf);
real_fchmod(fd, PSEUDO_FS_MODE(mode));
if (!msg) {
errno = ENOSYS;
diff --git a/guts/fchmodat.c b/guts/fchmodat.c
index 36bd4d1..9804711 100644
--- a/guts/fchmodat.c
+++ b/guts/fchmodat.c
@@ -33,7 +33,7 @@
/* purely for debugging purposes: check whether file
* is already in database.
*/
- msg = pseudo_client_op(OP_STAT, flags, -1, -1, path, &buf);
+ msg = pseudo_client_op(OP_STAT, -1, -1, path, &buf);
if (!msg || msg->result != RESULT_SUCCEED) {
pseudo_debug(2, "chmodat to 0%o on %d/%s, ino %llu, new file.\n",
mode, dirfd, path, (unsigned long long) buf.st_ino);
@@ -54,7 +54,7 @@
*/
buf.st_mode = (buf.st_mode & ~07777) | (mode & 07777);
- msg = pseudo_client_op(OP_CHMOD, flags, -1, dirfd, path, &buf);
+ msg = pseudo_client_op(OP_CHMOD, -1, dirfd, path, &buf);
if (!msg) {
errno = ENOSYS;
rc = -1;
diff --git a/guts/fchown.c b/guts/fchown.c
index 4d420c8..53a34de 100644
--- a/guts/fchown.c
+++ b/guts/fchown.c
@@ -15,7 +15,7 @@
return -1;
}
if (owner == -1 || group == -1) {
- msg = pseudo_client_op(OP_STAT, 0, fd, -1, NULL, &buf);
+ msg = pseudo_client_op(OP_STAT, fd, -1, NULL, &buf);
/* copy in any existing values... */
if (msg) {
if (msg->result == RESULT_SUCCEED) {
@@ -38,7 +38,7 @@
}
pseudo_debug(2, "fchown, fd %d: %d:%d -> %d:%d\n",
fd, owner, group, buf.st_uid, buf.st_gid);
- msg = pseudo_client_op(OP_FCHOWN, 0, fd, -1, 0, &buf);
+ msg = pseudo_client_op(OP_FCHOWN, fd, -1, 0, &buf);
if (!msg) {
errno = ENOSYS;
rc = -1;
diff --git a/guts/fchownat.c b/guts/fchownat.c
index 8d24d3e..181fa6d 100644
--- a/guts/fchownat.c
+++ b/guts/fchownat.c
@@ -30,7 +30,7 @@
}
save_errno = errno;
- msg = pseudo_client_op(OP_STAT, flags, -1, -1, path, &buf);
+ msg = pseudo_client_op(OP_STAT, -1, -1, path, &buf);
/* copy in any existing values... */
if (msg) {
if (msg->result == RESULT_SUCCEED) {
@@ -48,7 +48,7 @@
if (group != -1) {
buf.st_gid = group;
}
- msg = pseudo_client_op(OP_CHOWN, flags, -1, dirfd, path, &buf);
+ msg = pseudo_client_op(OP_CHOWN, -1, dirfd, path, &buf);
if (!msg) {
errno = ENOSYS;
rc = -1;
diff --git a/guts/fclose.c b/guts/fclose.c
index e0c5681..bcf4ace 100644
--- a/guts/fclose.c
+++ b/guts/fclose.c
@@ -9,7 +9,7 @@
return -1;
}
int fd = fileno(fp);
- pseudo_client_op(OP_CLOSE, 0, fd, -1, 0, 0);
+ pseudo_client_op(OP_CLOSE, fd, -1, 0, 0);
rc = real_fclose(fp);
/* return rc;
diff --git a/guts/fcntl.c b/guts/fcntl.c
index d03d40c..ec7277d 100644
--- a/guts/fcntl.c
+++ b/guts/fcntl.c
@@ -22,7 +22,7 @@
save_errno = errno;
if (rc != -1) {
pseudo_debug(2, "fcntl_dup: %d->%d\n", fd, rc);
- pseudo_client_op(OP_DUP, 0, fd, rc, 0, 0);
+ pseudo_client_op(OP_DUP, fd, rc, 0, 0);
}
errno = save_errno;
break;
diff --git a/guts/fopen.c b/guts/fopen.c
index 2aae54c..6495d69 100644
--- a/guts/fopen.c
+++ b/guts/fopen.c
@@ -16,13 +16,13 @@
pseudo_debug(2, "fopen '%s': fd %d\n", path, fd);
if (real___fxstat64(_STAT_VER, fd, &buf) != -1) {
if (!existed) {
- pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf);
+ pseudo_client_op(OP_CREAT, -1, -1, path, &buf);
}
- pseudo_client_op(OP_OPEN, 0, fd, -1, path, &buf);
+ pseudo_client_op(OP_OPEN, fd, -1, path, &buf);
} else {
pseudo_debug(1, "fopen (fd %d) succeeded, but fstat failed (%s).\n",
fd, strerror(errno));
- pseudo_client_op(OP_OPEN, 0, fd, -1, path, 0);
+ pseudo_client_op(OP_OPEN, fd, -1, path, 0);
}
errno = save_errno;
}
diff --git a/guts/fopen64.c b/guts/fopen64.c
index 0b0ab58..c6de09c 100644
--- a/guts/fopen64.c
+++ b/guts/fopen64.c
@@ -5,6 +5,7 @@
*/
struct stat64 buf;
int save_errno;
+
int existed = (real___xstat64(_STAT_VER, path, &buf) != -1);
rc = real_fopen64(path, mode);
@@ -16,13 +17,13 @@
pseudo_debug(2, "fopen64 '%s': fd %d\n", path, fd);
if (real___fxstat64(_STAT_VER, fd, &buf) != -1) {
if (!existed) {
- pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf);
+ pseudo_client_op(OP_CREAT, -1, -1, path, &buf);
}
- pseudo_client_op(OP_OPEN, 0, fd, -1, path, &buf);
+ pseudo_client_op(OP_OPEN, fd, -1, path, &buf);
} else {
pseudo_debug(1, "fopen64 (fd %d) succeeded, but fstat failed (%s).\n",
fd, strerror(errno));
- pseudo_client_op(OP_OPEN, 0, fd, -1, path, 0);
+ pseudo_client_op(OP_OPEN, fd, -1, path, 0);
}
errno = save_errno;
}
diff --git a/guts/freopen.c b/guts/freopen.c
index 312bc0a..92c9d87 100644
--- a/guts/freopen.c
+++ b/guts/freopen.c
@@ -16,13 +16,13 @@
pseudo_debug(2, "freopen '%s': fd %d\n", path, fd);
if (real___fxstat64(_STAT_VER, fd, &buf) != -1) {
if (!existed) {
- pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf);
+ pseudo_client_op(OP_CREAT, -1, -1, path, &buf);
}
- pseudo_client_op(OP_OPEN, 0, fd, -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, 0, fd, -1, path, 0);
+ pseudo_client_op(OP_OPEN, fd, -1, path, 0);
}
errno = save_errno;
}
diff --git a/guts/get_current_dir_name.c b/guts/get_current_dir_name.c
new file mode 100644
index 0000000..671c5dc
--- /dev/null
+++ b/guts/get_current_dir_name.c
@@ -0,0 +1,15 @@
+/*
+ * static char *
+ * wrap_get_current_dir_name(void) {
+ * char * rc = NULL;
+ */
+
+ pseudo_debug(3, "get_current_dir_name (getcwd)\n");
+ /* this relies on a Linux extension, but we dutifully
+ * emulated that extension.
+ */
+ rc = wrap_getcwd(NULL, 0);
+
+/* return rc;
+ * }
+ */
diff --git a/guts/getcwd.c b/guts/getcwd.c
new file mode 100644
index 0000000..d8f4d36
--- /dev/null
+++ b/guts/getcwd.c
@@ -0,0 +1,40 @@
+/*
+ * static char *
+ * wrap_getcwd(char *buf, size_t size) {
+ * char * rc = NULL;
+ */
+ pseudo_debug(2, "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 one, something's very wrong... */
+ if (!size) {
+ size = pseudo_cwd_len;
+ }
+ if (size) {
+ buf = malloc(size);
+ } else {
+ pseudo_diag("can't figure out CWD: length %ld\n",
+ (unsigned long) pseudo_cwd_len);
+ }
+ if (!buf) {
+ pseudo_diag("couldn't allocate requested CWD buffer - need %ld byes\n",
+ (unsigned long) size);
+ errno = ENOMEM;
+ return NULL;
+ }
+ }
+ rc = buf;
+ memcpy(buf, pseudo_cwd, pseudo_cwd_len + 1);
+ if (!*buf) {
+ strcpy(buf, "/");
+ }
+
+/* return rc;
+ * }
+ */
diff --git a/guts/getwd.c b/guts/getwd.c
new file mode 100644
index 0000000..2bac467
--- /dev/null
+++ b/guts/getwd.c
@@ -0,0 +1,18 @@
+/*
+ * static char *
+ * wrap_getwd(char *buf) {
+ * char * rc = NULL;
+ */
+
+ pseudo_debug(3, "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/guts/lchown.c b/guts/lchown.c
index 6f7e53a..2d0aff2 100644
--- a/guts/lchown.c
+++ b/guts/lchown.c
@@ -4,14 +4,17 @@
*/
pseudo_msg_t *msg;
struct stat64 buf;
-
+ if (!path) {
+ errno = EFAULT;
+ return -1;
+ }
pseudo_debug(2, "lchown(%s, %d, %d)\n",
- path ? path : "<null>", owner, group);
+ path ? path : "<nil>", owner, group);
if (real___lxstat64(_STAT_VER, path, &buf) == -1) {
return -1;
}
if (owner == -1 || group == -1) {
- msg = pseudo_client_op(OP_STAT, AT_SYMLINK_NOFOLLOW, -1, -1, path, &buf);
+ msg = pseudo_client_op(OP_STAT, -1, -1, path, &buf);
/* copy in any existing values... */
if (msg) {
if (msg->result == RESULT_SUCCEED) {
@@ -32,7 +35,7 @@
if (group != -1) {
buf.st_gid = group;
}
- msg = pseudo_client_op(OP_CHOWN, AT_SYMLINK_NOFOLLOW, -1, -1, path, &buf);
+ msg = pseudo_client_op(OP_CHOWN, -1, -1, path, &buf);
if (!msg) {
errno = ENOSYS;
rc = -1;
diff --git a/guts/link.c b/guts/link.c
index 278edd7..a68a1c1 100644
--- a/guts/link.c
+++ b/guts/link.c
@@ -17,11 +17,11 @@
* there is one. OP_LINK is also used to insert unseen
* files, though, so it can't be implicit.
*/
- msg = pseudo_client_op(OP_STAT, 0, -1, -1, oldpath, &buf);
+ msg = pseudo_client_op(OP_STAT, -1, -1, oldpath, &buf);
if (msg) {
pseudo_stat_msg(&buf, msg);
}
- pseudo_client_op(OP_LINK, 0, -1, -1, newpath, &buf);
+ pseudo_client_op(OP_LINK, -1, -1, newpath, &buf);
}
/* return rc;
diff --git a/guts/mkdirat.c b/guts/mkdirat.c
index a5ae5d8..188e66b 100644
--- a/guts/mkdirat.c
+++ b/guts/mkdirat.c
@@ -22,7 +22,7 @@
stat_rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, AT_SYMLINK_NOFOLLOW);
#endif
if (stat_rc != -1) {
- pseudo_client_op(OP_MKDIR, AT_SYMLINK_NOFOLLOW, -1, dirfd, path, &buf);
+ pseudo_client_op(OP_MKDIR, -1, dirfd, path, &buf);
} else {
pseudo_debug(1, "mkdir of %s succeeded, but stat failed: %s\n",
path, strerror(errno));
diff --git a/guts/mkstemp.c b/guts/mkstemp.c
index b339b5c..a8f5915 100644
--- a/guts/mkstemp.c
+++ b/guts/mkstemp.c
@@ -5,21 +5,40 @@
*/
struct stat64 buf;
int save_errno;
+ size_t len;
+ char *tmp_template;
- rc = real_mkstemp(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 (real___fxstat64(_STAT_VER, rc, &buf) != -1) {
- pseudo_client_op(OP_CREAT, 0, -1, -1, template, &buf);
- pseudo_client_op(OP_OPEN, 0, rc, -1, template, &buf);
+ pseudo_client_op(OP_CREAT, -1, -1, tmp_template, &buf);
+ pseudo_client_op(OP_OPEN, rc, -1, tmp_template, &buf);
} else {
pseudo_debug(1, "mkstemp (fd %d) succeeded, but fstat failed (%s).\n",
rc, strerror(errno));
- pseudo_client_op(OP_OPEN, 0, rc, -1, template, 0);
+ pseudo_client_op(OP_OPEN, 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);
+ free(tmp_template);
/* return rc;
* }
*/
diff --git a/guts/openat.c b/guts/openat.c
index 9475aeb..801f1e3 100644
--- a/guts/openat.c
+++ b/guts/openat.c
@@ -48,13 +48,13 @@
if (stat_rc != -1) {
buf.st_mode = PSEUDO_DB_MODE(buf.st_mode, mode);
if (!existed) {
- pseudo_client_op(OP_CREAT, 0, -1, dirfd, path, &buf);
+ pseudo_client_op(OP_CREAT, -1, dirfd, path, &buf);
}
- pseudo_client_op(OP_OPEN, 0, rc, dirfd, path, &buf);
+ pseudo_client_op(OP_OPEN, rc, dirfd, path, &buf);
} else {
pseudo_debug(1, "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, 0, rc, dirfd, path, 0);
+ pseudo_client_op(OP_OPEN, rc, dirfd, path, 0);
}
errno = save_errno;
}
diff --git a/guts/rename.c b/guts/rename.c
index 9dd6d99..117eb78 100644
--- a/guts/rename.c
+++ b/guts/rename.c
@@ -8,7 +8,7 @@
int oldrc, newrc;
int save_errno;
- pseudo_debug(1, "rename: %s->%s\n",
+ pseudo_debug(2, "rename: %s->%s\n",
oldpath ? oldpath : "<nil>",
newpath ? newpath : "<nil>");
@@ -53,10 +53,10 @@
*/
/* newpath must be removed. */
- pseudo_client_op(OP_UNLINK, AT_SYMLINK_NOFOLLOW, -1, -1, newpath, &newbuf);
+ pseudo_client_op(OP_UNLINK, -1, -1, newpath, &newbuf);
/* fill in "correct" details from server */
- msg = pseudo_client_op(OP_STAT, AT_SYMLINK_NOFOLLOW, -1, -1, oldpath, &oldbuf);
+ msg = pseudo_client_op(OP_STAT, -1, -1, oldpath, &oldbuf);
if (msg && msg->result == RESULT_SUCCEED) {
pseudo_stat_msg(&oldbuf, msg);
pseudo_debug(1, "renaming %s, got old mode of 0%o\n", oldpath, (int) msg->mode);
@@ -67,9 +67,9 @@
*/
pseudo_debug(1, "renaming new '%s' [%llu]\n",
oldpath, (unsigned long long) oldbuf.st_ino);
- pseudo_client_op(OP_LINK, AT_SYMLINK_NOFOLLOW, -1, -1, oldpath, &oldbuf);
+ pseudo_client_op(OP_LINK, -1, -1, oldpath, &oldbuf);
}
- pseudo_client_op(OP_RENAME, AT_SYMLINK_NOFOLLOW, -1, -1, newpath, &oldbuf, oldpath);
+ pseudo_client_op(OP_RENAME, -1, -1, newpath, &oldbuf, oldpath);
errno = save_errno;
/* return rc;
diff --git a/guts/rmdir.c b/guts/rmdir.c
index 029e5a2..94de46a 100644
--- a/guts/rmdir.c
+++ b/guts/rmdir.c
@@ -13,7 +13,7 @@
rc = real_rmdir(path);
save_errno = errno;
if (rc != -1) {
- pseudo_client_op(OP_UNLINK, AT_SYMLINK_NOFOLLOW, -1, -1, path, &buf);
+ pseudo_client_op(OP_UNLINK, -1, -1, path, &buf);
}
errno = save_errno;
diff --git a/guts/symlink.c b/guts/symlink.c
index bc1c4be..324fef7 100644
--- a/guts/symlink.c
+++ b/guts/symlink.c
@@ -1,10 +1,10 @@
/*
* static int
- * wrap_symlink(const char *oldpath, const char *newpath) {
+ * wrap_symlink(const char *oldname, const char *newpath) {
* int rc = -1;
*/
- rc = wrap_symlinkat(oldpath, AT_FDCWD, newpath);
+ rc = wrap_symlinkat(oldname, AT_FDCWD, newpath);
/* return rc;
* }
diff --git a/guts/symlinkat.c b/guts/symlinkat.c
index 5f1cc59..df1df06 100644
--- a/guts/symlinkat.c
+++ b/guts/symlinkat.c
@@ -1,21 +1,23 @@
/*
* static int
- * wrap_symlinkat(const char *oldpath, int dirfd, const char *newpath) {
+ * wrap_symlinkat(const char *oldname, int dirfd, const char *newpath) {
* int rc = -1;
*/
struct stat64 buf;
+ char *roldname = 0;
#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
if (dirfd != AT_FDCWD) {
errno = ENOSYS;
return -1;
}
- rc = real_symlink(oldpath, newpath);
+ rc = real_symlink(roldname ? roldname : oldname, newpath);
#else
- rc = real_symlinkat(oldpath, dirfd, newpath);
+ rc = real_symlinkat(roldname ? roldname : oldname, dirfd, newpath);
#endif
if (rc == -1) {
+ free(roldname);
return rc;
}
#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
@@ -28,10 +30,13 @@
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, AT_SYMLINK_NOFOLLOW, -1, dirfd, newpath, &buf);
+ pseudo_client_op(OP_SYMLINK, -1, dirfd, newpath, &buf);
+
+ free(roldname);
/* return rc;
* }
diff --git a/guts/unlinkat.c b/guts/unlinkat.c
index cfa71e7..1c2868a 100644
--- a/guts/unlinkat.c
+++ b/guts/unlinkat.c
@@ -1,6 +1,6 @@
/*
* static int
- * wrap_unlinkat(int dirfd, const char *path, int flags) {
+ * wrap_unlinkat(int dirfd, const char *path, int rflags) {
* int rc = -1;
*/
#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
@@ -8,18 +8,17 @@
errno = ENOSYS;
return -1;
}
- if (flags) {
+ 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",
- flags, path ? path : "<nil>");
+ rflags, path ? path : "<nil>");
errno = ENOSYS;
return -1;
}
#endif
-
struct stat64 buf;
#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
@@ -33,10 +32,10 @@
#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
rc = real_unlink(path);
#else
- rc = real_unlinkat(dirfd, path, flags);
+ rc = real_unlinkat(dirfd, path, rflags);
#endif
if (rc != -1) {
- pseudo_client_op(OP_UNLINK, AT_SYMLINK_NOFOLLOW, -1, dirfd, path, &buf);
+ pseudo_client_op(OP_UNLINK, -1, dirfd, path, &buf);
}
/* return rc;
diff --git a/makewrappers b/makewrappers
index 11ef407..bc01e0d 100755
--- a/makewrappers
+++ b/makewrappers
@@ -51,6 +51,11 @@ cat >&5 <<EOF
#include <string.h>
#include <errno.h>
#include <pthread.h>
+#include <dirent.h>
+#include <fts.h>
+#include <ftw.h>
+#include <glob.h>
+#include <utime.h>
#include <sys/types.h>
#include <unistd.h>
@@ -140,26 +145,64 @@ do
\#*) continue;;
esac
# obtain return type, name, and arguments
- args=`expr "$signature" : '.*(\(.*\));'`
- return_and_name=`expr "$signature" : '\(.*\)('`
+ args=`expr "$signature" : '[^(]*(\(.*\));'`
+ modifiers=`expr "$signature" : '.*; /\* \(.*\) \*/'`
+ return_and_name=`expr "$signature" : '\([^(]*\)('`
name=`expr "$return_and_name" : '.*[^a-zA-Z0-9_]\([a-zA-Z0-9_]*\)$'`
type=`expr "$return_and_name" : '\(.*[^ ]\) *'"$name"'$'`
printf >&2 ' %s' "$name"
+ wrapargnames=''
argnames=''
+ # for handling path canonicalization
+ pathnames=''
+ flags='0'
+ dirfd='AT_FDCWD'
+
save_IFS=$IFS
IFS=,
set -- $args
- IFS=$save_ifs
+ IFS=$save_IFS
args=''
optional_arg=false
+ prepend=''
+ depth=0
for arg
do
- # strip whitespace
- arg=${arg# }
- arg=${arg% }
# handle optional arguments, like the third arg
# to open()
+ if [ $depth -gt 0 ]; then
+ case $arg in
+ *\)*)
+ lcount=`echo $arg | tr -cd '(' | wc -c`
+ rcount=`echo $arg | tr -cd ')' | wc -c`
+ depth=`expr $depth + $lcount - $rcount`
+ prepend="${prepend:+$prepend,}$arg"
+ arg=""
+ ;;
+ *) prepend="${prepend:+$prepend,}$arg"
+ arg=""
+ ;;
+ esac
+ else
+ case $arg in
+ *\(*) lcount=`echo $arg | tr -cd '(' | wc -c`
+ rcount=`echo $arg | tr -cd ')' | wc -c`
+ depth=`expr $depth + $lcount - $rcount`
+ prepend="${prepend:+$prepend,}$arg"
+ arg=""
+ ;;
+ esac
+ fi
+ # we're inside nested ()s
+ if [ $depth -gt 0 ]; then
+ continue
+ fi
+ arg="$prepend$arg"
+ # strip whitespace
+ arg=${arg# }
+ arg=${arg% }
+ prepend=''
case $arg in
...*)
optional_arg=true
@@ -167,6 +210,7 @@ do
arg=`expr "$arg" : '\.\.\.{\(.*\)}'`
argname=`expr "$arg" : '.*[^a-zA-Z0-9_]\([a-zA-Z0-9_]*\)$'`
argnames="$argnames${argnames:+, }$argname"
+ wrapargnames="$wrapargnames${wrapargnames:+, }$argname"
# we need this to extract and pass the argument
optional_decl=$arg
@@ -174,24 +218,61 @@ do
optional_name=$argname
optional_type=`expr "$arg" : '\(.*[^ ]\) *'"$argname"'$'`
;;
+ *\(*) # function pointer
+ argname=`expr "$arg" : '[^(]*(\*\([a-zA-Z0-9_]*\).*'`
+ args="$args${args:+, }$arg"
+ wrapargnames="$wrapargnames${wrapargnames:+, }$argname"
+ argnames="$argnames${argnames:+, }$argname"
+ prev_argname=$argname
+ ;;
*)
- argname=`expr "$arg" : '.*[^a-zA-Z0-9_]\([a-zA-Z0-9_]*\)$'`
+ argname=`expr "$arg" : '.*[^a-zA-Z0-9_](*\([a-zA-Z0-9_]*\))*(*)*$'`
args="$args${args:+, }$arg"
+ # special handling for canonicalization
+ # set this before changing path -> rpath, for guts files
+ wrapargnames="$wrapargnames${wrapargnames:+, }$argname"
+ case $argname in
+ *path) pathnames="${pathnames+${pathnames} }$argname"
+ argname="r$argname"
+ ;;
+ dirfd) dirfd='dirfd';;
+ flags) flags='flags';;
+ esac
argnames="$argnames${argnames:+, }$argname"
prev_argname=$argname
;;
esac
done
+ # see whether flags was overridden
+ flags_tmp=`expr "$modifiers" : 'flags=\([^ ]*\)'`
+ if [ -n "$flags_tmp" ]; then
+ flags=$flags_tmp
+ fi
+ decl_paths=''
+ alloc_paths=''
+ free_paths=''
+ # any argument ending in "path" is presumed to need to be
+ # converted to a chroot path. To avoid this, name the
+ # argument something else (e.g. "template" for mkstemp)
+ for p in $pathnames; do
+ decl_paths="${decl_paths}
+ char *r$p = (char *) $p;"
+ alloc_paths="${alloc_paths}
+ r$p = pseudo_root_path(__func__, __LINE__, $dirfd, $p, $flags);"
+ free_paths="${free_paths}
+ free(r$p);"
+ done
# determine default return value.
case $type in
- int)
+ int|ssize_t|long)
default_value=-1;;
uid_t|gid_t)
default_value=0;;
- 'FILE *')
+ 'FILE *' | 'char *' | 'DIR *' | 'FTS *')
default_value=NULL;;
- *) echo >&2 "Unknown type '$type'." ; exit 1 ;;
+ *) echo >&2 "
+Unknown type '$type'." ; exit 1 ;;
esac
# create the wrappers
# first the dummy, and the function pointer:
@@ -226,10 +307,12 @@ EOF
fi
# and now the body of the wrapper:
cat >&5 <<EOF
+ pseudo_debug(4, "called: $name\n");
if (pseudo_getlock()) {
errno = EBUSY;
return $default_value;
}
+ $decl_paths
if (pseudo_populate_wrappers()) {
$type rc = $default_value;
int save_errno;
@@ -240,14 +323,18 @@ EOF
rc = dummy_$name($argnames);
}
} else {
+$alloc_paths
rc = wrap_$name($argnames);
+$free_paths
}
save_errno = errno;
pseudo_droplock();
errno = save_errno;
+ pseudo_debug(4, "completed: $name\n");
return rc;
} else {
pseudo_droplock();
+ pseudo_debug(4, "completed: $name\n");
return dummy_$name($argnames);
}
}
@@ -302,7 +389,7 @@ EOF
* $type rc = $default_value;
*/
- rc = real_$name($argnames);
+ rc = real_$name($wrapargnames);
/* return rc;
* }
@@ -316,7 +403,7 @@ EOF
* $type rc = $default_value;
*/
- rc = real_$name($argnames);
+ rc = real_$name($wrapargnames);
/* return rc;
* }
diff --git a/pseudo.c b/pseudo.c
index 447f602..8352de2 100644
--- a/pseudo.c
+++ b/pseudo.c
@@ -64,9 +64,11 @@ main(int argc, char *argv[]) {
int lockfd, newfd;
char *ld_env = getenv("LD_PRELOAD");
int rc;
- char opts[PATH_MAX] = "", *optptr = opts;
+ char opts[pseudo_path_max()], *optptr = opts;
char *lockname;
+ opts[0] = '\0';
+
s = getenv("PSEUDO_DEBUG");
if (s) {
int level = atoi(s);
@@ -108,7 +110,7 @@ main(int argc, char *argv[]) {
usage(0);
break;
case 'l':
- optptr += snprintf(optptr, PATH_MAX - (optptr - opts),
+ optptr += snprintf(optptr, pseudo_path_max() - (optptr - opts),
"%s-l", optptr > opts ? " " : "");
opt_l = 1;
break;
@@ -124,7 +126,7 @@ main(int argc, char *argv[]) {
pseudo_diag("Timeout must be an integer value.\n");
usage(EXIT_FAILURE);
}
- optptr += snprintf(optptr, PATH_MAX - (optptr - opts),
+ optptr += snprintf(optptr, pseudo_path_max() - (optptr - opts),
"%s-t %d", optptr > opts ? " " : "",
pseudo_server_timeout);
break;
diff --git a/pseudo.h b/pseudo.h
index 560991f..57681fb 100644
--- a/pseudo.h
+++ b/pseudo.h
@@ -118,6 +118,8 @@ extern void pseudo_dropenv(void);
extern void pseudo_setupenv(char *);
extern char *pseudo_prefix_path(char *);
extern char *pseudo_get_prefix(char *);
+extern ssize_t pseudo_sys_path_max(void);
+extern ssize_t pseudo_path_max(void);
extern char *pseudo_version;
diff --git a/pseudo_client.c b/pseudo_client.c
index d957116..5ada209 100644
--- a/pseudo_client.c
+++ b/pseudo_client.c
@@ -37,14 +37,16 @@
#include "pseudo_ipc.h"
#include "pseudo_client.h"
+static char *base_path(int dirfd, const char *path, int leave_last);
+
static int connect_fd = -1;
static int server_pid = 0;
int pseudo_dir_fd = -1;
+char *pseudo_cwd = 0;
+size_t pseudo_cwd_len;
static char **fd_paths = 0;
static int nfds = 0;
-static char cwdbuf[PATH_MAX * 2], *cwd;
-static int cwdlen = 0;
static int messages = 0;
static struct timeval message_time = { 0 };
static int pseudo_inited = 0;
@@ -75,13 +77,52 @@ pseudo_client_touchgid(void) {
setenv("PSEUDO_GIDS", gidbuf, 1);
}
+char *
+pseudo_root_path(const char *func, int line, int dirfd, const char *path, int leave_last) {
+ char *rc;
+ pseudo_antimagic();
+ rc = base_path(dirfd, path, leave_last);
+ pseudo_magic();
+ if (!rc) {
+ pseudo_diag("couldn't allocate absolute path for '%s'.\n",
+ path);
+ }
+ pseudo_debug(3, "root_path [%s, %d]: '%s' from '%s'\n",
+ func, line,
+ rc ? rc : "<nil>",
+ path ? path : "<nil>");
+ return rc;
+}
+
+int
+pseudo_client_getcwd(void) {
+ char *cwd;
+ cwd = malloc(pseudo_path_max());
+ if (!cwd) {
+ pseudo_diag("Can't allocate CWD buffer!\n");
+ return -1;
+ }
+ pseudo_debug(2, "getcwd: trying to find cwd.\n");
+ if (getcwd(cwd, pseudo_path_max())) {
+ /* cwd now holds a canonical path to current directory */
+ pseudo_cwd_len = strlen(cwd);
+ pseudo_debug(3, "getcwd okay: [%s] %d bytes\n", cwd, (int) pseudo_cwd_len);
+ free(pseudo_cwd);
+ pseudo_cwd = cwd;
+ return 0;
+ } else {
+ pseudo_diag("Can't get CWD: %s\n", strerror(errno));
+ return -1;
+ }
+}
+
static char *
fd_path(int fd) {
if (fd >= 0 && fd < nfds) {
return fd_paths[fd];
}
if (fd == AT_FDCWD) {
- return cwd;
+ return pseudo_cwd;
}
return 0;
}
@@ -130,8 +171,7 @@ pseudo_client_reset() {
close(connect_fd);
connect_fd = -1;
}
- cwd = getcwd(cwdbuf, PATH_MAX);
- cwdlen = strlen(cwd);
+ pseudo_client_getcwd();
if (!pseudo_inited) {
char *env;
@@ -551,39 +591,42 @@ pseudo_client_shutdown(void) {
static char *
base_path(int dirfd, const char *path, int leave_last) {
char *basepath = 0;
- size_t pathlen = -1;
- size_t baselen;
+ size_t baselen = 0;
char *newpath;
- if (dirfd != -1 && dirfd != AT_FDCWD) {
- if (dirfd >= 0) {
- basepath = fd_path(dirfd);
- baselen = strlen(basepath);
+ if (path[0] != '/') {
+ if (dirfd != -1 && dirfd != AT_FDCWD) {
+ if (dirfd >= 0) {
+ basepath = fd_path(dirfd);
+ baselen = strlen(basepath);
+ } else {
+ pseudo_diag("got *at() syscall for unknown directory, fd %d\n", dirfd);
+ }
} else {
- pseudo_diag("got *at() syscall for unknown directory, fd %d\n", dirfd);
+ basepath = pseudo_cwd;
+ baselen = pseudo_cwd_len;
+ }
+ if (!basepath) {
+ pseudo_diag("unknown base path for fd %d, path %s\n", dirfd, path);
+ return 0;
}
- } else {
- basepath = cwd;
- baselen = cwdlen;
- }
- if (!basepath) {
- pseudo_diag("unknown base path for fd %d, path %s\n", dirfd, path);
- return 0;
}
- pathlen = baselen + strlen(path) + 2;
newpath = pseudo_fix_path(basepath, path, baselen, NULL, leave_last);
+ pseudo_debug(4, "base_path: %s</>%s\n",
+ basepath ? basepath : "<nil>",
+ path ? path : "<nil>");
return newpath;
}
pseudo_msg_t *
-pseudo_client_op(op_id_t op, int flags, int fd, int dirfd, const char *path, const struct stat64 *buf, ...) {
+pseudo_client_op(op_id_t op, int fd, int dirfd, const char *path, const struct stat64 *buf, ...) {
pseudo_msg_t *result = 0;
pseudo_msg_t msg = { .type = PSEUDO_MSG_OP };
- char *newpath = 0;
size_t pathlen = -1;
int do_request = 0;
char *oldpath = 0;
+ char *newpath = 0;
/* disable wrappers */
pseudo_antimagic();
@@ -606,43 +649,27 @@ pseudo_client_op(op_id_t op, int flags, int fd, int dirfd, const char *path, con
pseudo_magic();
return 0;
}
- if (oldpath[0] != '/') {
- oldpath = base_path(dirfd, oldpath, 1);
- } else {
- oldpath = pseudo_fix_path(NULL, oldpath, 0, NULL, 1);
- }
}
if (path) {
- /* fixup relative path */
- if (*path != '/') {
- newpath = base_path(dirfd, path, flags);
- } else {
- newpath = pseudo_fix_path(NULL, path, 0, NULL, flags);
- }
- if (newpath) {
- pathlen = strlen(newpath) + 1;
- } else {
- pseudo_diag("couldn't allocate space for a path (%s). Sorry.\n", path);
- free(oldpath);
- pseudo_magic();
- return 0;
- }
+ /* path fixup has to happen in the specific functions,
+ * because they may have to make calls which have to be
+ * fixed up for chroot stuff already.
+ */
+ pathlen = strlen(path) + 1;
if (oldpath) {
size_t full_len = strlen(oldpath) + 1 + pathlen;
char *both_paths = malloc(full_len);
if (!both_paths) {
pseudo_diag("can't allocate space for paths for a rename operation. Sorry.\n");
- free(newpath);
- free(oldpath);
pseudo_magic();
return 0;
}
snprintf(both_paths, full_len, "%s%c%s",
- newpath, 0, oldpath);
+ path, 0, oldpath);
pseudo_debug(2, "rename: %s -> %s [%d]\n",
both_paths + pathlen, both_paths, (int) full_len);
- free(newpath);
+ path = both_paths;
newpath = both_paths;
pathlen = full_len;
}
@@ -660,10 +687,9 @@ pseudo_client_op(op_id_t op, int flags, int fd, int dirfd, const char *path, con
(dirfd != -1 && dirfd != AT_FDCWD && op != OP_DUP) ? "at" : "");
if (oldpath) {
pseudo_debug(2, " %s ->", (char *) oldpath);
- free(oldpath);
}
- if (newpath || path) {
- pseudo_debug(2, " %s", newpath ? newpath : path);
+ if (path) {
+ pseudo_debug(2, " %s", path);
}
if (fd != -1) {
pseudo_debug(2, " [fd %d]", fd);
@@ -688,12 +714,11 @@ pseudo_client_op(op_id_t op, int flags, int fd, int dirfd, const char *path, con
pseudo_debug(4, "processing request [ino %llu]\n", (unsigned long long) msg.ino);
switch (msg.op) {
case OP_CHDIR:
- cwd = getcwd(cwdbuf, PATH_MAX);
- cwdlen = strlen(cwd);
+ pseudo_client_getcwd();
do_request = 0;
break;
case OP_OPEN:
- pseudo_client_path(fd, newpath ? newpath : path);
+ pseudo_client_path(fd, path);
do_request = 1;
break;
case OP_CLOSE:
@@ -752,7 +777,7 @@ pseudo_client_op(op_id_t op, int flags, int fd, int dirfd, const char *path, con
struct timeval tv1, tv2;
pseudo_debug(4, "sending request [ino %llu]\n", (unsigned long long) msg.ino);
gettimeofday(&tv1, NULL);
- result = pseudo_client_request(&msg, pathlen, newpath ? newpath : path);
+ result = pseudo_client_request(&msg, pathlen, path);
gettimeofday(&tv2, NULL);
++messages;
message_time.tv_sec += (tv2.tv_sec - tv1.tv_sec);
@@ -787,6 +812,7 @@ pseudo_client_op(op_id_t op, int flags, int fd, int dirfd, const char *path, con
}
pseudo_debug(2, "\n");
+ /* if not NULL, newpath is the buffer holding both paths */
free(newpath);
if (do_request && (messages % 1000 == 0)) {
diff --git a/pseudo_client.h b/pseudo_client.h
index b5a6075..a1e8d45 100644
--- a/pseudo_client.h
+++ b/pseudo_client.h
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-extern pseudo_msg_t *pseudo_client_op(op_id_t op, int flags, int fd, int dirfd, const char *path, const struct stat64 *buf, ...);
+extern pseudo_msg_t *pseudo_client_op(op_id_t op, int fd, int dirfd, const char *path, const struct stat64 *buf, ...);
extern void pseudo_antimagic(void);
extern void pseudo_magic(void);
extern void pseudo_client_reset(void);
@@ -41,6 +41,13 @@ extern int pseudo_rgid;
extern int pseudo_fgid;
extern int pseudo_dir_fd;
+/* support related to chroot/getcwd/etc. */
+extern int pseudo_client_getcwd(void);
+extern char *pseudo_root_path(const char *, int, int, const char *, int);
+#define PSEUDO_ROOT_PATH(x, y, z) pseudo_root_path(__func__, __LINE__, (x), (y), (z));
+extern char *pseudo_cwd;
+extern size_t pseudo_cwd_len;
+
/* Root can read, write, and execute files which have no read, write,
* or execute permissions.
*
diff --git a/pseudo_util.c b/pseudo_util.c
index 0a2c683..4bc2d5a 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -30,7 +30,9 @@
#include "pseudo_ipc.h"
#include "pseudo_db.h"
-/* 3 = detailed protocol analysis
+/* 5 = ridiculous levels of duplication
+ * 4 = exhaustive detail
+ * 3 = detailed protocol analysis
* 2 = higher-level protocol analysis
* 1 = stuff that might go wrong
* 0 = fire and arterial bleeding
@@ -43,6 +45,8 @@ static size_t pid_len;
static int pseudo_append_element(char **newpath, size_t *allocated, char **current, const char *element, size_t elen, int leave_last);
static int pseudo_append_elements(char **newpath, size_t *allocated, char **current, const char *elements, size_t elen, int leave_last);
extern char **environ;
+static ssize_t pseudo_max_pathlen = -1;
+static ssize_t pseudo_sys_max_pathlen = -1;
char *pseudo_version = PSEUDO_VERSION;
@@ -198,11 +202,11 @@ pseudo_append_element(char **pnewpath, size_t *pallocated, char **pcurrent, cons
is_link = 0;
}
if (is_link) {
- char linkbuf[PATH_MAX + 1];
+ char linkbuf[pseudo_path_max() + 1];
ssize_t linklen;
int retval;
- linklen = readlink(newpath, linkbuf, PATH_MAX);
+ linklen = readlink(newpath, linkbuf, pseudo_path_max());
if (linklen == -1) {
pseudo_diag("uh-oh! '%s' seems to be a symlink, but I can't read it. Ignoring.", newpath);
return 0;
@@ -459,29 +463,29 @@ pseudo_get_prefix(char *pathname) {
char *s;
s = getenv("PSEUDO_PREFIX");
if (!s) {
- char mypath[PATH_MAX];
+ char mypath[pseudo_path_max()];
char *dir;
char *tmp_path;
if (pathname[0] == '/') {
- snprintf(mypath, PATH_MAX, "%s", pathname);
+ snprintf(mypath, pseudo_path_max(), "%s", pathname);
s = mypath + strlen(mypath);
} else {
- if (!getcwd(mypath, PATH_MAX)) {
+ if (!getcwd(mypath, pseudo_path_max())) {
mypath[0] = '\0';
}
s = mypath + strlen(mypath);
- s += snprintf(s, PATH_MAX - (s - mypath), "/%s",
+ s += snprintf(s, pseudo_path_max() - (s - mypath), "/%s",
pathname);
}
- tmp_path = pseudo_fix_path(NULL, mypath, 0, 0, 0);
+ tmp_path = pseudo_fix_path(NULL, mypath, 0, 0, AT_SYMLINK_NOFOLLOW);
/* point s to the end of the fixed path */
- if (strlen(tmp_path) >= PATH_MAX) {
- pseudo_diag("Can't expand path '%s' -- expansion exceeds PATH_MAX.\n",
- mypath);
+ if (strlen(tmp_path) >= pseudo_path_max()) {
+ pseudo_diag("Can't expand path '%s' -- expansion exceeds %d.\n",
+ mypath, (int) pseudo_path_max());
free(tmp_path);
} else {
- s = mypath + snprintf(mypath, PATH_MAX, "%s", tmp_path);
+ s = mypath + snprintf(mypath, pseudo_path_max(), "%s", tmp_path);
free(tmp_path);
}
@@ -508,3 +512,57 @@ pseudo_get_prefix(char *pathname) {
}
return s;
}
+
+/* these functions define the sizes pseudo will try to use
+ * when trying to allocate space, or guess how much space
+ * other people will have allocated; see the GNU man page
+ * for realpath(3) for an explanation of why the sys_path_max
+ * functions exists, approximately -- it's there to be a size
+ * that I'm pretty sure the user will have allocated if they
+ * provided a buffer to that defective function.
+ */
+/* I'm pretty sure this will be larger than real PATH_MAX */
+#define REALLY_BIG_PATH 16384
+/* A likely common value for PATH_MAX */
+#define SORTA_BIG_PATH 4096
+ssize_t
+pseudo_path_max(void) {
+ if (pseudo_max_pathlen == -1) {
+ long l = pathconf("/", _PC_PATH_MAX);
+ if (l < 0) {
+ if (_POSIX_PATH_MAX > 0) {
+ pseudo_max_pathlen = _POSIX_PATH_MAX;
+ } else {
+ pseudo_max_pathlen = REALLY_BIG_PATH;
+ }
+ } else {
+ if (l <= REALLY_BIG_PATH) {
+ pseudo_max_pathlen = l;
+ } else {
+ pseudo_max_pathlen = REALLY_BIG_PATH;
+ }
+ }
+ }
+ return pseudo_max_pathlen;
+}
+
+ssize_t
+pseudo_sys_path_max(void) {
+ if (pseudo_sys_max_pathlen == -1) {
+ long l = pathconf("/", _PC_PATH_MAX);
+ if (l < 0) {
+ if (_POSIX_PATH_MAX > 0) {
+ pseudo_sys_max_pathlen = _POSIX_PATH_MAX;
+ } else {
+ pseudo_sys_max_pathlen = SORTA_BIG_PATH;
+ }
+ } else {
+ if (l <= SORTA_BIG_PATH) {
+ pseudo_sys_max_pathlen = l;
+ } else {
+ pseudo_sys_max_pathlen = SORTA_BIG_PATH;
+ }
+ }
+ }
+ return pseudo_sys_max_pathlen;
+}
diff --git a/wrapfuncs.in b/wrapfuncs.in
index e92de5e..5b262e7 100644
--- a/wrapfuncs.in
+++ b/wrapfuncs.in
@@ -1,44 +1,47 @@
int open(const char *path, int flags, ...{mode_t mode});
+char *getcwd(char *buf, size_t size);
+char *getwd(char *buf);
+char *get_current_dir_name(void);
int close(int fd);
-int link(const char *oldpath, const char *newpath);
-int rename(const char *oldpath, const char *newpath);
-int renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
-int unlink(const char *path);
-int unlinkat(int dirfd, const char *path, int flags);
+int link(const char *oldpath, const char *newpath); /* 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 unlink(const char *path); /* flags=AT_SYMLINK_NOFOLLOW */
+int unlinkat(int dirfd, const char *path, int rflags); /* flags=AT_SYMLINK_NOFOLLOW */
int creat(const char *path, mode_t mode);
int __xstat(int ver, const char *path, struct stat *buf);
-int __lxstat(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 chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
int chown(const char *path, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
-int lchown(const char *path, uid_t owner, gid_t group);
+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 fchownat(int dirfd, const char *path, uid_t owner, gid_t group, int flags);
int fchmodat(int dirfd, const char *path, mode_t mode, 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);
-int __xmknodat(int ver, int dirfd, const char *path, mode_t mode, dev_t *dev);
+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 dup2(int oldfd, int newfd);
int dup(int fd);
-int mkdir(const char *path, mode_t mode);
+int mkdir(const char *path, mode_t mode); /* flags=AT_SYMLINK_NOFOLLOW */
int mkdirat(int dirfd, const char *path, mode_t mode);
-int rmdir(const char *path);
+int rmdir(const char *path); /* flags=AT_SYMLINK_NOFOLLOW */
int chdir(const char *path);
int fchdir(int dirfd);
int fcntl(int fd, int cmd, ...{struct flock *lock});
int fork(void);
int vfork(void);
# just so we know the inums of symlinks
-int symlink(const char *oldpath, const char *newpath);
-int symlinkat(const char *oldpath, int dirfd, const char *newpath);
+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 */
# needed because glibc 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 mkstemp(char *template);
+int mkstemp(char *template); /* flags=AT_SYMLINK_NOFOLLOW */
# I bet you never knew there were this many of these!
int setfsuid(uid_t fsuid);
int setfsgid(gid_t fsgid);
diff --git a/wrapfuncs64.in b/wrapfuncs64.in
index 94c4744..8470c04 100644
--- a/wrapfuncs64.in
+++ b/wrapfuncs64.in
@@ -3,7 +3,7 @@ int openat64(int dirfd, const char *path, int flags, ...{mode_t mode});
int __openat64_2(int dirfd, const char *path, int flags);
int creat64(const char *path, mode_t mode);
int __xstat64(int ver, const char *path, struct stat64 *buf);
-int __lxstat64(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);