/* * This function returns an NSPR PRFileDesc * which the caller can read to * obtain the prestine value of the shared library, before any OS related * changes to it (usually address fixups). * * If prelink is installed, this * file descriptor is a pipe connecting the output of * /usr/sbin/prelink -u -o - {Library} * and *pid returns the process id of the prelink child. * * If prelink is not installed, it returns a normal readonly handle to the * library itself and *pid is set to '0'. */ PRFileDesc * bl_OpenUnPrelink(const char *shName, int *pid) { char *command= strdup(FREEBL_PRELINK_COMMAND); char *argString = NULL; char **argv = NULL; char *shNameArg = NULL; char *cp; pid_t child; int argc = 0, argNext = 0; struct stat statBuf; int pipefd[2] = {-1,-1}; int ret; *pid = 0; /* make sure the prelink command exists first. If not, fall back to * just reading the file */ for (cp = command; *cp ; cp++) { if (*cp == ' ') { *cp++ = 0; argString = cp; break; } } memset (&statBuf, 0, sizeof(statBuf)); /* stat the file, follow the link */ ret = stat(command, &statBuf); if (ret < 0) { free(command); return PR_Open(shName, PR_RDONLY, 0); } /* file exits, make sure it's an executable */ if (!S_ISREG(statBuf.st_mode) || ((statBuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)) { free(command); return PR_Open(shName, PR_RDONLY, 0); } /* OK, the prelink command exists and looks correct, use it */ /* build the arglist while we can still malloc */ /* count the args if any */ if (argString && *argString) { /* argString may have leading spaces, strip them off*/ for (cp = argString; *cp && *cp == ' '; cp++); argString = cp; if (*cp) { /* there is at least one arg.. */ argc = 1; } /* count the rest: Note there is no provision for escaped * spaces here */ for (cp = argString; *cp ; cp++) { if (*cp == ' ') { while (*cp && *cp == ' ') cp++; if (*cp) argc++; } } } /* add the additional args: argv[0] (command), shName, NULL*/ argc += 3; argv = PORT_NewArray(char *, argc); if (argv == NULL) { goto loser; } /* fill in the arglist */ argv[argNext++] = command; if (argString && *argString) { argv[argNext++] = argString; for (cp = argString; *cp; cp++) { if (*cp == ' ') { *cp++ = 0; while (*cp && *cp == ' ') cp++; if (*cp) argv[argNext++] = cp; } } } /* exec doesn't advertise taking const char **argv, do the paranoid * copy */ shNameArg = strdup(shName); if (shNameArg == NULL) { goto loser; } argv[argNext++] = shNameArg; argv[argNext++] = 0; ret = pipe(pipefd); if (ret < 0) { goto loser; } /* use vfork() so we don't trigger the pthread_at_fork() handlers */ child = vfork(); if (child < 0) goto loser; if (child == 0) { /* set up the file descriptors */ /* if we need to support BSD, this will need to be an open of * /dev/null and dup2(nullFD, 0)*/ close(0); /* associate pipefd[1] with stdout */ if (pipefd[1] != 1) dup2(pipefd[1], 1); close(2); close(pipefd[0]); /* should probably close the other file descriptors? */ execv(command, argv); /* avoid at_exit() handlers */ _exit(1); /* shouldn't reach here except on an error */ } close(pipefd[1]); pipefd[1] = -1; /* this is safe because either vfork() as full fork() semantics, and thus * already has it's own address space, or because vfork() has paused * the parent util the exec or exit */ free(command); free(shNameArg); PORT_Free(argv); *pid = child; return PR_ImportPipe(pipefd[0]); loser: if (pipefd[0] != -1) { close(pipefd[0]); } if (pipefd[1] != -1) { close(pipefd[1]); } free(command); free(shNameArg); PORT_Free(argv); return NULL; }
PR_IMPLEMENT(PRFileDesc *) PR_GetInheritedFD( const char *name) { PRFileDesc *fd; const char *envVar; const char *ptr; int len = strlen(name); PROsfd osfd; int nColons; PRIntn fileType; envVar = PR_GetEnv("NSPR_INHERIT_FDS"); if (NULL == envVar || '\0' == envVar[0]) { PR_SetError(PR_UNKNOWN_ERROR, 0); return NULL; } ptr = envVar; while (1) { if ((ptr[len] == ':') && (strncmp(ptr, name, len) == 0)) { ptr += len + 1; PR_sscanf(ptr, "%d:0x%" PR_SCNxOSFD, &fileType, &osfd); switch ((PRDescType)fileType) { case PR_DESC_FILE: fd = PR_ImportFile(osfd); break; case PR_DESC_PIPE: fd = PR_ImportPipe(osfd); break; case PR_DESC_SOCKET_TCP: fd = PR_ImportTCPSocket(osfd); break; case PR_DESC_SOCKET_UDP: fd = PR_ImportUDPSocket(osfd); break; default: PR_ASSERT(0); PR_SetError(PR_UNKNOWN_ERROR, 0); fd = NULL; break; } if (fd) { /* * An inherited FD is inheritable by default. * The child process needs to call PR_SetFDInheritable * to make it non-inheritable if so desired. */ fd->secret->inheritable = _PR_TRI_TRUE; } return fd; } /* Skip three colons */ nColons = 0; while (*ptr) { if (*ptr == ':') { if (++nColons == 3) { break; } } ptr++; } if (*ptr == '\0') { PR_SetError(PR_UNKNOWN_ERROR, 0); return NULL; } ptr++; } }