예제 #1
0
/*
 * prb_child_create()  - this routine instantiates and rendevous with the
 * target child process.  This routine returns an opaque handle for the
 * childs /proc entry.
 */
prb_status_t
prb_child_create(const char *cmdname, char * const *cmdargs,
                 const char *loption, const char *libtnfprobe_path,
                 char * const *envp, prb_proc_ctl_t **ret_val)
{
    prb_status_t	prbstat;
    pid_t		childpid;
    char		executable_name[PATH_MAX + 2];
    extern char 	**environ;
    char * const *	env_to_use;
    size_t		loptlen, probepathlen;
    volatile shmem_msg_t *smp;

    /* initialize shmem communication buffer to cause child to wait */
    prbstat = prb_shmem_init(&smp);
    if (prbstat)
        return (prbstat);

    /* fork to create the child process */
    childpid = fork();
    if (childpid == (pid_t) - 1) {
        DBG(perror("prb_child_create: fork failed"));
        return (prb_status_map(errno));
    }
    if (childpid == 0) {
        char		   *oldenv;
        char		   *newenv;

        /* ---- CHILD PROCESS ---- */

        DBG_TNF_PROBE_1(prb_child_create_1, "libtnfctl",
                        "sunw%verbosity 1; sunw%debug 'child process created'",
                        tnf_long, pid, getpid());

        if (envp) {
            env_to_use = envp;
            goto ContChild;
        }

        /* append libtnfprobe.so to the LD_PRELOAD environment */
        loptlen = (loption) ? strlen(loption) : 0;
        /* probepathlen has a "/" added in ("+ 1") */
        probepathlen = (libtnfprobe_path) ?
                       (strlen(libtnfprobe_path) + 1) : 0;
        oldenv = getenv(PRELOAD);
        if (oldenv) {
            newenv = (char *) malloc(strlen(PRELOAD) +
                                     1 +	/* "=" */
                                     strlen(oldenv) +
                                     1 +	/* " " */
                                     probepathlen +
                                     strlen(LIBPROBE) +
                                     1 +	/* " " */
                                     loptlen +
                                     1);	/* NULL */

            if (!newenv)
                goto ContChild;
            (void) strcpy(newenv, PRELOAD);
            (void) strcat(newenv, "=");
            (void) strcat(newenv, oldenv);
            (void) strcat(newenv, " ");
            if (probepathlen) {
                (void) strcat(newenv, libtnfprobe_path);
                (void) strcat(newenv, "/");
            }
            (void) strcat(newenv, LIBPROBE);
            if (loptlen) {
                (void) strcat(newenv, " ");
                (void) strcat(newenv, loption);
            }
        } else {
            newenv = (char *) malloc(strlen(PRELOAD) +
                                     1 +	/* "=" */
                                     probepathlen +
                                     strlen(LIBPROBE) +
                                     1 +	/* " " */
                                     loptlen +
                                     1);	/* NULL */
            if (!newenv)
                goto ContChild;
            (void) strcpy(newenv, PRELOAD);
            (void) strcat(newenv, "=");
            if (probepathlen) {
                (void) strcat(newenv, libtnfprobe_path);
                (void) strcat(newenv, "/");
            }
            (void) strcat(newenv, LIBPROBE);
            if (loptlen) {
                (void) strcat(newenv, " ");
                (void) strcat(newenv, loption);
            }
        }
        (void) putenv((char *) newenv);
        env_to_use = environ;
        /*
         * We don't check the return value of putenv because the
         * desired libraries might already be in the target, even
         * if our effort to change the environment fails.  We
         * should continue either way ...
         */
ContChild:
        /* wait until the parent releases us */
        (void) prb_shmem_wait(smp);

        DBG_TNF_PROBE_1(prb_child_create_2, "libtnfctl",
                        "sunw%verbosity 2; "
                        "sunw%debug 'child process about to exec'",
                        tnf_string, cmdname, cmdname);

        /*
         * make the child it's own process group.
         * This is so that signals delivered to parent are not
         * also delivered to child.
         */
        (void) setpgrp();
        prbstat = find_executable(cmdname, executable_name);
        if (prbstat) {
            DBG((void) fprintf(stderr, "prb_child_create: %s\n",
                               prb_status_str(prbstat)));
            /* parent waits for exit */
            _exit(1);
        }
        if (execve(executable_name, cmdargs, env_to_use) == -1) {
            DBG(perror("prb_child_create: exec failed"));
            _exit(1);
        }

        /* Never reached */
        _exit(1);
    }
    /* ---- PARENT PROCESS ---- */
    /* child is waiting for us */

    prbstat = sync_child(childpid, smp, ret_val);
    if (prbstat) {
        return (prbstat);
    }

    return (PRB_STATUS_OK);

}
예제 #2
0
파일: prb_rtld.c 프로젝트: andreiw/polaris
/*
 * prb_rtld_wait() - waits on target to execute getpid()
 */
static prb_status_t
prb_rtld_wait(prb_proc_ctl_t *proc_p)
{
	prb_proc_state_t pstate;
	prb_status_t	prbstat;

	DBG_TNF_PROBE_0(prb_rtld_wait_1, "libtnfctl", "sunw%verbosity 2");

	/* stop on exit of getpid() */
	prbstat = prb_proc_exit(proc_p, SYS_getpid, PRB_SYS_ADD);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't set up child to stop on "
			"exit of getpid(): %s\n", prb_status_str(prbstat)));
		return (prbstat);
	}
	/* stop on entry of exit() - i.e. exec failed */
	prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_ADD);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't set up child to stop on "
			"entry of exit(): %s\n", prb_status_str(prbstat)));
		return (prbstat);
	}
	/* continue target and wait for it to stop */
	prbstat = prb_proc_cont(proc_p);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't continue target process: %s\n",
				prb_status_str(prbstat)));
		return (prbstat);
	}
	/* wait for target to stop */
	prbstat = prb_proc_wait(proc_p, B_FALSE, NULL);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't wait on target process: %s\n",
			prb_status_str(prbstat)));
		return (prbstat);
	}
	/* make sure it did stop on getpid() */
	prbstat = prb_proc_state(proc_p, &pstate);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't get state of target: %s\n",
				prb_status_str(prbstat)));
		return (prbstat);
	}
	if (pstate.ps_issysentry && (pstate.ps_syscallnum == SYS_exit)) {
		DBG((void) fprintf(stderr, "prb_rtld_wait: target exited\n"));
		return (prb_status_map(EACCES));
	}
	/* catch any other errors */
	if (!(pstate.ps_issysexit && (pstate.ps_syscallnum == SYS_getpid))) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: target didn't stop on getpid\n"));
		return (PRB_STATUS_BADSYNC);
	}
	/* clear wait on getpid */
	prbstat = prb_proc_exit(proc_p, SYS_getpid, PRB_SYS_DEL);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't clear child to stop on "
			"exit of getpid(): %s\n", prb_status_str(prbstat)));
		return (prbstat);
	}
	/* clear wait on exit */
	prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_DEL);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't clear child to stop on "
			"entry of exit(): %s\n", prb_status_str(prbstat)));
		return (prbstat);
	}
	/* start-stop the process to clear it out of the system call */
	prbstat = prb_proc_prstop(proc_p);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't prstop child: %s\n",
			prb_status_str(prbstat)));
		return (prbstat);
	}
	return (PRB_STATUS_OK);
}