proc_create.c revision 224632
1179185Sjb/*- 2179185Sjb * Copyright (c) 2008 John Birrell (jb@freebsd.org) 3179185Sjb * All rights reserved. 4179185Sjb * 5179185Sjb * Redistribution and use in source and binary forms, with or without 6179185Sjb * modification, are permitted provided that the following conditions 7179185Sjb * are met: 8179185Sjb * 1. Redistributions of source code must retain the above copyright 9179185Sjb * notice, this list of conditions and the following disclaimer. 10179185Sjb * 2. Redistributions in binary form must reproduce the above copyright 11179185Sjb * notice, this list of conditions and the following disclaimer in the 12179185Sjb * documentation and/or other materials provided with the distribution. 13179185Sjb * 14179185Sjb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15179185Sjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16179185Sjb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17179185Sjb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18179185Sjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19179185Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20179185Sjb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21179185Sjb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22179185Sjb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23179185Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24179185Sjb * SUCH DAMAGE. 25179185Sjb * 26179185Sjb * $FreeBSD: head/lib/libproc/proc_create.c 224632 2011-08-03 09:55:59Z avg $ 27179185Sjb */ 28179185Sjb 29179185Sjb#include "_libproc.h" 30210688Srpaulo#include <stdio.h> 31179185Sjb#include <err.h> 32179185Sjb#include <errno.h> 33179185Sjb#include <fcntl.h> 34179185Sjb#include <limits.h> 35179185Sjb#include <stdlib.h> 36179185Sjb#include <string.h> 37179185Sjb#include <unistd.h> 38179185Sjb#include <sys/wait.h> 39179185Sjb 40179185Sjbint 41179185Sjbproc_attach(pid_t pid, int flags, struct proc_handle **pphdl) 42179185Sjb{ 43179185Sjb struct proc_handle *phdl; 44179185Sjb int error = 0; 45179185Sjb int status; 46179185Sjb 47210688Srpaulo if (pid == 0 || pid == getpid()) 48179185Sjb return (EINVAL); 49179185Sjb 50179185Sjb /* 51179185Sjb * Allocate memory for the process handle, a structure containing 52179185Sjb * all things related to the process. 53179185Sjb */ 54179185Sjb if ((phdl = malloc(sizeof(struct proc_handle))) == NULL) 55179185Sjb return (ENOMEM); 56179185Sjb 57179185Sjb memset(phdl, 0, sizeof(struct proc_handle)); 58179185Sjb phdl->pid = pid; 59179185Sjb phdl->flags = flags; 60179185Sjb phdl->status = PS_RUN; 61210688Srpaulo elf_version(EV_CURRENT); 62179185Sjb 63210688Srpaulo if (ptrace(PT_ATTACH, phdl->pid, 0, 0) != 0) { 64179185Sjb error = errno; 65210688Srpaulo DPRINTF("ERROR: cannot ptrace child process %d", pid); 66210688Srpaulo goto out; 67210688Srpaulo } 68179185Sjb 69179185Sjb /* Wait for the child process to stop. */ 70210688Srpaulo if (waitpid(pid, &status, WUNTRACED) == -1) { 71210688Srpaulo error = errno; 72210688Srpaulo DPRINTF("ERROR: child process %d didn't stop as expected", pid); 73210688Srpaulo goto out; 74210688Srpaulo } 75179185Sjb 76179185Sjb /* Check for an unexpected status. */ 77210688Srpaulo if (WIFSTOPPED(status) == 0) 78210688Srpaulo DPRINTF("ERROR: child process %d status 0x%x", pid, status); 79179185Sjb else 80179185Sjb phdl->status = PS_STOP; 81179185Sjb 82224632Savgout: 83179185Sjb if (error) 84179185Sjb proc_free(phdl); 85179185Sjb else 86179185Sjb *pphdl = phdl; 87179185Sjb return (error); 88179185Sjb} 89179185Sjb 90179185Sjbint 91184697Srodrigcproc_create(const char *file, char * const *argv, proc_child_func *pcf, 92184697Srodrigc void *child_arg, struct proc_handle **pphdl) 93179185Sjb{ 94179185Sjb struct proc_handle *phdl; 95179185Sjb int error = 0; 96179185Sjb int status; 97179185Sjb pid_t pid; 98179185Sjb 99179185Sjb /* 100179185Sjb * Allocate memory for the process handle, a structure containing 101179185Sjb * all things related to the process. 102179185Sjb */ 103179185Sjb if ((phdl = malloc(sizeof(struct proc_handle))) == NULL) 104179185Sjb return (ENOMEM); 105179185Sjb 106210688Srpaulo elf_version(EV_CURRENT); 107210688Srpaulo 108179185Sjb /* Fork a new process. */ 109184697Srodrigc if ((pid = vfork()) == -1) 110179185Sjb error = errno; 111179185Sjb else if (pid == 0) { 112179185Sjb /* The child expects to be traced. */ 113179185Sjb if (ptrace(PT_TRACE_ME, 0, 0, 0) != 0) 114179185Sjb _exit(1); 115179185Sjb 116184697Srodrigc if (pcf != NULL) 117184697Srodrigc (*pcf)(child_arg); 118184697Srodrigc 119179185Sjb /* Execute the specified file: */ 120179185Sjb execvp(file, argv); 121179185Sjb 122179185Sjb /* Couldn't execute the file. */ 123179185Sjb _exit(2); 124179185Sjb } else { 125179185Sjb /* The parent owns the process handle. */ 126179185Sjb memset(phdl, 0, sizeof(struct proc_handle)); 127179185Sjb phdl->pid = pid; 128179185Sjb phdl->status = PS_IDLE; 129179185Sjb 130179185Sjb /* Wait for the child process to stop. */ 131210688Srpaulo if (waitpid(pid, &status, WUNTRACED) == -1) { 132210688Srpaulo error = errno; 133210688Srpaulo DPRINTF("ERROR: child process %d didn't stop as expected", pid); 134210688Srpaulo goto bad; 135210688Srpaulo } 136179185Sjb 137179185Sjb /* Check for an unexpected status. */ 138210688Srpaulo if (WIFSTOPPED(status) == 0) { 139210688Srpaulo error = errno; 140210688Srpaulo DPRINTF("ERROR: child process %d status 0x%x", pid, status); 141210688Srpaulo goto bad; 142210688Srpaulo } else 143179185Sjb phdl->status = PS_STOP; 144179185Sjb } 145210688Srpaulobad: 146179185Sjb if (error) 147179185Sjb proc_free(phdl); 148179185Sjb else 149179185Sjb *pphdl = phdl; 150179185Sjb return (error); 151179185Sjb} 152179185Sjb 153179185Sjbvoid 154179185Sjbproc_free(struct proc_handle *phdl) 155179185Sjb{ 156179185Sjb free(phdl); 157179185Sjb} 158