proc_create.c revision 179185
150477Speter/*- 281077Speter * Copyright (c) 2008 John Birrell (jb@freebsd.org) 341199Skato * All rights reserved. 433080Skato * 541199Skato * Redistribution and use in source and binary forms, with or without 616359Sasami * modification, are permitted provided that the following conditions 716359Sasami * are met: 834458Skato * 1. Redistributions of source code must retain the above copyright 955966Skato * notice, this list of conditions and the following disclaimer. 1044082Skato * 2. Redistributions in binary form must reproduce the above copyright 1129006Skato * notice, this list of conditions and the following disclaimer in the 1229006Skato * documentation and/or other materials provided with the distribution. 1329006Skato * 1416359Sasami * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1532939Skato * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1616359Sasami * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1716359Sasami * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1826477Skato * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1932092Skato * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2027844Skato * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2127844Skato * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2258287Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2361628Skato * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2483366Sjulian * SUCH DAMAGE. 2517256Sasami * 2655656Sbde * $FreeBSD: head/lib/libproc/proc_create.c 179185 2008-05-22 02:09:21Z jb $ 2755656Sbde */ 2855656Sbde 2955656Sbde#include "_libproc.h" 3055656Sbde#include <err.h> 3155656Sbde#include <errno.h> 3255656Sbde#include <fcntl.h> 3355656Sbde#include <limits.h> 3470264Skato#include <stdlib.h> 3570264Skato#include <string.h> 3641975Skato#include <unistd.h> 3725572Skato#include <sys/wait.h> 3825195Skato 3933080Skatoint 4033080Skatoproc_attach(pid_t pid, int flags, struct proc_handle **pphdl) 4133080Skato{ 4244633Skato struct proc_handle *phdl; 4318208Sasami struct kevent kev; 4431556Skato int error = 0; 4527392Skato int status; 4627392Skato 4733019Skato if (pid == 0 || pphdl == NULL) 4847976Skato return (EINVAL); 4927391Skato 5033019Skato /* 5133019Skato * Allocate memory for the process handle, a structure containing 5233019Skato * all things related to the process. 5333019Skato */ 5461616Skato if ((phdl = malloc(sizeof(struct proc_handle))) == NULL) 5533019Skato return (ENOMEM); 5661616Skato 5733019Skato memset(phdl, 0, sizeof(struct proc_handle)); 5833019Skato phdl->pid = pid; 5933019Skato phdl->flags = flags; 6040003Skato phdl->status = PS_RUN; 6133019Skato 6233019Skato EV_SET(&kev, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 6342163Skato 0, NULL); 6479699Snyan 6519122Sasami if ((phdl->kq = kqueue()) == -1) 6629006Skato err(1, "ERROR: cannot create kernel evet queue"); 6729006Skato 6829006Skato if (kevent(phdl->kq, &kev, 1, NULL, 0, NULL) < 0) 6929006Skato err(2, "ERROR: cannot monitor child process %d", pid); 7029006Skato 7129006Skato if (ptrace(PT_ATTACH, phdl->pid, NULL, 0) != 0) 7218265Sasami error = errno; 7348175Skato 7448175Skato /* Wait for the child process to stop. */ 7548175Skato else if (waitpid(pid, &status, WUNTRACED) == -1) 7648175Skato err(3, "ERROR: child process %d didn't stop as expected", pid); 7748175Skato 7829137Skato /* Check for an unexpected status. */ 7953053Snyan else if (WIFSTOPPED(status) == 0) 8053053Snyan err(4, "ERROR: child process %d status 0x%x", pid, status); 8133270Skato else 8248175Skato phdl->status = PS_STOP; 8348175Skato 8448175Skato if (error) 8548175Skato proc_free(phdl); 8653053Snyan else 8753053Snyan *pphdl = phdl; 8848175Skato 8948175Skato return (error); 9053053Snyan} 9118208Sasami 9242795Skatoint 9342795Skatoproc_create(const char *file, char * const *argv, struct proc_handle **pphdl) 9454880Skato{ 9527173Skato struct proc_handle *phdl; 9621773Skato struct kevent kev; 9721773Skato int error = 0; 9839002Skato int status; 9939002Skato pid_t pid; 10044635Skato 10142795Skato /* 10242795Skato * Allocate memory for the process handle, a structure containing 10342795Skato * all things related to the process. 10442795Skato */ 10542795Skato if ((phdl = malloc(sizeof(struct proc_handle))) == NULL) 10621773Skato return (ENOMEM); 10778135Speter 10878135Speter /* Fork a new process. */ 10978135Speter if ((pid = fork()) == -1) 11078135Speter error = errno; 11123847Skato else if (pid == 0) { 11223847Skato /* The child expects to be traced. */ 11329533Skato if (ptrace(PT_TRACE_ME, 0, 0, 0) != 0) 11442283Skato _exit(1); 11542283Skato 11642283Skato /* Execute the specified file: */ 11742283Skato execvp(file, argv); 11842283Skato 11942283Skato /* Couldn't execute the file. */ 12042283Skato _exit(2); 12142283Skato } else { 12242283Skato /* The parent owns the process handle. */ 12342283Skato memset(phdl, 0, sizeof(struct proc_handle)); 12442283Skato phdl->pid = pid; 12542283Skato phdl->status = PS_IDLE; 12658887Skato 12742283Skato EV_SET(&kev, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 12842283Skato 0, NULL); 12942283Skato 13042283Skato if ((phdl->kq = kqueue()) == -1) 13142283Skato err(1, "ERROR: cannot create kernel evet queue"); 13242283Skato 13338225Skato if (kevent(phdl->kq, &kev, 1, NULL, 0, NULL) < 0) 13438225Skato err(2, "ERROR: cannot monitor child process %d", pid); 13549522Skato 13642163Skato /* Wait for the child process to stop. */ 13742163Skato if (waitpid(pid, &status, WUNTRACED) == -1) 13842163Skato err(3, "ERROR: child process %d didn't stop as expected", pid); 13942163Skato 14042163Skato /* Check for an unexpected status. */ 14142163Skato if (WIFSTOPPED(status) == 0) 14242163Skato err(4, "ERROR: child process %d status 0x%x", pid, status); 14342163Skato else 14466916Skato phdl->status = PS_STOP; 14549522Skato } 14642163Skato 14742163Skato if (error) 14842163Skato proc_free(phdl); 14942163Skato else 15042163Skato *pphdl = phdl; 15142163Skato 15242163Skato return (error); 15366916Skato} 15449522Skato 15542163Skatovoid 15649522Skatoproc_free(struct proc_handle *phdl) 15775051Snyan{ 15842163Skato free(phdl); 15942163Skato} 16042163Skato