aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.txt3
-rw-r--r--ports/common/guts/execv.c1
-rw-r--r--pseudo_client.c18
-rw-r--r--pseudo_client.h8
-rw-r--r--pseudo_util.c46
-rw-r--r--pseudo_wrappers.c18
6 files changed, 66 insertions, 28 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt
index 5d2e118..ede9969 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -1,3 +1,6 @@
+2016-03-09:
+ * (seebs) workaround for bash redefining getenv/unsetenv/etc.
+
2016-03-02:
* (seebs) more server launch rework and updates
* (seebs) make dup/dup2 less verbose in client
diff --git a/ports/common/guts/execv.c b/ports/common/guts/execv.c
index 6093e44..c071626 100644
--- a/ports/common/guts/execv.c
+++ b/ports/common/guts/execv.c
@@ -19,6 +19,7 @@
pseudo_setupenv();
if (pseudo_has_unload(NULL)) {
+ /* and here we attach */
pseudo_dropenv();
}
/* if exec() fails, we may end up taking signals unexpectedly...
diff --git a/pseudo_client.c b/pseudo_client.c
index 371a5b8..6a08df3 100644
--- a/pseudo_client.c
+++ b/pseudo_client.c
@@ -105,6 +105,9 @@ gid_t pseudo_egid;
gid_t pseudo_sgid;
gid_t pseudo_fgid;
+int (*pseudo_real_fork)(void) = fork;
+int (*pseudo_real_execv)(const char *, char * const *) = execv;
+
#define PSEUDO_ETC_FILE(filename, realname, flags) pseudo_etc_file(filename, realname, flags, passwd_paths, npasswd_paths)
/* helper function to make a directory, just like mkdir -p.
@@ -939,7 +942,7 @@ client_spawn_server(void) {
FILE *fp;
char * pseudo_pidfile;
- if ((server_pid = fork()) != 0) {
+ if ((server_pid = pseudo_real_fork()) != 0) {
if (server_pid == -1) {
pseudo_diag("couldn't fork server: %s\n", strerror(errno));
return 1;
@@ -1041,14 +1044,13 @@ client_spawn_server(void) {
*/
pseudo_client_logging = 0;
- /* execve will call setupenv, then call dropenv if
- * PSEUDO_UNLOAD is set. We call execve, not execv, due
- * to unsetenv changing the responses given by getenv,
- * but not changing the contents of the variable environ,
- * in some cases.
+ /* manual setup of environment, so we can call real-execv
+ * instead of the wrapper.
*/
- pseudo_set_value("PSEUDO_UNLOAD", "1");
- execve(argv[0], argv, environ);
+ pseudo_set_value("PSEUDO_UNLOAD", "YES");
+ pseudo_setupenv();
+ pseudo_dropenv();
+ pseudo_real_execv(argv[0], argv);
pseudo_diag("critical failure: exec of pseudo daemon failed: %s\n", strerror(errno));
exit(1);
}
diff --git a/pseudo_client.h b/pseudo_client.h
index e732bae..68e5160 100644
--- a/pseudo_client.h
+++ b/pseudo_client.h
@@ -58,6 +58,14 @@ extern int pseudo_pwd_lck_close(void);
extern FILE *pseudo_pwd;
extern FILE *pseudo_grp;
+/* pseudo_wrappers will try to initialize these */
+extern int (*pseudo_real_lstat)(const char *path, PSEUDO_STATBUF *buf);
+extern int (*pseudo_real_unsetenv)(const char *);
+extern char * (*pseudo_real_getenv)(const char *);
+extern int (*pseudo_real_setenv)(const char *, const char *, int);
+extern int (*pseudo_real_fork)(void);
+extern int (*pseudo_real_execv)(const char *, char * const *);
+
/* support related to chroot/getcwd/etc. */
extern int pseudo_client_getcwd(void);
extern int pseudo_client_chroot(const char *);
diff --git a/pseudo_util.c b/pseudo_util.c
index be07951..0c156cf 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -81,6 +81,16 @@ typedef struct {
char *data;
} pseudo_evlog_entry;
+/* so bash overrides getenv/unsetenv/etcetera, preventing them from
+ * actually modifying environ, so we have pseudo_wrappers try to dlsym
+ * the right values. This could fail, in which case we'd get null
+ * pointers, and we'll just call whatever the linker gives us and
+ * hope for the best.
+ */
+#define SETENV(x, y, z) (pseudo_real_setenv ? pseudo_real_setenv : setenv)(x, y, z)
+#define GETENV(x) (pseudo_real_getenv ? pseudo_real_getenv : getenv)(x)
+#define UNSETENV(x) (pseudo_real_unsetenv ? pseudo_real_unsetenv : unsetenv)(x)
+
#define PSEUDO_EVLOG_ENTRIES 250
#define PSEUDO_EVLOG_LENGTH 256
static pseudo_evlog_entry event_log[PSEUDO_EVLOG_ENTRIES];
@@ -102,6 +112,10 @@ static int pseudo_util_initted = -1; /* Not yet run */
/* bypass wrapper logic on path computations */
int (*pseudo_real_lstat)(const char *path, PSEUDO_STATBUF *buf) = NULL;
+/* bash workaround */
+int (*pseudo_real_unsetenv)(const char *) = unsetenv;
+char * (*pseudo_real_getenv)(const char *) = getenv;
+int (*pseudo_real_setenv)(const char *, const char *, int) = setenv;
#if 0
static void
@@ -126,7 +140,7 @@ pseudo_has_unload(char * const *envp) {
size_t i = 0;
/* Is it in the caller environment? */
- if (NULL != getenv(unload))
+ if (NULL != GETENV(unload))
return 1;
/* Is it in the environment cache? */
@@ -161,7 +175,7 @@ pseudo_get_value(const char *key) {
/* Check if the environment has it and we don't ...
* if so, something went wrong... so we'll attempt to recover
*/
- if (pseudo_env[i].key && !pseudo_env[i].value && getenv(pseudo_env[i].key))
+ if (pseudo_env[i].key && !pseudo_env[i].value && GETENV(pseudo_env[i].key))
pseudo_init_util();
if (pseudo_env[i].value)
@@ -215,8 +229,8 @@ pseudo_init_util(void) {
pseudo_util_initted = 1;
for (i = 0; pseudo_env[i].key; i++) {
- if (getenv(pseudo_env[i].key))
- pseudo_set_value(pseudo_env[i].key, getenv(pseudo_env[i].key));
+ if (GETENV(pseudo_env[i].key))
+ pseudo_set_value(pseudo_env[i].key, GETENV(pseudo_env[i].key));
}
pseudo_util_initted = 0;
@@ -820,7 +834,7 @@ pseudo_fix_path(const char *base, const char *path, size_t rootlen, size_t basel
* we don't try to fix the library path.
*/
void pseudo_dropenv() {
- char *ld_preload = getenv(PRELINK_LIBRARIES);
+ char *ld_preload = GETENV(PRELINK_LIBRARIES);
if (ld_preload) {
ld_preload = without_libpseudo(ld_preload);
@@ -828,9 +842,9 @@ void pseudo_dropenv() {
pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_LIBRARIES);
}
if (ld_preload && strlen(ld_preload)) {
- setenv(PRELINK_LIBRARIES, ld_preload, 1);
+ SETENV(PRELINK_LIBRARIES, ld_preload, 1);
} else {
- unsetenv(PRELINK_LIBRARIES);
+ UNSETENV(PRELINK_LIBRARIES);
}
}
}
@@ -886,14 +900,14 @@ pseudo_setupenv() {
while (pseudo_env[i].key) {
if (pseudo_env[i].value) {
- setenv(pseudo_env[i].key, pseudo_env[i].value, 0);
+ SETENV(pseudo_env[i].key, pseudo_env[i].value, 0);
pseudo_debug(PDBGF_ENV | PDBGF_VERBOSE, "pseudo_env: %s => %s\n",
pseudo_env[i].key, pseudo_env[i].value);
}
i++;
}
- const char *ld_library_path = getenv(PRELINK_PATH);
+ const char *ld_library_path = GETENV(PRELINK_PATH);
char *libdir_path = pseudo_libdir_path(NULL);
if (!ld_library_path) {
size_t len = strlen(libdir_path) + 1 + (strlen(libdir_path) + 2) + 1;
@@ -902,7 +916,7 @@ pseudo_setupenv() {
pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_PATH);
}
snprintf(newenv, len, "%s:%s64", libdir_path, libdir_path);
- setenv(PRELINK_PATH, newenv, 1);
+ SETENV(PRELINK_PATH, newenv, 1);
} else if (!strstr(ld_library_path, libdir_path)) {
size_t len = strlen(ld_library_path) + 1 + strlen(libdir_path) + 1 + (strlen(libdir_path) + 2) + 1;
char *newenv = malloc(len);
@@ -910,26 +924,26 @@ pseudo_setupenv() {
pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_PATH);
}
snprintf(newenv, len, "%s:%s:%s64", ld_library_path, libdir_path, libdir_path);
- setenv(PRELINK_PATH, newenv, 1);
+ SETENV(PRELINK_PATH, newenv, 1);
} else {
/* nothing to do, ld_library_path exists and contains
* our preferred path */
}
- char *ld_preload = getenv(PRELINK_LIBRARIES);
+ char *ld_preload = GETENV(PRELINK_LIBRARIES);
if (ld_preload) {
ld_preload = with_libpseudo(ld_preload, libdir_path);
if (!ld_preload) {
pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_LIBRARIES);
}
- setenv(PRELINK_LIBRARIES, ld_preload, 1);
+ SETENV(PRELINK_LIBRARIES, ld_preload, 1);
free(ld_preload);
} else {
ld_preload = with_libpseudo("", libdir_path);
if (!ld_preload) {
pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_LIBRARIES);
}
- setenv(PRELINK_LIBRARIES, ld_preload, 1);
+ SETENV(PRELINK_LIBRARIES, ld_preload, 1);
free(ld_preload);
}
@@ -940,9 +954,9 @@ pseudo_setupenv() {
#if PSEUDO_PORT_DARWIN
- char *force_flat = getenv("DYLD_FORCE_FLAT_NAMESPACE");
+ char *force_flat = GETENV("DYLD_FORCE_FLAT_NAMESPACE");
if (!force_flat) {
- setenv("DYLD_FORCE_FLAT_NAMESPACE", "1", 1);
+ SETENV("DYLD_FORCE_FLAT_NAMESPACE", "1", 1);
}
#endif
}
diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c
index 353a5a4..4a38bef 100644
--- a/pseudo_wrappers.c
+++ b/pseudo_wrappers.c
@@ -86,16 +86,15 @@ extern struct timeval *pseudo_wrapper_time;
#define PROFILE_DONE do {} while(0)
#endif
+/* later, the init code can change these to refer to the real calls and
+ * skip the wrappers.
+ */
#ifdef PSEUDO_XATTRDB
extern ssize_t (*pseudo_real_lgetxattr)(const char *, const char *, void *, size_t);
extern ssize_t (*pseudo_real_fgetxattr)(int, const char *, void *, size_t);
extern int (*pseudo_real_lsetxattr)(const char *, const char *, const void *, size_t, int);
extern int (*pseudo_real_fsetxattr)(int, const char *, const void *, size_t, int);
#endif
-/* later, the init code can change these to refer to the real calls and
- * skip the wrappers.
- */
-extern int (*pseudo_real_lstat)(const char *path, PSEUDO_STATBUF *buf);
static void
_libpseudo_init(void) {
@@ -178,6 +177,17 @@ pseudo_init_wrappers(void) {
pseudo_real_fsetxattr = real_fsetxattr;
#endif
pseudo_real_lstat = base_lstat;
+ /* bash has its own local copies of these which it uses
+ * instead of ours...
+ */
+ pseudo_real_unsetenv = dlsym(RTLD_NEXT, "unsetenv");
+ pseudo_real_getenv = dlsym(RTLD_NEXT, "getenv");
+ pseudo_real_setenv = dlsym(RTLD_NEXT, "setenv");
+ /* and these are used so the client's server spawn can bypass
+ * wrappers.
+ */
+ pseudo_real_fork = dlsym(RTLD_NEXT, "fork");
+ pseudo_real_execv = dlsym(RTLD_NEXT, "execv");
/* Once the wrappers are setup, we can now use open... so
* setup the logfile, if necessary...