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