void parent_fetch_cmd(struct child *child, struct children *children, struct mail_ctx *mctx, struct msg *msg) { struct mail *m = mctx->mail; struct child_deliver_data *data; uid_t uid = msg->data.uid; gid_t gid = msg->data.gid; data = xmalloc(sizeof *data); data->child = child; data->msgid = msg->id; data->account = mctx->account; data->hook = child_deliver_cmd_hook; data->mctx = mctx; data->cmddata = msg->data.cmddata; data->mail = m; data->name = "command"; data->uid = uid; data->gid = gid; child = child_start( children, uid, gid, child_deliver, parent_deliver, data, child); log_debug3("parent: command " "child %ld started (uid %lu)", (long) child->pid, (u_long) uid); }
static int run_decoder(aac_t *aac) { char *darg[8]={AAC_DECODER,"-f","2","-o", NULL, NULL, NULL}; darg[4]=FIFO_NAME; darg[5]=aac->fname; aac->dpid=child_start(darg,NULL,NULL,NULL); if(!(aac->inf=fopen(FIFO_NAME,"r"))) { ERRMSG("can't open fifo\n"); return -1; } return 0; }
int parent_run(wshd_t *w) { char path[MAXPATHLEN]; int rv; pid_t pid; memset(path, 0, sizeof(path)); strcpy(path + strlen(path), w->run_path); strcpy(path + strlen(path), "/"); strcpy(path + strlen(path), "wshd.sock"); w->fd = un_listen(path); rv = barrier_open(&w->barrier_parent); assert(rv == 0); rv = barrier_open(&w->barrier_child); assert(rv == 0); /* Unshare mount namespace, so the before clone hook is free to mount * whatever it needs without polluting the global mount namespace. */ rv = unshare(CLONE_NEWNS); assert(rv == 0); rv = run(w->lib_path, "hook-parent-before-clone.sh"); assert(rv == 0); pid = child_start(w); assert(pid > 0); parent_setenv_pid(w, pid); rv = run(w->lib_path, "hook-parent-after-clone.sh"); assert(rv == 0); rv = barrier_signal(&w->barrier_parent); if (rv == -1) { fprintf(stderr, "Error waking up child process\n"); exit(1); } rv = barrier_wait(&w->barrier_child); if (rv == -1) { fprintf(stderr, "Error waiting for acknowledgement from child process\n"); exit(1); } return 0; }
void parent_fetch_action(struct child *child, struct children *children, struct deliver_ctx *dctx, struct msg *msg) { struct actitem *ti = msg->data.actitem; struct mail *m = dctx->mail; struct mail *md = &dctx->wr_mail; struct child_deliver_data *data; uid_t uid = msg->data.uid; gid_t gid = msg->data.gid; memset(md, 0, sizeof *md); /* * If writing back, open a new mail now and set its ownership so it * can be accessed by the child. */ if (ti->deliver->type == DELIVER_WRBACK) { if (mail_open(md, IO_BLOCKSIZE) != 0) { log_warn("parent: failed to create mail"); parent_fetch_error(child, msg); return; } if (geteuid() == 0 && shm_owner(&md->shm, conf.child_uid, conf.child_gid) != 0) { mail_destroy(md); log_warn("parent: failed to set mail ownership"); parent_fetch_error(child, msg); return; } md->decision = m->decision; } data = xmalloc(sizeof *data); data->child = child; data->msgid = msg->id; data->account = dctx->account; data->hook = child_deliver_action_hook; data->actitem = ti; data->dctx = dctx; data->mail = m; data->name = "deliver"; data->uid = uid; data->gid = gid; child = child_start( children, uid, gid, child_deliver, parent_deliver, data, child); log_debug3("parent: deliver " "child %ld started (uid %lu)", (long) child->pid, (u_long) uid); }
static void compile_dex_with_dexopt(const char* dex_file_name, const char* odex_file_name) { SCOPED_RESLIST(rl); int dex_file = xopen(dex_file_name, O_RDONLY, 0); const char* odex_temp_filename = xaprintf( "%s.tmp.%s", odex_file_name, gen_hex_random(ENOUGH_ENTROPY)); cleanup_commit(cleanup_allocate(), cleanup_tmpfile, odex_temp_filename); int odex_temp_file = xopen(odex_temp_filename, O_RDWR | O_CREAT | O_EXCL, 0644); allow_inherit(dex_file); allow_inherit(odex_temp_file); struct child_start_info csi = { .io[0] = CHILD_IO_DEV_NULL, .io[1] = CHILD_IO_PIPE, .io[2] = CHILD_IO_DUP_TO_STDOUT, .exename = "dexopt", .argv = ARGV( "dexopt", "--zip", xaprintf("%d", dex_file), xaprintf("%d", odex_temp_file), dex_file_name, "v=ao=fm=y"), }; struct child* dexopt = child_start(&csi); struct growable_buffer output = slurp_fd_buf(dexopt->fd[1]->fd); int status = child_status_to_exit_code(child_wait(dexopt)); if (status != 0) die(EINVAL, "dexopt failed: %s", massage_output_buf(output)); xrename(odex_temp_filename, odex_file_name); } static void compile_dex(const char* dex_file_name, const char* odex_file_name) { if (api_level() < 21) compile_dex_with_dexopt(dex_file_name, odex_file_name); } int rdex_main(const struct cmd_rdex_info* info) { const char* dex_file_name = info->dexfile; struct stat dex_stat = xstat(dex_file_name); const char* odex_file_name = make_odex_name(dex_file_name); bool need_recompile = true; struct stat odex_stat; if (stat(odex_file_name, &odex_stat) == 0 && dex_stat.st_mtime <= odex_stat.st_mtime) { need_recompile = false; } (void) need_recompile; (void) odex_file_name; (void) compile_dex; if (need_recompile) compile_dex(dex_file_name, odex_file_name); if (setenv("CLASSPATH", dex_file_name, 1) == -1) die_errno("setenv"); if (info->classname[0] == '-') die(EINVAL, "class name cannot begin with '-'"); execvp("app_process", (char* const*) ARGV_CONCAT( ARGV("app_process", xdirname(dex_file_name), info->classname), info->args ?: empty_argv)); die_errno("execvp(\"app_process\", ..."); }
static struct child* start_child(struct msg_shex_hello* shex_hello) { if (shex_hello->nr_argv < 2) die(ECOMM, "insufficient arguments given"); SCOPED_RESLIST(rl_args); char** child_args = read_child_arglist(shex_hello->nr_argv); reslist_pop_nodestroy(rl_args); struct child_start_info csi = { .flags = CHILD_SETSID, .exename = child_args[0], .argv = (const char* const *) child_args + 1, .pty_setup = setup_pty, .pty_setup_data = shex_hello, .deathsig = -SIGHUP, }; if (shex_hello->si[0].pty_p) csi.flags |= CHILD_PTY_STDIN; if (shex_hello->si[1].pty_p) csi.flags |= CHILD_PTY_STDOUT; if (shex_hello->si[2].pty_p) csi.flags |= CHILD_PTY_STDERR; return child_start(&csi); } static void __attribute__((noreturn)) re_exec_as_root() { execlp("su", "su", "-c", xaprintf("%s stub", orig_argv0), NULL); die_errno("execlp of su"); } int stub_main(int argc, const char** argv) { if (argc != 1) die(EINVAL, "this command is internal"); /* XMKRAW_SKIP_CLEANUP so we never change from raw back to cooked * mode on exit. The connection dies on exit anyway, and * resetting the pty can send some extra bytes that can confuse * our peer. */ if (isatty(0)) xmkraw(0, XMKRAW_SKIP_CLEANUP); if (isatty(1)) xmkraw(1, XMKRAW_SKIP_CLEANUP); printf(FB_ADB_PROTO_START_LINE "\n", build_time, (int) getuid()); fflush(stdout); struct msg_shex_hello* shex_hello; struct msg* mhdr = read_msg(0, read_all_adb_encoded); if (mhdr->type == MSG_EXEC_AS_ROOT) re_exec_as_root(); // Never returns if (mhdr->type != MSG_SHEX_HELLO || mhdr->size < sizeof (struct msg_shex_hello)) { die(ECOMM, "bad hello"); } shex_hello = (struct msg_shex_hello*) mhdr; struct child* child = start_child(shex_hello); struct stub stub; memset(&stub, 0, sizeof (stub)); stub.child = child; struct fb_adb_sh* sh = &stub.sh; sh->process_msg = stub_process_msg; sh->max_outgoing_msg = shex_hello->maxmsg; sh->nrch = 5; struct channel** ch = xalloc(sh->nrch * sizeof (*ch)); ch[FROM_PEER] = channel_new(fdh_dup(0), shex_hello->stub_recv_bufsz, CHANNEL_FROM_FD); ch[FROM_PEER]->window = UINT32_MAX; ch[FROM_PEER]->adb_encoding_hack = true; replace_with_dev_null(0); ch[TO_PEER] = channel_new(fdh_dup(1), shex_hello->stub_send_bufsz, CHANNEL_TO_FD); replace_with_dev_null(1); ch[CHILD_STDIN] = channel_new(child->fd[0], shex_hello->si[0].bufsz, CHANNEL_TO_FD); ch[CHILD_STDIN]->track_bytes_written = true; ch[CHILD_STDIN]->bytes_written = ringbuf_room(ch[CHILD_STDIN]->rb); ch[CHILD_STDOUT] = channel_new(child->fd[1], shex_hello->si[1].bufsz, CHANNEL_FROM_FD); ch[CHILD_STDOUT]->track_window = true; ch[CHILD_STDERR] = channel_new(child->fd[2], shex_hello->si[2].bufsz, CHANNEL_FROM_FD); ch[CHILD_STDERR]->track_window = true; sh->ch = ch; io_loop_init(sh); PUMP_WHILE(sh, (!channel_dead_p(ch[FROM_PEER]) && !channel_dead_p(ch[TO_PEER]) && (!channel_dead_p(ch[CHILD_STDOUT]) || !channel_dead_p(ch[CHILD_STDERR])))); if (channel_dead_p(ch[FROM_PEER]) || channel_dead_p(ch[TO_PEER])) { // // If we lost our peer connection, make sure the child sees // SIGHUP instead of seeing its stdin close: just drain any // internally-buffered IO and exit. When we lose the pty, the // child gets SIGHUP. // // Make sure we won't be getting any more commands. channel_close(ch[FROM_PEER]); channel_close(ch[TO_PEER]); PUMP_WHILE(sh, (!channel_dead_p(ch[FROM_PEER]) || !channel_dead_p(ch[TO_PEER]))); // Drain output buffers channel_close(ch[CHILD_STDIN]); PUMP_WHILE(sh, !channel_dead_p(ch[CHILD_STDIN])); return 128 + SIGHUP; } // // Clean exit: close standard handles and drain IO. Peer still // has no idea that we're exiting. Get exit status, send that to // peer, then cleanly shut down the peer connection. // dbg("clean exit"); channel_close(ch[CHILD_STDIN]); channel_close(ch[CHILD_STDOUT]); channel_close(ch[CHILD_STDERR]); PUMP_WHILE (sh, (!channel_dead_p(ch[CHILD_STDIN]) || !channel_dead_p(ch[CHILD_STDOUT]) || !channel_dead_p(ch[CHILD_STDERR]))); send_exit_message(child_wait(child), sh); channel_close(ch[TO_PEER]); PUMP_WHILE(sh, !channel_dead_p(ch[TO_PEER])); channel_close(ch[FROM_PEER]); PUMP_WHILE(sh, !channel_dead_p(ch[FROM_PEER])); return 0; }
void adb_send_file(const char* local, const char* remote, const char* const* adb_args) { SCOPED_RESLIST(rl_send_stub); struct child_start_info csi = { .flags = CHILD_MERGE_STDERR, .exename = "adb", .argv = argv_concat((const char*[]){"adb", NULL}, adb_args ?: empty_argv, (const char*[]){"push", local, remote, NULL}, NULL), }; struct child* adb = child_start(&csi); fdh_destroy(adb->fd[0]); char buf[512]; size_t len = read_all(adb->fd[1]->fd, buf, sizeof (buf)); fdh_destroy(adb->fd[1]); int status = child_wait(adb); if (!(WIFEXITED(status) && WEXITSTATUS(status) == 0)) { if (len == sizeof (buf)) --len; while (len > 0 && isspace(buf[len - 1])) --len; buf[len] = '\0';