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$ 27179185Sjb */ 28179185Sjb 29270731Smarkj#include <sys/types.h> 30270731Smarkj#include <sys/sysctl.h> 31270731Smarkj#include <sys/wait.h> 32270731Smarkj 33179185Sjb#include <err.h> 34179185Sjb#include <errno.h> 35179185Sjb#include <fcntl.h> 36179185Sjb#include <limits.h> 37179185Sjb#include <stdlib.h> 38179185Sjb#include <string.h> 39179185Sjb#include <unistd.h> 40179185Sjb 41270731Smarkj#include "_libproc.h" 42270731Smarkj 43270731Smarkjstatic int proc_init(pid_t, int, int, struct proc_handle *); 44270731Smarkj 45270731Smarkjstatic int 46270731Smarkjproc_init(pid_t pid, int flags, int status, struct proc_handle *phdl) 47270731Smarkj{ 48270731Smarkj int mib[4], error; 49270731Smarkj size_t len; 50270731Smarkj 51270731Smarkj memset(phdl, 0, sizeof(*phdl)); 52270731Smarkj phdl->pid = pid; 53270731Smarkj phdl->flags = flags; 54270731Smarkj phdl->status = status; 55270731Smarkj 56270731Smarkj mib[0] = CTL_KERN; 57270731Smarkj mib[1] = KERN_PROC; 58270731Smarkj mib[2] = KERN_PROC_PATHNAME; 59270731Smarkj mib[3] = pid; 60270731Smarkj len = sizeof(phdl->execname); 61270731Smarkj if (sysctl(mib, 4, phdl->execname, &len, NULL, 0) != 0) { 62270731Smarkj error = errno; 63270731Smarkj DPRINTF("ERROR: cannot get pathname for child process %d", pid); 64270731Smarkj return (error); 65270731Smarkj } 66270731Smarkj if (len == 0) 67270731Smarkj phdl->execname[0] = '\0'; 68270731Smarkj 69270731Smarkj return (0); 70270731Smarkj} 71270731Smarkj 72179185Sjbint 73179185Sjbproc_attach(pid_t pid, int flags, struct proc_handle **pphdl) 74179185Sjb{ 75179185Sjb struct proc_handle *phdl; 76179185Sjb int error = 0; 77179185Sjb int status; 78179185Sjb 79210688Srpaulo if (pid == 0 || pid == getpid()) 80179185Sjb return (EINVAL); 81179185Sjb 82179185Sjb /* 83179185Sjb * Allocate memory for the process handle, a structure containing 84179185Sjb * all things related to the process. 85179185Sjb */ 86179185Sjb if ((phdl = malloc(sizeof(struct proc_handle))) == NULL) 87179185Sjb return (ENOMEM); 88179185Sjb 89210688Srpaulo elf_version(EV_CURRENT); 90179185Sjb 91270731Smarkj error = proc_init(pid, flags, PS_RUN, phdl); 92270731Smarkj if (error != 0) 93270731Smarkj goto out; 94270731Smarkj 95210688Srpaulo if (ptrace(PT_ATTACH, phdl->pid, 0, 0) != 0) { 96179185Sjb error = errno; 97210688Srpaulo DPRINTF("ERROR: cannot ptrace child process %d", pid); 98210688Srpaulo goto out; 99210688Srpaulo } 100179185Sjb 101179185Sjb /* Wait for the child process to stop. */ 102210688Srpaulo if (waitpid(pid, &status, WUNTRACED) == -1) { 103210688Srpaulo error = errno; 104210688Srpaulo DPRINTF("ERROR: child process %d didn't stop as expected", pid); 105210688Srpaulo goto out; 106210688Srpaulo } 107179185Sjb 108179185Sjb /* Check for an unexpected status. */ 109210688Srpaulo if (WIFSTOPPED(status) == 0) 110259895Smarkj DPRINTFX("ERROR: child process %d status 0x%x", pid, status); 111179185Sjb else 112179185Sjb phdl->status = PS_STOP; 113179185Sjb 114224632Savgout: 115179185Sjb if (error) 116179185Sjb proc_free(phdl); 117179185Sjb else 118179185Sjb *pphdl = phdl; 119179185Sjb return (error); 120179185Sjb} 121179185Sjb 122179185Sjbint 123184697Srodrigcproc_create(const char *file, char * const *argv, proc_child_func *pcf, 124184697Srodrigc void *child_arg, struct proc_handle **pphdl) 125179185Sjb{ 126179185Sjb struct proc_handle *phdl; 127179185Sjb int error = 0; 128179185Sjb int status; 129179185Sjb pid_t pid; 130179185Sjb 131179185Sjb /* 132179185Sjb * Allocate memory for the process handle, a structure containing 133179185Sjb * all things related to the process. 134179185Sjb */ 135179185Sjb if ((phdl = malloc(sizeof(struct proc_handle))) == NULL) 136179185Sjb return (ENOMEM); 137179185Sjb 138210688Srpaulo elf_version(EV_CURRENT); 139210688Srpaulo 140179185Sjb /* Fork a new process. */ 141184697Srodrigc if ((pid = vfork()) == -1) 142179185Sjb error = errno; 143179185Sjb else if (pid == 0) { 144179185Sjb /* The child expects to be traced. */ 145179185Sjb if (ptrace(PT_TRACE_ME, 0, 0, 0) != 0) 146179185Sjb _exit(1); 147179185Sjb 148184697Srodrigc if (pcf != NULL) 149184697Srodrigc (*pcf)(child_arg); 150184697Srodrigc 151179185Sjb /* Execute the specified file: */ 152179185Sjb execvp(file, argv); 153179185Sjb 154179185Sjb /* Couldn't execute the file. */ 155179185Sjb _exit(2); 156179185Sjb } else { 157179185Sjb /* The parent owns the process handle. */ 158270731Smarkj error = proc_init(pid, 0, PS_IDLE, phdl); 159270731Smarkj if (error != 0) 160270731Smarkj goto bad; 161179185Sjb 162179185Sjb /* Wait for the child process to stop. */ 163210688Srpaulo if (waitpid(pid, &status, WUNTRACED) == -1) { 164210688Srpaulo error = errno; 165259895Smarkj DPRINTF("ERROR: child process %d didn't stop as expected", pid); 166210688Srpaulo goto bad; 167210688Srpaulo } 168179185Sjb 169179185Sjb /* Check for an unexpected status. */ 170210688Srpaulo if (WIFSTOPPED(status) == 0) { 171210688Srpaulo error = errno; 172259895Smarkj DPRINTFX("ERROR: child process %d status 0x%x", pid, status); 173210688Srpaulo goto bad; 174210688Srpaulo } else 175179185Sjb phdl->status = PS_STOP; 176179185Sjb } 177210688Srpaulobad: 178179185Sjb if (error) 179179185Sjb proc_free(phdl); 180179185Sjb else 181179185Sjb *pphdl = phdl; 182179185Sjb return (error); 183179185Sjb} 184179185Sjb 185179185Sjbvoid 186179185Sjbproc_free(struct proc_handle *phdl) 187179185Sjb{ 188179185Sjb free(phdl); 189179185Sjb} 190