8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libtnfctl / prb_child.c
blobe5d01a94e5937bc7d4f3a1b4ddd14bf90c3306f0
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright (c) 1994, by Sun Microsytems, Inc.
27 * interfaces to exec a command and run it till all loadobjects have
28 * been loaded (rtld sync point).
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <limits.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
39 #include "prb_proc_int.h"
40 #include "dbg.h"
43 * Defines
46 #define PRELOAD "LD_PRELOAD"
47 #define LIBPROBE "libtnfprobe.so.1"
50 * Local declarations
53 static prb_status_t sync_child(int pid, volatile shmem_msg_t *smp,
54 prb_proc_ctl_t **proc_pp);
57 * prb_child_create() - this routine instantiates and rendevous with the
58 * target child process. This routine returns an opaque handle for the
59 * childs /proc entry.
61 prb_status_t
62 prb_child_create(const char *cmdname, char * const *cmdargs,
63 const char *loption, const char *libtnfprobe_path,
64 char * const *envp, prb_proc_ctl_t **ret_val)
66 prb_status_t prbstat;
67 pid_t childpid;
68 char executable_name[PATH_MAX + 2];
69 extern char **environ;
70 char * const * env_to_use;
71 size_t loptlen, probepathlen;
72 volatile shmem_msg_t *smp;
74 /* initialize shmem communication buffer to cause child to wait */
75 prbstat = prb_shmem_init(&smp);
76 if (prbstat)
77 return (prbstat);
79 /* fork to create the child process */
80 childpid = fork();
81 if (childpid == (pid_t)-1) {
82 DBG(perror("prb_child_create: fork failed"));
83 return (prb_status_map(errno));
85 if (childpid == 0) {
86 char *oldenv;
87 char *newenv;
89 /* ---- CHILD PROCESS ---- */
91 DBG_TNF_PROBE_1(prb_child_create_1, "libtnfctl",
92 "sunw%verbosity 1; sunw%debug 'child process created'",
93 tnf_long, pid, getpid());
95 if (envp) {
96 env_to_use = envp;
97 goto ContChild;
100 /* append libtnfprobe.so to the LD_PRELOAD environment */
101 loptlen = (loption) ? strlen(loption) : 0;
102 /* probepathlen has a "/" added in ("+ 1") */
103 probepathlen = (libtnfprobe_path) ?
104 (strlen(libtnfprobe_path) + 1) : 0;
105 oldenv = getenv(PRELOAD);
106 if (oldenv) {
107 newenv = (char *)malloc(strlen(PRELOAD) +
108 1 + /* "=" */
109 strlen(oldenv) +
110 1 + /* " " */
111 probepathlen +
112 strlen(LIBPROBE) +
113 1 + /* " " */
114 loptlen +
115 1); /* NULL */
117 if (!newenv)
118 goto ContChild;
119 (void) strcpy(newenv, PRELOAD);
120 (void) strcat(newenv, "=");
121 (void) strcat(newenv, oldenv);
122 (void) strcat(newenv, " ");
123 if (probepathlen) {
124 (void) strcat(newenv, libtnfprobe_path);
125 (void) strcat(newenv, "/");
127 (void) strcat(newenv, LIBPROBE);
128 if (loptlen) {
129 (void) strcat(newenv, " ");
130 (void) strcat(newenv, loption);
132 } else {
133 newenv = (char *)malloc(strlen(PRELOAD) +
134 1 + /* "=" */
135 probepathlen +
136 strlen(LIBPROBE) +
137 1 + /* " " */
138 loptlen +
139 1); /* NULL */
140 if (!newenv)
141 goto ContChild;
142 (void) strcpy(newenv, PRELOAD);
143 (void) strcat(newenv, "=");
144 if (probepathlen) {
145 (void) strcat(newenv, libtnfprobe_path);
146 (void) strcat(newenv, "/");
148 (void) strcat(newenv, LIBPROBE);
149 if (loptlen) {
150 (void) strcat(newenv, " ");
151 (void) strcat(newenv, loption);
154 (void) putenv((char *)newenv);
155 env_to_use = environ;
157 * We don't check the return value of putenv because the
158 * desired libraries might already be in the target, even
159 * if our effort to change the environment fails. We
160 * should continue either way ...
162 ContChild:
163 /* wait until the parent releases us */
164 (void) prb_shmem_wait(smp);
166 DBG_TNF_PROBE_1(prb_child_create_2, "libtnfctl",
167 "sunw%verbosity 2; "
168 "sunw%debug 'child process about to exec'",
169 tnf_string, cmdname, cmdname);
172 * make the child it's own process group.
173 * This is so that signals delivered to parent are not
174 * also delivered to child.
176 (void) setpgrp();
177 prbstat = find_executable(cmdname, executable_name);
178 if (prbstat) {
179 DBG((void) fprintf(stderr, "prb_child_create: %s\n",
180 prb_status_str(prbstat)));
181 /* parent waits for exit */
182 _exit(1);
184 if (execve(executable_name, cmdargs, env_to_use) == -1) {
185 DBG(perror("prb_child_create: exec failed"));
186 _exit(1);
189 /* Never reached */
190 _exit(1);
192 /* ---- PARENT PROCESS ---- */
193 /* child is waiting for us */
195 prbstat = sync_child(childpid, smp, ret_val);
196 if (prbstat) {
197 return (prbstat);
200 return (PRB_STATUS_OK);
205 * interface that registers the address of the debug structure
206 * in the target process. This is where the linker maintains all
207 * the information about the loadobjects
209 void
210 prb_dbgaddr(prb_proc_ctl_t *proc_p, uintptr_t dbgaddr)
212 proc_p->dbgaddr = dbgaddr;
216 * continue the child until the run time linker has loaded in all
217 * the loadobjects (rtld sync point)
219 static prb_status_t
220 sync_child(int childpid, volatile shmem_msg_t *smp, prb_proc_ctl_t **proc_pp)
222 prb_proc_ctl_t *proc_p, *oldproc_p;
223 prb_status_t prbstat = PRB_STATUS_OK;
224 prb_status_t tempstat;
225 prb_proc_state_t pstate;
227 prbstat = prb_proc_open(childpid, proc_pp);
228 if (prbstat)
229 return (prbstat);
231 proc_p = *proc_pp;
233 prbstat = prb_proc_stop(proc_p);
234 if (prbstat)
235 goto ret_failure;
238 * default is to kill-on-last-close. In case we cannot sync with
239 * target, we don't want the target to continue.
241 prbstat = prb_proc_setrlc(proc_p, B_FALSE);
242 if (prbstat)
243 goto ret_failure;
245 prbstat = prb_proc_setklc(proc_p, B_TRUE);
246 if (prbstat)
247 goto ret_failure;
249 /* REMIND: do we have to wait on SYS_exec also ? */
250 prbstat = prb_proc_exit(proc_p, SYS_execve, PRB_SYS_ADD);
251 if (prbstat)
252 goto ret_failure;
254 prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_ADD);
255 if (prbstat)
256 goto ret_failure;
258 prbstat = prb_shmem_clear(smp);
259 if (prbstat)
260 goto ret_failure;
262 prbstat = prb_proc_cont(proc_p);
263 if (prbstat)
264 goto ret_failure;
266 prbstat = prb_proc_wait(proc_p, B_FALSE, NULL);
267 switch (prbstat) {
268 case PRB_STATUS_OK:
269 break;
270 case EAGAIN:
272 * If we had exec'ed a setuid/setgid program PIOCWSTOP
273 * will return EAGAIN. Reopen the 'fd' and try again.
274 * Read the last section of /proc man page - we reopen first
275 * and then close the old fd.
277 oldproc_p = proc_p;
278 tempstat = prb_proc_reopen(childpid, proc_pp);
279 proc_p = *proc_pp;
280 if (tempstat) {
281 /* here EACCES means exec'ed a setuid/setgid program */
282 (void) prb_proc_close(oldproc_p);
283 return (tempstat);
286 (void) prb_proc_close(oldproc_p);
287 break;
288 default:
289 goto ret_failure;
292 prbstat = prb_shmem_free(smp);
293 if (prbstat)
294 goto ret_failure;
296 prbstat = prb_proc_state(proc_p, &pstate);
297 if (prbstat)
298 goto ret_failure;
300 if (pstate.ps_issysexit && (pstate.ps_syscallnum == SYS_execve)) {
301 /* expected condition */
302 prbstat = PRB_STATUS_OK;
303 } else {
304 prbstat = prb_status_map(ENOENT);
305 goto ret_failure;
308 /* clear old interest mask */
309 prbstat = prb_proc_exit(proc_p, 0, PRB_SYS_NONE);
310 if (prbstat)
311 goto ret_failure;
313 prbstat = prb_proc_entry(proc_p, 0, PRB_SYS_NONE);
314 if (prbstat)
315 goto ret_failure;
317 /* Successful return */
318 return (PRB_STATUS_OK);
320 ret_failure:
321 (void) prb_proc_close(proc_p);
322 return (prbstat);