1 1.1 christos /*- 2 1.1 christos * Copyright (c) 2008 John Birrell (jb (at) freebsd.org) 3 1.1 christos * All rights reserved. 4 1.1 christos * 5 1.1 christos * Redistribution and use in source and binary forms, with or without 6 1.1 christos * modification, are permitted provided that the following conditions 7 1.1 christos * are met: 8 1.1 christos * 1. Redistributions of source code must retain the above copyright 9 1.1 christos * notice, this list of conditions and the following disclaimer. 10 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright 11 1.1 christos * notice, this list of conditions and the following disclaimer in the 12 1.1 christos * documentation and/or other materials provided with the distribution. 13 1.1 christos * 14 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 1.1 christos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 1.1 christos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 1.1 christos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 1.1 christos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 1.1 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 1.1 christos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 1.1 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 1.1 christos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 1.1 christos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 1.1 christos * SUCH DAMAGE. 25 1.1 christos * 26 1.1 christos * $FreeBSD: head/lib/libproc/proc_create.c 265255 2014-05-03 04:44:03Z markj $ 27 1.1 christos */ 28 1.2 christos #include <sys/cdefs.h> 29 1.3 chs __RCSID("$NetBSD: proc_create.c,v 1.3 2017/06/09 01:17:25 chs Exp $"); 30 1.1 christos 31 1.1 christos #include <sys/types.h> 32 1.1 christos #include <sys/sysctl.h> 33 1.1 christos #include <sys/wait.h> 34 1.1 christos 35 1.1 christos #include <err.h> 36 1.1 christos #include <errno.h> 37 1.1 christos #include <fcntl.h> 38 1.1 christos #include <limits.h> 39 1.1 christos #include <stdlib.h> 40 1.1 christos #include <string.h> 41 1.1 christos #include <unistd.h> 42 1.1 christos 43 1.1 christos #include "_libproc.h" 44 1.1 christos 45 1.1 christos static int proc_init(pid_t, int, int, struct proc_handle *); 46 1.1 christos 47 1.1 christos static int 48 1.1 christos proc_init(pid_t pid, int flags, int status, struct proc_handle *phdl) 49 1.1 christos { 50 1.3 chs struct kinfo_proc2 kp; 51 1.3 chs int mib[6], error; 52 1.1 christos size_t len; 53 1.1 christos 54 1.1 christos memset(phdl, 0, sizeof(*phdl)); 55 1.1 christos phdl->pid = pid; 56 1.1 christos phdl->flags = flags; 57 1.1 christos phdl->status = status; 58 1.1 christos 59 1.1 christos mib[0] = CTL_KERN; 60 1.2 christos mib[1] = KERN_PROC_ARGS; 61 1.2 christos mib[2] = pid; 62 1.2 christos mib[3] = KERN_PROC_PATHNAME; 63 1.1 christos len = sizeof(phdl->execname); 64 1.1 christos if (sysctl(mib, 4, phdl->execname, &len, NULL, 0) != 0) { 65 1.1 christos error = errno; 66 1.1 christos DPRINTF("ERROR: cannot get pathname for child process %d", pid); 67 1.1 christos return (error); 68 1.1 christos } 69 1.1 christos if (len == 0) 70 1.1 christos phdl->execname[0] = '\0'; 71 1.1 christos 72 1.3 chs #ifdef _LP64 73 1.3 chs len = sizeof(kp); 74 1.3 chs mib[0] = CTL_KERN; 75 1.3 chs mib[1] = KERN_PROC2; 76 1.3 chs mib[2] = KERN_PROC_PID; 77 1.3 chs mib[3] = pid; 78 1.3 chs mib[4] = len; 79 1.3 chs mib[5] = 1; 80 1.3 chs if (sysctl(mib, 6, &kp, &len, NULL, 0) != 0) { 81 1.3 chs error = errno; 82 1.3 chs DPRINTF("ERROR: cannot get kinfo_proc2 for pid %d", pid); 83 1.3 chs return (error); 84 1.3 chs } 85 1.3 chs phdl->model = (kp.p_flag & P_32) ? PR_MODEL_ILP32 : PR_MODEL_LP64; 86 1.3 chs #else 87 1.3 chs phdl->model = PR_MODEL_ILP32; 88 1.3 chs #endif 89 1.3 chs 90 1.1 christos return (0); 91 1.1 christos } 92 1.1 christos 93 1.1 christos int 94 1.1 christos proc_attach(pid_t pid, int flags, struct proc_handle **pphdl) 95 1.1 christos { 96 1.1 christos struct proc_handle *phdl; 97 1.1 christos int error = 0; 98 1.1 christos int status; 99 1.1 christos 100 1.1 christos if (pid == 0 || pid == getpid()) 101 1.1 christos return (EINVAL); 102 1.1 christos 103 1.1 christos /* 104 1.1 christos * Allocate memory for the process handle, a structure containing 105 1.1 christos * all things related to the process. 106 1.1 christos */ 107 1.1 christos if ((phdl = malloc(sizeof(struct proc_handle))) == NULL) 108 1.1 christos return (ENOMEM); 109 1.1 christos 110 1.1 christos elf_version(EV_CURRENT); 111 1.1 christos 112 1.1 christos error = proc_init(pid, flags, PS_RUN, phdl); 113 1.1 christos if (error != 0) 114 1.1 christos goto out; 115 1.1 christos 116 1.1 christos if (ptrace(PT_ATTACH, phdl->pid, 0, 0) != 0) { 117 1.1 christos error = errno; 118 1.1 christos DPRINTF("ERROR: cannot ptrace child process %d", pid); 119 1.1 christos goto out; 120 1.1 christos } 121 1.1 christos 122 1.1 christos /* Wait for the child process to stop. */ 123 1.1 christos if (waitpid(pid, &status, WUNTRACED) == -1) { 124 1.1 christos error = errno; 125 1.1 christos DPRINTF("ERROR: child process %d didn't stop as expected", pid); 126 1.1 christos goto out; 127 1.1 christos } 128 1.1 christos 129 1.1 christos /* Check for an unexpected status. */ 130 1.1 christos if (WIFSTOPPED(status) == 0) 131 1.1 christos DPRINTFX("ERROR: child process %d status 0x%x", pid, status); 132 1.1 christos else 133 1.1 christos phdl->status = PS_STOP; 134 1.1 christos 135 1.1 christos out: 136 1.1 christos if (error) 137 1.1 christos proc_free(phdl); 138 1.1 christos else 139 1.1 christos *pphdl = phdl; 140 1.1 christos return (error); 141 1.1 christos } 142 1.1 christos 143 1.1 christos int 144 1.1 christos proc_create(const char *file, char * const *argv, proc_child_func *pcf, 145 1.1 christos void *child_arg, struct proc_handle **pphdl) 146 1.1 christos { 147 1.1 christos struct proc_handle *phdl; 148 1.1 christos int error = 0; 149 1.1 christos int status; 150 1.1 christos pid_t pid; 151 1.1 christos 152 1.1 christos /* 153 1.1 christos * Allocate memory for the process handle, a structure containing 154 1.1 christos * all things related to the process. 155 1.1 christos */ 156 1.1 christos if ((phdl = malloc(sizeof(struct proc_handle))) == NULL) 157 1.1 christos return (ENOMEM); 158 1.1 christos 159 1.1 christos elf_version(EV_CURRENT); 160 1.1 christos 161 1.1 christos /* Fork a new process. */ 162 1.1 christos if ((pid = vfork()) == -1) 163 1.1 christos error = errno; 164 1.1 christos else if (pid == 0) { 165 1.1 christos /* The child expects to be traced. */ 166 1.1 christos if (ptrace(PT_TRACE_ME, 0, 0, 0) != 0) 167 1.1 christos _exit(1); 168 1.1 christos 169 1.1 christos if (pcf != NULL) 170 1.1 christos (*pcf)(child_arg); 171 1.1 christos 172 1.1 christos /* Execute the specified file: */ 173 1.1 christos execvp(file, argv); 174 1.1 christos 175 1.1 christos /* Couldn't execute the file. */ 176 1.1 christos _exit(2); 177 1.1 christos } else { 178 1.1 christos /* The parent owns the process handle. */ 179 1.1 christos error = proc_init(pid, 0, PS_IDLE, phdl); 180 1.1 christos if (error != 0) 181 1.1 christos goto bad; 182 1.1 christos 183 1.1 christos /* Wait for the child process to stop. */ 184 1.1 christos if (waitpid(pid, &status, WUNTRACED) == -1) { 185 1.1 christos error = errno; 186 1.1 christos DPRINTF("ERROR: child process %d didn't stop as expected", pid); 187 1.1 christos goto bad; 188 1.1 christos } 189 1.1 christos 190 1.1 christos /* Check for an unexpected status. */ 191 1.1 christos if (WIFSTOPPED(status) == 0) { 192 1.1 christos error = errno; 193 1.1 christos DPRINTFX("ERROR: child process %d status 0x%x", pid, status); 194 1.1 christos goto bad; 195 1.1 christos } else 196 1.1 christos phdl->status = PS_STOP; 197 1.1 christos } 198 1.1 christos bad: 199 1.1 christos if (error) 200 1.1 christos proc_free(phdl); 201 1.1 christos else 202 1.1 christos *pphdl = phdl; 203 1.1 christos return (error); 204 1.1 christos } 205 1.1 christos 206 1.1 christos void 207 1.1 christos proc_free(struct proc_handle *phdl) 208 1.1 christos { 209 1.1 christos free(phdl); 210 1.1 christos } 211