Exemple #1
0
int
execvp(const char *file, char *const *argv) {
	sigset_t saved;
	
	int rc = -1;

	if (!pseudo_check_wrappers() || !real_execvp) {
		/* rc was initialized to the "failure" value */
		pseudo_enosys("execvp");
		return rc;
	}

	pseudo_debug(4, "called: execvp\n");
	pseudo_sigblock(&saved);
	if (pseudo_getlock()) {
		errno = EBUSY;
		sigprocmask(SIG_SETMASK, &saved, NULL);
		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(4, "completed: execvp\n");
	errno = save_errno;
	return rc;
}
Exemple #2
0
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(4, "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(4, "completed: fork\n");
	errno = save_errno;
	return rc;
}
Exemple #3
0
static void
pseudo_client_path(int fd, const char *path) {
	if (fd < 0)
		return;

	if (fd >= nfds) {
		int i;
		pseudo_debug(2, "expanding fds from %d to %d\n",
			nfds, fd + 1);
		fd_paths = realloc(fd_paths, (fd + 1) * sizeof(char *));
		for (i = nfds; i < fd + 1; ++i)
			fd_paths[i] = 0;
		nfds = fd + 1;
	} else {
		if (fd_paths[fd]) {
			pseudo_debug(2, "reopening fd %d [%s] -- didn't see close\n",
				fd, fd_paths[fd]);
		}
		/* yes, it is safe to free null pointers. yay for C89 */
		free(fd_paths[fd]);
		fd_paths[fd] = 0;
	}
	if (path) {
		fd_paths[fd] = strdup(path);
	}
}
Exemple #4
0
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(3, "getcwd: trying to find cwd.\n");
	if (getcwd(cwd, pseudo_path_max())) {
		/* cwd now holds a canonical path to current directory */
		free(pseudo_cwd);
		pseudo_cwd = cwd;
		pseudo_cwd_len = strlen(pseudo_cwd);
		pseudo_debug(3, "getcwd okay: [%s] %d bytes\n", pseudo_cwd, (int) pseudo_cwd_len);
		if (pseudo_chroot_len &&
			pseudo_cwd_len >= pseudo_chroot_len &&
			!memcmp(pseudo_cwd, pseudo_chroot, pseudo_chroot_len) &&
			(pseudo_cwd[pseudo_chroot_len] == '\0' ||
			pseudo_cwd[pseudo_chroot_len] == '/')) {
			pseudo_cwd_rel = pseudo_cwd + pseudo_chroot_len;
		} else {
			pseudo_cwd_rel = pseudo_cwd;
		}
		pseudo_debug(4, "abscwd: <%s>\n", pseudo_cwd);
		if (pseudo_cwd_rel != pseudo_cwd) {
			pseudo_debug(4, "relcwd: <%s>\n", pseudo_cwd_rel);
		}
		return 0;
	} else {
		pseudo_diag("Can't get CWD: %s\n", strerror(errno));
		return -1;
	}
}
Exemple #5
0
static int
client_connect(void) {
	/* we have a server pid, is it responsive? */
	struct sockaddr_un sun = { .sun_family = AF_UNIX, .sun_path = PSEUDO_SOCKET };
	int cwd_fd;

#if PSEUDO_PORT_DARWIN
	sun.sun_len = strlen(PSEUDO_SOCKET) + 1;
#endif

	connect_fd = socket(PF_UNIX, SOCK_STREAM, 0);
	connect_fd = pseudo_fd(connect_fd, MOVE_FD);
	if (connect_fd == -1) {
		pseudo_diag("can't create socket: %s (%s)\n", sun.sun_path, strerror(errno));
		return 1;
	}

	pseudo_debug(3, "connecting socket...\n");
	cwd_fd = open(".", O_RDONLY);
	if (cwd_fd == -1) {
		pseudo_diag("Couldn't stash directory before opening socket: %s",
			strerror(errno));
		close(connect_fd);
		connect_fd = -1;
		return 1;
	}
	if (fchdir(pseudo_localstate_dir_fd) == -1) {
		pseudo_diag("Couldn't chdir to server directory [%d]: %s\n",
			pseudo_localstate_dir_fd, strerror(errno));
		close(connect_fd);
		close(cwd_fd);
		connect_fd = -1;
		return 1;
	}
	if (connect(connect_fd, (struct sockaddr *) &sun, sizeof(sun)) == -1) {
		pseudo_debug(3, "can't connect socket to pseudo.socket: (%s)\n", strerror(errno));
		close(connect_fd);
		if (fchdir(cwd_fd) == -1) {
			pseudo_diag("return to previous directory failed: %s\n",
				strerror(errno));
		}
		close(cwd_fd);
		connect_fd = -1;
		return 1;
	}
	if (fchdir(cwd_fd) == -1) {
		pseudo_diag("return to previous directory failed: %s\n",
			strerror(errno));
	}
	close(cwd_fd);
	pseudo_debug(4, "connected socket.\n");
	return 0;
}
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;
}
Exemple #7
0
int
pseudo_client_chroot(const char *path) {
	/* free old value */
	free(pseudo_chroot);

	pseudo_debug(2, "client chroot: %s\n", path);
	if (!strcmp(path, "/")) {
		pseudo_chroot_len = 0;
		pseudo_chroot = 0;
		pseudo_set_value("PSEUDO_CHROOT", NULL);
		return 0;
	}
	/* allocate new value */
	pseudo_chroot_len = strlen(path);
	pseudo_chroot = malloc(pseudo_chroot_len + 1);
	if (!pseudo_chroot) {
		pseudo_diag("Couldn't allocate chroot directory buffer.\n");
		pseudo_chroot_len = 0;
		errno = ENOMEM;
		return -1;
	}
	memcpy(pseudo_chroot, path, pseudo_chroot_len + 1);
	pseudo_set_value("PSEUDO_CHROOT", pseudo_chroot);
	return 0;
}
Exemple #8
0
int
execle(const char *file, const char *arg, ...) {
	sigset_t saved;
	va_list ap;
	char **argv;
	char **envp;

	int rc = -1;

	if (!pseudo_check_wrappers()) {
		/* rc was initialized to the "failure" value */
		pseudo_enosys("execle");
		return rc;
	}

	va_start(ap, arg);
	argv = execl_to_v(ap, arg, (char *const **)&envp);
	va_end(ap);
	if (!argv) {
		errno = ENOMEM;
		return -1;
	}

	pseudo_debug(4, "called: execle\n");
	pseudo_sigblock(&saved);
	if (pseudo_getlock()) {
		errno = EBUSY;
		sigprocmask(SIG_SETMASK, &saved, NULL);
		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(4, "completed: execle\n");
	errno = save_errno;
	free(argv);
	return rc;
}
Exemple #9
0
static pseudo_msg_t *
pseudo_client_request(pseudo_msg_t *msg, size_t len, const char *path) {
	pseudo_msg_t *response = 0;
	int tries = 0;
	int rc;

	if (!msg)
		return 0;

	do {
		do {
			pseudo_debug(4, "sending a message: ino %llu\n",
				(unsigned long long) msg->ino);
			if (connect_fd < 0) {
				pseudo_debug(2, "trying to get server\n");
				if (pseudo_client_setup()) {
					return 0;
				}
			}
			rc = pseudo_msg_send(connect_fd, msg, len, path);
			if (rc != 0) {
				pseudo_debug(2, "msg_send: %d%s\n",
					rc,
					rc == -1 ? " (sigpipe)" :
					           " (short write)");
				pseudo_client_setup();
				++tries;
				if (tries > 3) {
					pseudo_debug(1, "can't get server going again.\n");
					return 0;
				}
			}
		} while (rc != 0);
		pseudo_debug(5, "sent!\n");
		response = pseudo_msg_receive(connect_fd);
		if (!response) {
			++tries;
			if (tries > 3) {
				pseudo_debug(1, "can't get responses.\n");
				return 0;
			}
		}
	} while (response == 0);
	if (response->type != PSEUDO_MSG_ACK) {
		pseudo_debug(2, "got non-ack response %d\n", response->type);
		return 0;
	} else {
		pseudo_debug(4, "got response type %d\n", response->type);
	}
	return response;
}
static int
client_ping(void) {
	pseudo_msg_t ping;
	pseudo_msg_t *ack;
	char tagbuf[pseudo_path_max()];
	char *tag = pseudo_get_value("PSEUDO_TAG");

	memset(&ping, 0, sizeof(ping));

	ping.type = PSEUDO_MSG_PING;
	ping.op = OP_NONE;

	ping.pathlen = snprintf(tagbuf, sizeof(tagbuf), "%s%c%s",
		program_invocation_name ? program_invocation_name : "<unknown>",
		0,
		tag ? tag : "");
	free(tag);
	ping.client = getpid();
	ping.result = 0;
	errno = 0;
	pseudo_debug(4, "sending ping\n");
	if (pseudo_msg_send(connect_fd, &ping, ping.pathlen, tagbuf)) {
		pseudo_debug(3, "error pinging server: %s\n", strerror(errno));
		return 1;
	}
	ack = pseudo_msg_receive(connect_fd);
	if (!ack) {
		pseudo_debug(2, "no ping response from server: %s\n", strerror(errno));
		/* and that's not good, so... */
		server_pid = 0;
		return 1;
	}
	if (ack->type != PSEUDO_MSG_ACK) {
		pseudo_debug(1, "invalid ping response from server: expected ack, got %d\n", ack->type);
		/* and that's not good, so... */
		server_pid = 0;
		return 1;
	}
	pseudo_debug(5, "ping ok\n");
	return 0;
}
Exemple #11
0
static char *
base_path(int dirfd, const char *path, int leave_last) {
	char *basepath = 0;
	size_t baselen = 0;
	size_t minlen = 0;
	char *newpath;

	if (!path)
		return NULL;
	if (!*path)
		return strdup("");

	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 {
			basepath = pseudo_cwd;
			baselen = pseudo_cwd_len;
		}
		if (!basepath) {
			pseudo_diag("unknown base path for fd %d, path %s\n", dirfd, path);
			return 0;
		}
		/* if there's a chroot path, and it's the start of basepath,
		 * flag it for pseudo_fix_path
		 */
		if (pseudo_chroot_len && baselen >= pseudo_chroot_len &&
			!memcmp(basepath, pseudo_chroot, pseudo_chroot_len) &&
			(basepath[pseudo_chroot_len] == '\0' || basepath[pseudo_chroot_len] == '/')) {

			minlen = pseudo_chroot_len;
		}
	} else if (pseudo_chroot_len) {
		/* "absolute" is really relative to chroot path */
		basepath = pseudo_chroot;
		baselen = pseudo_chroot_len;
		minlen = pseudo_chroot_len;
	}

	newpath = pseudo_fix_path(basepath, path, minlen, baselen, NULL, leave_last);
	pseudo_debug(4, "base_path: %s</>%s\n",
		basepath ? basepath : "<nil>",
		path ? path : "<nil>");
	return newpath;
}
Exemple #12
0
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;
}
Exemple #13
0
static int
pseudo_client_setup(void) {
	char * pseudo_pidfile;
	FILE *fp;
	server_pid = 0;

	/* avoid descriptor leak, I hope */
	if (connect_fd >= 0) {
		close(connect_fd);
		connect_fd = -1;
	}

	pseudo_pidfile = pseudo_localstatedir_path(PSEUDO_PIDFILE);
	fp = fopen(pseudo_pidfile, "r");
	if (fp) {
		if (fscanf(fp, "%d", &server_pid) != 1) {
			pseudo_debug(1, "Opened server PID file, but didn't get a pid.\n");
		}
		fclose(fp);
	}
	if (server_pid) {
		if (kill(server_pid, 0) == -1) {
			pseudo_debug(1, "couldn't find server at pid %d: %s\n",
				server_pid, strerror(errno));
			server_pid = 0;
		}
	}
	if (!server_pid) {
		if (client_spawn_server()) {
			return 1;
		}
	}
	if (!client_connect() && !client_ping()) {
		return 0;
	}
	pseudo_debug(2, "server seems to be gone, trying to restart\n");
	if (client_spawn_server()) {
		pseudo_debug(1, "failed to spawn server, giving up.\n");
		return 1;
	} else {
		pseudo_debug_verbose();
		pseudo_debug(2, "restarted, new pid %d\n", server_pid);
		if (!client_connect() && !client_ping()) {
			pseudo_debug_terse();
			return 0;
		}
		pseudo_debug_terse();
	}
	pseudo_debug(1, "couldn't get a server, giving up.\n");
	return 1;
}
Exemple #14
0
int
pseudo_client_shutdown(void) {
	pseudo_msg_t msg;
	pseudo_msg_t *ack;
	char *pseudo_path;

	pseudo_path = pseudo_prefix_path(NULL);
	if (pseudo_prefix_dir_fd == -1) {
		if (pseudo_path) {
			pseudo_prefix_dir_fd = open(pseudo_path, O_RDONLY);
			/* directory is missing? */
			if (pseudo_prefix_dir_fd == -1 && errno == ENOENT) {
				pseudo_debug(1, "prefix directory doesn't exist, trying to create\n");
				mkdir_p(pseudo_path);
				pseudo_prefix_dir_fd = open(pseudo_path, O_RDONLY);
			}
			pseudo_prefix_dir_fd = pseudo_fd(pseudo_prefix_dir_fd, COPY_FD);
			free(pseudo_path);
		} else {
			pseudo_diag("No prefix available to to find server.\n");
			exit(1);
		}
		if (pseudo_prefix_dir_fd == -1) {
			pseudo_diag("Can't open prefix path (%s) for server. (%s)\n",
				pseudo_prefix_path(NULL),
				strerror(errno));
			exit(1);
		}
	}
	pseudo_path = pseudo_localstatedir_path(NULL);
	mkdir_p(pseudo_path);
	if (pseudo_localstate_dir_fd == -1) {
		if (pseudo_path) {
			pseudo_localstate_dir_fd = open(pseudo_path, O_RDONLY);
			/* directory is missing? */
			if (pseudo_localstate_dir_fd == -1 && errno == ENOENT) {
				pseudo_debug(1, "local state dir doesn't exist, trying to create\n");
				mkdir_p(pseudo_path);
				pseudo_localstate_dir_fd = open(pseudo_path, O_RDONLY);
			}
			pseudo_localstate_dir_fd = pseudo_fd(pseudo_localstate_dir_fd, COPY_FD);
			free(pseudo_path);
		} else {
			pseudo_diag("No prefix available to to find server.\n");
			exit(1);
		}
		if (pseudo_localstate_dir_fd == -1) {
			pseudo_diag("Can't open local state path (%s) for server. (%s)\n",
				pseudo_localstatedir_path(NULL),
				strerror(errno));
			exit(1);
		}
	}
	if (client_connect()) {
		pseudo_diag("Pseudo server seems to be already offline.\n");
		return 0;
	}
	memset(&msg, 0, sizeof(pseudo_msg_t));
	msg.type = PSEUDO_MSG_SHUTDOWN;
	msg.op = OP_NONE;
	msg.client = getpid();
	pseudo_debug(2, "sending shutdown request\n");
	if (pseudo_msg_send(connect_fd, &msg, 0, NULL)) {
		pseudo_debug(1, "error requesting shutdown: %s\n", strerror(errno));
		return 1;
	}
	ack = pseudo_msg_receive(connect_fd);
	if (!ack) {
		pseudo_diag("server did not respond to shutdown query.\n");
		return 1;
	}
	if (ack->type == PSEUDO_MSG_ACK) {
		return 0;
	}
	pseudo_diag("Server refused shutdown.  Remaining client fds: %d\n", ack->fd);
	pseudo_diag("Client pids: %s\n", ack->path);
	pseudo_diag("Server will shut down after all clients exit.\n");
	return 0;
}
Exemple #15
0
/* spawn server */
static int
client_spawn_server(void) {
	int status;
	FILE *fp;
	char * pseudo_pidfile;

	if ((server_pid = fork()) != 0) {
		if (server_pid == -1) {
			pseudo_diag("couldn't fork server: %s\n", strerror(errno));
			return 1;
		}
		pseudo_debug(4, "spawned server, pid %d\n", server_pid);
		/* wait for the child process to terminate, indicating server
		 * is ready
		 */
		waitpid(server_pid, &status, 0);
		server_pid = -2;
		pseudo_pidfile = pseudo_localstatedir_path(PSEUDO_PIDFILE);
		fp = fopen(pseudo_pidfile, "r");
		if (fp) {
			if (fscanf(fp, "%d", &server_pid) != 1) {
				pseudo_debug(1, "Opened server PID file, but didn't get a pid.\n");
			}
			fclose(fp);
		} else {
			pseudo_debug(1, "no pid file (%s): %s\n",
				pseudo_pidfile, strerror(errno));
		}
		pseudo_debug(2, "read new pid file: %d\n", server_pid);
		free(pseudo_pidfile);
		/* at this point, we should have a new server_pid */
		return 0;
	} else {
		char *base_args[] = { NULL, NULL, NULL };
		char **argv;
		char *option_string = pseudo_get_value("PSEUDO_OPTS");
		int args;
		int fd;

		pseudo_new_pid();
		base_args[0] = pseudo_bindir_path("pseudo");
		base_args[1] = "-d";
		if (option_string) {
			char *s;
			int arg;

			/* count arguments in PSEUDO_OPTS, starting at 2
			 * for pseudo/-d/NULL, plus one for the option string.
			 * The number of additional arguments may be less
			 * than the number of spaces, but can't be more.
			 */
			args = 4;
			for (s = option_string; *s; ++s)
				if (*s == ' ')
					++args;

			argv = malloc(args * sizeof(char *));
			argv[0] = base_args[0];
			argv[1] = base_args[1];
			arg = 2;
			while ((s = strsep(&option_string, " ")) != NULL) {
				if (*s) {
					argv[arg++] = strdup(s);
				}
			}
			argv[arg] = 0;
		} else {
			argv = base_args;
		}

		/* close any higher-numbered fds which might be open,
		 * such as sockets.  We don't have to worry about 0 and 1;
		 * the server closes them already, and more importantly,
		 * they can't have been opened or closed without us already
		 * having spawned a server... The issue is just socket()
		 * calls which could result in fds being left open, and those
		 * can't overwrite fds 0-2 unless we closed them...
		 * 
		 * No, really.  It works.
		 */
		for (fd = 3; fd < 1024; ++fd) {
			if (fd != pseudo_util_debug_fd)
				close(fd);
		}
		/* and now, execute the server */

		pseudo_set_value("PSEUDO_RELOADED", "YES");
		pseudo_setupenv();
		pseudo_dropenv(); /* drop PRELINK_LIBRARIES */

		pseudo_debug(4, "calling execv on %s\n", argv[0]);

		execv(argv[0], argv);
		pseudo_diag("critical failure: exec of pseudo daemon failed: %s\n", strerror(errno));
		exit(1);
	}
}
Exemple #16
0
void
pseudo_init_client(void) {
	char *env;

	pseudo_antimagic();
	pseudo_new_pid();
	if (connect_fd != -1) {
		close(connect_fd);
		connect_fd = -1;
	}

	/* in child processes, PSEUDO_DISABLED may have become set to
	 * some truthy value, in which case we'd disable pseudo,
	 * or it may have gone away, in which case we'd enable
	 * pseudo (and cause it to reinit the defaults).
	 */
	env = getenv("PSEUDO_DISABLED");
	if (!env) {
		env = pseudo_get_value("PSEUDO_DISABLED");
	}
	if (env) {
		int actually_disabled = 1;
		switch (*env) {
		case '0':
		case 'f':
		case 'F':
		case 'n':
		case 'N':
			actually_disabled = 0;
			break;
		case 's':
		case 'S':
			actually_disabled = 0;
			pseudo_local_only = 1;
			break;
		}
		if (actually_disabled) {
			if (!pseudo_disabled) {
				pseudo_antimagic();
				pseudo_disabled = 1;
			}
			pseudo_set_value("PSEUDO_DISABLED", "1");
		} else {
			if (pseudo_disabled) {
				pseudo_magic();
				pseudo_disabled = 0;
				pseudo_inited = 0; /* Re-read the initial values! */
			}
			pseudo_set_value("PSEUDO_DISABLED", "0");
		}
	} else {
		pseudo_set_value("PSEUDO_DISABLED", "0");
	}

	/* Setup global items needed for pseudo to function... */
	if (!pseudo_inited) {
		/* Ensure that all of the values are reset */
		server_pid = 0;
		pseudo_prefix_dir_fd = -1;
		pseudo_localstate_dir_fd = -1;
		pseudo_pwd_fd = -1;
		pseudo_pwd_lck_fd = -1;
		pseudo_pwd_lck_name = NULL;
		pseudo_pwd = NULL;
		pseudo_grp_fd = -1;
		pseudo_grp = NULL;
		pseudo_cwd = NULL;
		pseudo_cwd_len = 0;
		pseudo_chroot = NULL;
		pseudo_passwd = NULL;
		pseudo_chroot_len = 0;
		pseudo_cwd_rel = NULL;
		pseudo_nosymlinkexp = 0;
	}

	if (!pseudo_disabled && !pseudo_inited) {
		char *pseudo_path = 0;

		pseudo_path = pseudo_prefix_path(NULL);
		if (pseudo_prefix_dir_fd == -1) {
			if (pseudo_path) {
				pseudo_prefix_dir_fd = open(pseudo_path, O_RDONLY);
				/* directory is missing? */
				if (pseudo_prefix_dir_fd == -1 && errno == ENOENT) {
					pseudo_debug(1, "prefix directory doesn't exist, trying to create\n");
					mkdir_p(pseudo_path);
					pseudo_prefix_dir_fd = open(pseudo_path, O_RDONLY);
				}
				pseudo_prefix_dir_fd = pseudo_fd(pseudo_prefix_dir_fd, MOVE_FD);
			} else {
				pseudo_diag("No prefix available to to find server.\n");
				exit(1);
			}
			if (pseudo_prefix_dir_fd == -1) {
				pseudo_diag("Can't open prefix path (%s) for server: %s\n",
					pseudo_path,
					strerror(errno));
				exit(1);
			}
		}
		free(pseudo_path);
		pseudo_path = pseudo_localstatedir_path(NULL);
		if (pseudo_localstate_dir_fd == -1) {
			if (pseudo_path) {
				pseudo_localstate_dir_fd = open(pseudo_path, O_RDONLY);
				/* directory is missing? */
				if (pseudo_localstate_dir_fd == -1 && errno == ENOENT) {
					pseudo_debug(1, "local state directory doesn't exist, trying to create\n");
					mkdir_p(pseudo_path);
					pseudo_localstate_dir_fd = open(pseudo_path, O_RDONLY);
				}
				pseudo_localstate_dir_fd = pseudo_fd(pseudo_localstate_dir_fd, MOVE_FD);
			} else {
				pseudo_diag("No prefix available to to find server.\n");
				exit(1);
			}
			if (pseudo_localstate_dir_fd == -1) {
				pseudo_diag("Can't open local state path (%s) for server: %s\n",
					pseudo_path,
					strerror(errno));
				exit(1);
			}
		}
		free(pseudo_path);

		env = pseudo_get_value("PSEUDO_NOSYMLINKEXP");
		if (env) {
			char *endptr;
			/* if the environment variable is not an empty string,
			 * parse it; "0" means turn NOSYMLINKEXP off, "1" means
			 * turn it on (disabling the feature).  An empty string
			 * or something we can't parse means to set the flag; this
			 * is a safe default because if you didn't want the flag
			 * set, you normally wouldn't set the environment variable
			 * at all.
			 */
			if (*env) {
				pseudo_nosymlinkexp = strtol(env, &endptr, 10);
				if (*endptr)
					pseudo_nosymlinkexp = 1;
			} else {
				pseudo_nosymlinkexp = 1;
			}
		} else {
			pseudo_nosymlinkexp = 0;
		}
		free(env);
		env = pseudo_get_value("PSEUDO_UIDS");
		if (env)
			sscanf(env, "%d,%d,%d,%d",
				&pseudo_ruid, &pseudo_euid,
				&pseudo_suid, &pseudo_fuid);
		free(env);

		env = pseudo_get_value("PSEUDO_GIDS");
		if (env)
			sscanf(env, "%d,%d,%d,%d",
				&pseudo_rgid, &pseudo_egid,
				&pseudo_sgid, &pseudo_fuid);
		free(env);

		env = pseudo_get_value("PSEUDO_CHROOT");
		if (env) {
			pseudo_chroot = strdup(env);
			if (pseudo_chroot) {
				pseudo_chroot_len = strlen(pseudo_chroot);
			} else {
				pseudo_diag("can't store chroot path (%s)\n", env);
			}
		}
		free(env);

		env = pseudo_get_value("PSEUDO_PASSWD");
		if (env) {
			pseudo_passwd = strdup(env);
		}
		free(env);

		pseudo_inited = 1;
	}
	if (!pseudo_disabled)
		pseudo_client_getcwd();

	pseudo_magic();
}