/* wrapper code -- this is the shared code used around the pseduo * wrapper functions, which are in pseudo_wrapfuncs.c. */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* used for various specific function arguments */ #include #include #include #include #include #include #include #include "pseudo.h" #include "pseudo_wrapfuncs.h" #include "pseudo_ipc.h" #include "pseudo_client.h" static void pseudo_enosys(const char *); static int pseudo_populate_wrappers(void); static volatile int antimagic = 0; static pthread_mutex_t pseudo_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_t pseudo_mutex_holder; static int pseudo_mutex_recursion = 0; static int pseudo_getlock(void); static void pseudo_droplock(void); static size_t pseudo_dechroot(char *, size_t); extern char *program_invocation_short_name; /* the generated code goes here */ #include "pseudo_wrapper_table.c" #include "pseudo_wrapfuncs.c" static int pseudo_getlock(void) { if (pthread_equal(pseudo_mutex_holder, pthread_self())) { ++pseudo_mutex_recursion; return 0; } else { if (pthread_mutex_lock(&pseudo_mutex) == 0) { pseudo_mutex_recursion = 1; pseudo_mutex_holder = pthread_self(); return 0; } else { return -1; } } } static void pseudo_droplock(void) { if (--pseudo_mutex_recursion == 0) { pseudo_mutex_holder = 0; pthread_mutex_unlock(&pseudo_mutex); } } void pseudo_antimagic() { ++antimagic; } void pseudo_magic() { if (antimagic > 0) --antimagic; } static void pseudo_enosys(const char *func) { pseudo_diag("pseudo: ENOSYS for '%s'.\n", func ? func : ""); if (getenv("PSEUDO_ENOSYS_ABORT")) abort(); } /* de-chroot a string. * note that readlink() yields an unterminated buffer, so * must pass in the correct length. Buffers are null-terminated * unconditionally if they are modified -- the modification would * shorten the string, so there will be space for the NUL, so * this is safe even for stuff like readlink(). */ static size_t pseudo_dechroot(char *s, size_t len) { if (len == (size_t) -1) len = strlen(s); if (pseudo_chroot_len && len >= pseudo_chroot_len && !memcmp(s, pseudo_chroot, pseudo_chroot_len)) { if (s[pseudo_chroot_len] == '/') { memmove(s, s + pseudo_chroot_len, len - pseudo_chroot_len); len -= pseudo_chroot_len; s[len] = '\0'; } else if (s[pseudo_chroot_len] == '\0') { s[0] = '/'; len = 1; s[len] = '\0'; } /* otherwise, it's not really a match... */ } return len; } static int pseudo_populate_wrappers(void) { int i; char *debug; static int done = 0; char *pseudo_path = 0; char *no_symlink_exp; if (done) return done; pseudo_getlock(); pseudo_antimagic(); for (i = 0; pseudo_functions[i].name; ++i) { if (*pseudo_functions[i].real == pseudo_functions[i].dummy) { int (*f)(void); char *e; dlerror(); f = dlsym(RTLD_NEXT, pseudo_functions[i].name); if ((e = dlerror()) != NULL) { /* leave it pointed to dummy */ pseudo_diag("No wrapper for %s: %s\n", pseudo_functions[i].name, e); } else { if (f) *pseudo_functions[i].real = f; } } } done = 1; debug = getenv("PSEUDO_DEBUG"); if (debug) { int level = atoi(debug); for (i = 0; i < level; ++i) { pseudo_debug_verbose(); } } no_symlink_exp = getenv("PSEUDO_NOSYMLINKEXP"); if (no_symlink_exp) { 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 (*no_symlink_exp) { pseudo_nosymlinkexp = strtol(no_symlink_exp, &endptr, 10); if (*endptr) pseudo_nosymlinkexp = 1; } else { pseudo_nosymlinkexp = 1; } } else { pseudo_nosymlinkexp = 0; } /* if PSEUDO_DEBUG_FILE is set up, redirect logging there. */ pseudo_logfile(NULL); /* must happen after wrappers are set up, because it can call * getcwd(), which needs wrappers, but must happen here so that * any attempt to use a path in a wrapper function will have a * value for cwd. */ pseudo_client_reset(); pseudo_path = pseudo_prefix_path(NULL); if (pseudo_prefix_dir_fd == -1) { if (pseudo_path) { pseudo_prefix_dir_fd = open(pseudo_path, O_RDONLY); pseudo_prefix_dir_fd = pseudo_fd(pseudo_prefix_dir_fd, MOVE_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.\n", strerror(errno)); exit(1); } } pseudo_path = pseudo_localstatedir_path(NULL); if (pseudo_localstate_dir_fd == -1) { if (pseudo_path) { pseudo_localstate_dir_fd = open(pseudo_path, O_RDONLY); pseudo_localstate_dir_fd = pseudo_fd(pseudo_localstate_dir_fd, MOVE_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 prefix path (%s) for server.\n", strerror(errno)); exit(1); } } pseudo_debug(2, "(%s) set up wrappers\n", program_invocation_short_name); pseudo_magic(); pseudo_droplock(); return done; }