Esempio n. 1
0
/*
 * 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;
}
Esempio n. 2
0
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++;
    }
}