1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "apr_arch_threadproc.h" 18#include "apr_strings.h" 19 20/* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE 21 * requested for a specific child handle; 22 */ 23static apr_file_t no_file = { NULL, -1, }; 24 25struct send_pipe { 26 int in; 27 int out; 28 int err; 29}; 30 31APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new, apr_pool_t *pool) 32{ 33 (*new) = (apr_procattr_t *)apr_palloc(pool, 34 sizeof(apr_procattr_t)); 35 36 if ((*new) == NULL) { 37 return APR_ENOMEM; 38 } 39 (*new)->pool = pool; 40 (*new)->parent_in = NULL; 41 (*new)->child_in = NULL; 42 (*new)->parent_out = NULL; 43 (*new)->child_out = NULL; 44 (*new)->parent_err = NULL; 45 (*new)->child_err = NULL; 46 (*new)->currdir = NULL; 47 (*new)->cmdtype = APR_PROGRAM; 48 (*new)->detached = 0; 49 return APR_SUCCESS; 50} 51 52APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, 53 apr_int32_t in, 54 apr_int32_t out, 55 apr_int32_t err) 56{ 57 apr_status_t rv; 58 59 if ((in != APR_NO_PIPE) && (in != APR_NO_FILE)) { 60 /* APR_CHILD_BLOCK maps to APR_WRITE_BLOCK, while 61 * APR_PARENT_BLOCK maps to APR_READ_BLOCK, so transpose 62 * the CHILD/PARENT blocking flags for the stdin pipe. 63 * stdout/stderr map to the correct mode by default. 64 */ 65 if (in == APR_CHILD_BLOCK) 66 in = APR_READ_BLOCK; 67 else if (in == APR_PARENT_BLOCK) 68 in = APR_WRITE_BLOCK; 69 70 if ((rv = apr_file_pipe_create_ex(&attr->child_in, &attr->parent_in, 71 in, attr->pool)) == APR_SUCCESS) 72 rv = apr_file_inherit_unset(attr->parent_in); 73 if (rv != APR_SUCCESS) 74 return rv; 75 } 76 else if (in == APR_NO_FILE) 77 attr->child_in = &no_file; 78 79 if ((out != APR_NO_PIPE) && (out != APR_NO_FILE)) { 80 if ((rv = apr_file_pipe_create_ex(&attr->parent_out, &attr->child_out, 81 out, attr->pool)) == APR_SUCCESS) 82 rv = apr_file_inherit_unset(attr->parent_out); 83 if (rv != APR_SUCCESS) 84 return rv; 85 } 86 else if (out == APR_NO_FILE) 87 attr->child_out = &no_file; 88 89 if ((err != APR_NO_PIPE) && (err != APR_NO_FILE)) { 90 if ((rv = apr_file_pipe_create_ex(&attr->parent_err, &attr->child_err, 91 err, attr->pool)) == APR_SUCCESS) 92 rv = apr_file_inherit_unset(attr->parent_err); 93 if (rv != APR_SUCCESS) 94 return rv; 95 } 96 else if (err == APR_NO_FILE) 97 attr->child_err = &no_file; 98 99 return APR_SUCCESS; 100} 101 102APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr, 103 const char *dir) 104{ 105 char * cwd; 106 if (dir[0] != '/') { 107 cwd = (char*)malloc(sizeof(char) * PATH_MAX); 108 getcwd(cwd, PATH_MAX); 109 attr->currdir = (char *)apr_pstrcat(attr->pool, cwd, "/", dir, NULL); 110 free(cwd); 111 } else { 112 attr->currdir = (char *)apr_pstrdup(attr->pool, dir); 113 } 114 if (attr->currdir) { 115 return APR_SUCCESS; 116 } 117 return APR_ENOMEM; 118} 119 120APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr, 121 apr_cmdtype_e cmd) 122{ 123 attr->cmdtype = cmd; 124 return APR_SUCCESS; 125} 126 127APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, apr_int32_t detach) 128{ 129 attr->detached = detach; 130 return APR_SUCCESS; 131} 132 133APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool) 134{ 135 int pid; 136 137 if ((pid = fork()) < 0) { 138 return errno; 139 } 140 else if (pid == 0) { 141 /* This is really ugly... 142 * The semantics of BeOS's fork() are that areas (used for shared 143 * memory) get COW'd :-( The only way we can make shared memory 144 * work across fork() is therefore to find any areas that have 145 * been created and then clone them into our address space. 146 * Thankfully only COW'd areas have the lock variable set at 147 * anything but 0, so we can use that to find the areas we need to 148 * copy. Of course what makes it even worse is that the loop through 149 * the area's will go into an infinite loop, eating memory and then 150 * eventually segfault unless we know when we reach then end of the 151 * "original" areas and stop. Why? Well, we delete the area and then 152 * add another to the end of the list... 153 */ 154 area_info ai; 155 int32 cookie = 0; 156 area_id highest = 0; 157 158 while (get_next_area_info(0, &cookie, &ai) == B_OK) 159 if (ai.area > highest) 160 highest = ai.area; 161 cookie = 0; 162 while (get_next_area_info(0, &cookie, &ai) == B_OK) { 163 if (ai.area > highest) 164 break; 165 if (ai.lock > 0) { 166 area_id original = find_area(ai.name); 167 delete_area(ai.area); 168 clone_area(ai.name, &ai.address, B_CLONE_ADDRESS, 169 ai.protection, original); 170 } 171 } 172 173 proc->pid = pid; 174 proc->in = NULL; 175 proc->out = NULL; 176 proc->err = NULL; 177 return APR_INCHILD; 178 } 179 proc->pid = pid; 180 proc->in = NULL; 181 proc->out = NULL; 182 proc->err = NULL; 183 return APR_INPARENT; 184} 185 186APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr, 187 apr_child_errfn_t *errfn) 188{ 189 /* won't ever be called on this platform, so don't save the function pointer */ 190 return APR_SUCCESS; 191} 192 193APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr, 194 apr_int32_t chk) 195{ 196 /* won't ever be used on this platform, so don't save the flag */ 197 return APR_SUCCESS; 198} 199 200APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr, 201 apr_int32_t addrspace) 202{ 203 /* won't ever be used on this platform, so don't save the flag */ 204 return APR_SUCCESS; 205} 206 207APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, const char *progname, 208 const char * const *args, 209 const char * const *env, 210 apr_procattr_t *attr, 211 apr_pool_t *pool) 212{ 213 int i=0,nargs=0; 214 char **newargs = NULL; 215 thread_id newproc, sender; 216 struct send_pipe *sp; 217 char * dir = NULL; 218 219 sp = (struct send_pipe *)apr_palloc(pool, sizeof(struct send_pipe)); 220 221 new->in = attr->parent_in; 222 new->err = attr->parent_err; 223 new->out = attr->parent_out; 224 sp->in = attr->child_in ? attr->child_in->filedes : FILENO_STDIN; 225 sp->out = attr->child_out ? attr->child_out->filedes : FILENO_STDOUT; 226 sp->err = attr->child_err ? attr->child_err->filedes : FILENO_STDERR; 227 228 i = 0; 229 while (args && args[i]) { 230 i++; 231 } 232 233 newargs = (char**)malloc(sizeof(char *) * (i + 4)); 234 newargs[0] = strdup("/boot/home/config/bin/apr_proc_stub"); 235 if (attr->currdir == NULL) { 236 /* we require the directory , so use a temp. variable */ 237 dir = malloc(sizeof(char) * PATH_MAX); 238 getcwd(dir, PATH_MAX); 239 newargs[1] = strdup(dir); 240 free(dir); 241 } else { 242 newargs[1] = strdup(attr->currdir); 243 } 244 newargs[2] = strdup(progname); 245 i=0;nargs = 3; 246 247 while (args && args[i]) { 248 newargs[nargs] = strdup(args[i]); 249 i++;nargs++; 250 } 251 newargs[nargs] = NULL; 252 253 /* ### we should be looking at attr->cmdtype in here... */ 254 255 newproc = load_image(nargs, (const char**)newargs, (const char**)env); 256 257 /* load_image copies the data so now we can free it... */ 258 while (--nargs >= 0) 259 free (newargs[nargs]); 260 free(newargs); 261 262 if (newproc < B_NO_ERROR) { 263 return errno; 264 } 265 266 resume_thread(newproc); 267 268 if (attr->child_in && (attr->child_in->filedes != -1)) { 269 apr_file_close(attr->child_in); 270 } 271 if (attr->child_out && (attr->child_in->filedes != -1)) { 272 apr_file_close(attr->child_out); 273 } 274 if (attr->child_err && (attr->child_in->filedes != -1)) { 275 apr_file_close(attr->child_err); 276 } 277 278 send_data(newproc, 0, (void*)sp, sizeof(struct send_pipe)); 279 new->pid = newproc; 280 281 /* before we go charging on we need the new process to get to a 282 * certain point. When it gets there it'll let us know and we 283 * can carry on. */ 284 receive_data(&sender, (void*)NULL,0); 285 286 return APR_SUCCESS; 287} 288 289APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc, 290 int *exitcode, 291 apr_exit_why_e *exitwhy, 292 apr_wait_how_e waithow, 293 apr_pool_t *p) 294{ 295 proc->pid = -1; 296 return apr_proc_wait(proc, exitcode, exitwhy, waithow); 297} 298 299APR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc, 300 int *exitcode, 301 apr_exit_why_e *exitwhy, 302 apr_wait_how_e waithow) 303{ 304 pid_t pstatus; 305 int waitpid_options = WUNTRACED; 306 int exit_int; 307 int ignore; 308 apr_exit_why_e ignorewhy; 309 310 if (exitcode == NULL) { 311 exitcode = &ignore; 312 } 313 if (exitwhy == NULL) { 314 exitwhy = &ignorewhy; 315 } 316 317 if (waithow != APR_WAIT) { 318 waitpid_options |= WNOHANG; 319 } 320 321 if ((pstatus = waitpid(proc->pid, &exit_int, waitpid_options)) > 0) { 322 proc->pid = pstatus; 323 if (WIFEXITED(exit_int)) { 324 *exitwhy = APR_PROC_EXIT; 325 *exitcode = WEXITSTATUS(exit_int); 326 } 327 else if (WIFSIGNALED(exit_int)) { 328 *exitwhy = APR_PROC_SIGNAL; 329 *exitcode = WTERMSIG(exit_int); 330 } 331 else { 332 333 /* unexpected condition */ 334 return APR_EGENERAL; 335 } 336 return APR_CHILD_DONE; 337 } 338 else if (pstatus == 0) { 339 return APR_CHILD_NOTDONE; 340 } 341 342 return errno; 343} 344 345APR_DECLARE(apr_status_t) apr_procattr_child_in_set(apr_procattr_t *attr, apr_file_t *child_in, 346 apr_file_t *parent_in) 347{ 348 apr_status_t rv; 349 350 if (attr->child_in == NULL && attr->parent_in == NULL 351 && child_in == NULL && parent_in == NULL) 352 if ((rv = apr_file_pipe_create(&attr->child_in, &attr->parent_in, 353 attr->pool)) == APR_SUCCESS) 354 rv = apr_file_inherit_unset(attr->parent_in); 355 356 if (child_in != NULL && rv == APR_SUCCESS) { 357 if (attr->child_in && (attr->child_in->filedes != -1)) 358 rv = apr_file_dup2(attr->child_in, child_in, attr->pool); 359 else { 360 attr->child_in = NULL; 361 if ((rv = apr_file_dup(&attr->child_in, child_in, attr->pool)) 362 == APR_SUCCESS) 363 rv = apr_file_inherit_set(attr->child_in); 364 } 365 } 366 367 if (parent_in != NULL && rv == APR_SUCCESS) 368 rv = apr_file_dup(&attr->parent_in, parent_in, attr->pool); 369 370 return rv; 371} 372 373APR_DECLARE(apr_status_t) apr_procattr_child_out_set(apr_procattr_t *attr, apr_file_t *child_out, 374 apr_file_t *parent_out) 375{ 376 apr_status_t rv; 377 378 if (attr->child_out == NULL && attr->parent_out == NULL 379 && child_out == NULL && parent_out == NULL) 380 if ((rv = apr_file_pipe_create(&attr->parent_out, &attr->child_out, 381 attr->pool)) == APR_SUCCESS) 382 rv = apr_file_inherit_unset(attr->parent_out); 383 384 if (child_out != NULL && rv == APR_SUCCESS) { 385 if (attr->child_out && (attr->child_out->filedes != -1)) 386 rv = apr_file_dup2(attr->child_out, child_out, attr->pool); 387 else { 388 attr->child_out = NULL; 389 if ((rv = apr_file_dup(&attr->child_out, child_out, attr->pool)) 390 == APR_SUCCESS) 391 rv = apr_file_inherit_set(attr->child_out); 392 } 393 } 394 395 if (parent_out != NULL && rv == APR_SUCCESS) 396 rv = apr_file_dup(&attr->parent_out, parent_out, attr->pool); 397 398 return rv; 399} 400 401APR_DECLARE(apr_status_t) apr_procattr_child_err_set(apr_procattr_t *attr, apr_file_t *child_err, 402 apr_file_t *parent_err) 403{ 404 apr_status_t rv; 405 406 if (attr->child_err == NULL && attr->parent_err == NULL 407 && child_err == NULL && parent_err == NULL) 408 if ((rv = apr_file_pipe_create(&attr->parent_err, &attr->child_err, 409 attr->pool)) == APR_SUCCESS) 410 rv = apr_file_inherit_unset(attr->parent_err); 411 412 if (child_err != NULL && rv == APR_SUCCESS) { 413 if (attr->child_err && (attr->child_err->filedes != -1)) 414 rv = apr_file_dup2(attr->child_err, child_err, attr->pool); 415 else { 416 attr->child_err = NULL; 417 if ((rv = apr_file_dup(&attr->child_err, child_err, attr->pool)) 418 == APR_SUCCESS) 419 rv = apr_file_inherit_set(attr->child_err); 420 } 421 } 422 423 if (parent_err != NULL && rv == APR_SUCCESS) 424 rv = apr_file_dup(&attr->parent_err, parent_err, attr->pool); 425 426 return rv; 427} 428 429APR_DECLARE(apr_status_t) apr_procattr_limit_set(apr_procattr_t *attr, apr_int32_t what, 430 void *limit) 431{ 432 return APR_ENOTIMPL; 433} 434 435APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr, 436 const char *username, 437 const char *password) 438{ 439 return APR_ENOTIMPL; 440} 441 442APR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr, 443 const char *groupname) 444{ 445 return APR_ENOTIMPL; 446} 447