int process_test_str(struct config *config, char *value, int value_sz, char *keyprefix) { int r; char c_file[1024]; char elf_file[1024]; snprintf(c_file, sizeof(c_file), "%s/plugin-%s.c", config->tmpdir, keyprefix); snprintf(elf_file, sizeof(elf_file), "%s/plugin-%s.elf", config->tmpdir, keyprefix); if(0 != write_file(c_file, value, value_sz)) { log_perror("write()"); return(-1); } char warn_buf[1024]; int warn_buf_sz = 0; if(0 != process_compile(config, c_file, elf_file, warn_buf, sizeof(warn_buf), &warn_buf_sz)) { warn_buf[MAX(1, warn_buf_sz)-1] = '\0'; log_error("compilation failed:\n%s", warn_buf); return(-1); } struct process *process = process_new(NULL, keyprefix, strlen(keyprefix)); log_warn("#%p: loaded code from str", process); r = process_load(process, elf_file); if(0 != r) { process_free(process); log_error("unable to load process:\n%s", warn_buf); return(-1); } r = process_run(NULL, process); process_free(process); if(r <= 0) { log_error("error while running process"); return(-1); } // ok! return(r); }
// return 1 to say that a file was processed static int maybe_process_file(struct asfd *asfd, struct sdirs *sdirs, struct sbuf *cb, struct sbuf *p1b, struct fzp *ucfp, struct conf **cconfs) { switch(sbuf_pathcmp(cb, p1b)) { case 0: return maybe_do_delta_stuff(asfd, sdirs, cb, p1b, ucfp, cconfs); case 1: //logp("ahead: %s\n", p1b->path); // ahead - need to get the whole file if(process_new(sdirs, cconfs, p1b, ucfp)) return -1; // Do not free. return 1; case -1: default: //logp("behind: %s\n", p1b->path); // Behind - need to read more from the old manifest. // Count a deleted file - it was in the old manifest // but not the new. cntr_add_deleted(get_cntr(cconfs[OPT_CNTR]), cb->path.cmd); return 0; } }
static int process_new_file(struct sbuf *cb, struct sbuf *p1b, FILE *ucfp, const char *currentdata, const char *datadirtmp, const char *deltmppath, struct dpth *dpth, int *resume_partial, struct cntr *cntr, struct config *cconf) { if(process_new(p1b, ucfp, currentdata, datadirtmp, deltmppath, dpth, resume_partial, cntr, cconf)) return -1; free_sbuf(cb); return 1; }
void test_new (void) { Process *process; /* Check that we can create a new Process structure; the structure * should be allocated with nih_alloc and have sensible defaults. */ TEST_FUNCTION ("process_new"); TEST_ALLOC_FAIL { process = process_new (NULL); if (test_alloc_failed) { TEST_EQ_P (process, NULL); continue; } TEST_ALLOC_SIZE (process, sizeof (Process)); TEST_EQ (process->script, FALSE); TEST_EQ_P (process->command, NULL); nih_free (process); } }
static int process_new_file(struct sdirs *sdirs, struct conf **cconfs, struct sbuf *cb, struct sbuf *p1b, struct fzp *ucfp) { if(process_new(sdirs, cconfs, p1b, ucfp)) return -1; sbuf_free_content(cb); return 1; }
static Process * _proc_construct_init() { Process *new_proc = process_new("init", NULL); new_proc->current_scene->pc = proc_kernel_thread(init_proc); return new_proc; }
static int process_new_file(struct sdirs *sdirs, struct conf *cconf, struct sbuf *cb, struct sbuf *p1b, FILE *ucfp, struct dpthl *dpthl) { if(process_new(sdirs, cconf, p1b, ucfp, dpthl)) return -1; sbuf_free_content(cb); return 1; }
/* Request: MUST NOT have extras. MUST have key. MUST have value. */ ST_RES *cmd_code_load(CONN *conn, ST_REQ *req, ST_RES *res) { if(req->extras_sz || !req->key_sz || !req->value_sz) return(set_error_code(res, MEMCACHE_STATUS_INVALID_ARGUMENTS, NULL)); if(CONFIG(conn)->vx32_disabled) { return(set_error_code(res, MEMCACHE_STATUS_UNKNOWN_COMMAND, "Command disabled by configuration")); } if(NULL != find_process(req->key, req->key_sz)) return(set_error_code(res, MEMCACHE_STATUS_KEY_EXISTS, NULL)); int r; char c_file[1024]; char elf_file[1024]; char keyprefix[32]; key_escape(keyprefix, sizeof(keyprefix), req->key, req->key_sz); keyprefix[MIN(req->key_sz, sizeof(keyprefix)-1)] = '\0'; // make it reasonably short snprintf(c_file, sizeof(c_file), "%s/plugin-%s.c", CONFIG(conn)->tmpdir, keyprefix); snprintf(elf_file, sizeof(elf_file), "%s/plugin-%s.elf", CONFIG(conn)->tmpdir, keyprefix); res->value = res->buf; r = write_file(c_file, req->value, req->value_sz); if(0 != r) { // never res->status = MEMCACHE_STATUS_ITEM_NOT_STORED; res->value_sz += snprintf(&res->value[res->value_sz], res->buf_sz - res->value_sz, "Error while saving file: %s", strerror(errno)); return(res); } if(0 != process_compile(CONFIG(conn), c_file, elf_file, res->value, res->buf_sz, (int*)&res->value_sz)) { res->status = MEMCACHE_STATUS_ITEM_NOT_STORED; return(res); } res->value_sz = MIN(res->value_sz, 4096); // no more than 4k logs res->value[res->value_sz++] = '\n'; res->value[res->value_sz++] = '\n'; struct process *process = process_new(conn, req->key, req->key_sz); log_warn("#%p: loaded code", process); r = process_load(process, elf_file); if(0 != r) { // never process_free(process); res->value_sz += snprintf(&res->value[res->value_sz], res->buf_sz - res->value_sz, "Error while loading the binary"); res->status = MEMCACHE_STATUS_ITEM_NOT_STORED; return(res); } if(0 != process_run(conn, process)) { process_free(process); res->value_sz += snprintf(&res->value[res->value_sz], res->buf_sz - res->value_sz, "Error while running the binary"); res->status = MEMCACHE_STATUS_ITEM_NOT_STORED; return(res); } res->status = MEMCACHE_STATUS_OK; return res; }
void host_addApplication(Host* host, GQuark pluginID, SimulationTime startTime, SimulationTime stopTime, gchar* arguments) { MAGIC_ASSERT(host); Process* application = process_new(pluginID, startTime, stopTime, arguments); g_queue_push_tail(host->applications, application); StartApplicationEvent* event = startapplication_new(application); worker_scheduleEvent((Event*)event, startTime, host->id); if(stopTime > startTime) { StopApplicationEvent* event = stopapplication_new(application); worker_scheduleEvent((Event*)event, stopTime, host->id); } }
struct process * process_spawn(struct closure *k) { struct vm *vm; struct process *p; vm = vm_new(current_process->vm->program, current_process->vm->prog_size); vm_set_pc(vm, k->label); vm->current_ar = activation_new_on_heap( k->arity + k->locals, NULL, k->ar); p = process_new(vm); #ifdef DEBUG if (trace_scheduling) printf("process #%d created\n", p->number); #endif return(p); }
Process::Process() { this->obj = process_new(); }
int main(int argc, char **argv) { char **real_argv = argv; struct scan_st *sc; struct symbol_table *stab; struct ast *a; char *source = NULL; int opt; int err_count = 0; #ifdef DEBUG int run_program = 1; int dump_symbols = 0; int dump_program = 0; int dump_icode = 0; #endif #ifdef DEBUG setvbuf(stdout, NULL, _IOLBF, 0); #endif /* * Get command-line arguments. */ while ((opt = getopt(argc, argv, OPTS)) != -1) { switch(opt) { #ifdef DEBUG case 'c': trace_scheduling++; break; #ifdef POOL_VALUES case 'd': trace_pool++; break; #endif case 'g': trace_gc++; break; #endif case 'G': gc_trigger = atoi(optarg); break; #ifdef DEBUG case 'i': dump_icode++; break; case 'l': trace_gen++; break; case 'm': trace_vm++; break; case 'n': run_program = 0; break; case 'o': trace_valloc++; break; case 'p': dump_program = 1; break; case 's': dump_symbols = 1; break; case 'v': trace_activations++; break; case 'y': trace_type_inference++; break; #endif case '?': default: usage(argv); } } argc -= optind; argv += optind; if (*argv != NULL) source = *argv; else usage(real_argv); #ifdef POOL_VALUES value_pool_new(); #endif gc_target = gc_trigger; if ((sc = scan_open(source)) != NULL) { stab = symbol_table_new(NULL, 0); global_ar = activation_new_on_heap(100, NULL, NULL); register_std_builtins(stab); report_start(); a = parse_program(sc, stab); scan_close(sc); #ifdef DEBUG if (dump_symbols) symbol_table_dump(stab, 1); if (dump_program) { ast_dump(a, 0); } #endif #ifndef DEBUG symbol_table_free(stab); types_free(); #endif err_count = report_finish(); if (err_count == 0) { struct iprogram *ip; struct vm *vm; struct process *p; unsigned char *program; program = bhuna_malloc(16384); ip = ast_gen_iprogram(a); iprogram_eliminate_nops(ip); iprogram_eliminate_useless_jumps(ip); iprogram_optimize_tail_calls(ip); iprogram_optimize_push_small_ints(ip); iprogram_eliminate_dead_code(ip); iprogram_gen(&program, ip); #ifdef DEBUG if (dump_icode > 0) iprogram_dump(ip, program); #endif vm = vm_new(program, 16384); vm_set_pc(vm, program); vm->current_ar = global_ar; p = process_new(vm); /* ast_dump(a, 0); */ if (RUN_PROGRAM) { process_scheduler(); } vm_free(vm); bhuna_free(program); /*value_dump_global_table();*/ } ast_free(a); /* XXX move on up */ /* gc(); */ /* actually do a full blow out at the end */ /* activation_free_from_stack(global_ar); */ #ifdef DEBUG symbol_table_free(stab); types_free(); if (trace_valloc > 0) { /* value_dump_global_table(); */ printf("Created: %8d\n", num_vars_created); printf("Cached: %8d\n", num_vars_cached); printf("Freed: %8d\n", num_vars_freed); } if (trace_activations > 0) { printf("AR's alloc'ed: %8d\n", activations_allocated); printf("AR's freed: %8d\n", activations_freed); } #ifdef POOL_VALUES if (trace_pool > 0) { pool_report(); } #endif #endif return(0); } else { fprintf(stderr, "Can't open `%s'\n", source); return(1); } }
int backup_phase2_server_protocol1(struct async *as, struct sdirs *sdirs, const char *incexc, int resume, struct conf **cconfs) { int ret=0; struct manio *p1manio=NULL; struct dpth *dpth=NULL; char *deltmppath=NULL; char *last_requested=NULL; // Where to write changed data. // Data is not getting written to a compressed file. // This is important for recovery if the power goes. struct fzp *chfp=NULL; struct fzp *ucfp=NULL; // unchanged data struct fzp *cmanfp=NULL; // previous (current) manifest. struct sbuf *cb=NULL; // file list in current manifest struct sbuf *p1b=NULL; // file list from client struct sbuf *rb=NULL; // receiving file from client struct asfd *asfd=as->asfd; int breaking=0; int breakcount=0; if(get_int(cconfs[OPT_BREAKPOINT])>=2000 && get_int(cconfs[OPT_BREAKPOINT])<3000) { breaking=get_int(cconfs[OPT_BREAKPOINT]); breakcount=breaking-2000; } logp("Begin phase2 (receive file data)\n"); if(!(dpth=dpth_alloc()) || dpth_protocol1_init(dpth, sdirs->currentdata, get_int(cconfs[OPT_MAX_STORAGE_SUBDIRS]))) goto error; if(open_previous_manifest(&cmanfp, sdirs, incexc, cconfs)) goto error; if(get_int(cconfs[OPT_DIRECTORY_TREE])) { // Need to make sure we do not try to create a path that is // too long. if(build_path_w(sdirs->treepath)) goto error; treepathlen=strlen(sdirs->treepath); init_fs_max(sdirs->treepath); } if(!(p1manio=manio_alloc()) || manio_init_read(p1manio, sdirs->phase1data) || !(cb=sbuf_alloc(cconfs)) || !(p1b=sbuf_alloc(cconfs)) || !(rb=sbuf_alloc(cconfs))) goto error; manio_set_protocol(p1manio, PROTO_1); if(resume && do_resume(p1manio, sdirs, dpth, cconfs)) goto error; // Unchanged and changed should now be truncated correctly, we just // have to open them for appending. if(!(ucfp=fzp_open(sdirs->unchanged, "a+b")) || !(chfp=fzp_open(sdirs->changed, "a+b"))) goto error; if(manio_closed(p1manio) && manio_open_next_fpath(p1manio)) goto error; while(1) { if(breaking) { if(breakcount--==0) return breakpoint(cconfs, __func__); } //printf("in loop, %s %s %c\n", // cmanfp?"got cmanfp":"no cmanfp", // rb->path.buf?:"no rb->path", // rb->path.buf?'X':rb->path.cmd); if(write_status(CNTR_STATUS_BACKUP, rb->path.buf?rb->path.buf:p1b->path.buf, cconfs)) goto error; if(last_requested || manio_closed(p1manio) || asfd->writebuflen) { switch(do_stuff_to_receive(asfd, sdirs, cconfs, rb, chfp, dpth, &last_requested)) { case 0: break; case 1: goto end; // Finished ok. case -1: goto error; } } switch(do_stuff_to_send(asfd, p1b, &last_requested)) { case 0: break; case 1: continue; case -1: goto error; } if(manio_closed(p1manio)) continue; sbuf_free_content(p1b); switch(manio_sbuf_fill_phase1(p1manio, asfd, p1b, NULL, sdirs, cconfs)) { case 0: break; case 1: manio_close(p1manio); if(asfd->write_str(asfd, CMD_GEN, "backupphase2end")) goto error; break; case -1: goto error; } if(!cmanfp) { // No old manifest, need to ask for a new file. if(process_new(sdirs, cconfs, p1b, ucfp)) goto error; continue; } // Have an old manifest, look for it there. // Might already have it, or be ahead in the old // manifest. if(cb->path.buf) switch(maybe_process_file(asfd, sdirs, cb, p1b, ucfp, cconfs)) { case 0: break; case 1: continue; case -1: goto error; } while(cmanfp) { sbuf_free_content(cb); switch(sbufl_fill(cb, asfd, cmanfp, cconfs)) { case 0: break; case 1: fzp_close(&cmanfp); if(process_new(sdirs, cconfs, p1b, ucfp)) goto error; continue; case -1: goto error; } switch(maybe_process_file(asfd, sdirs, cb, p1b, ucfp, cconfs)) { case 0: continue; case 1: break; case -1: goto error; } break; } } error: ret=-1; end: if(fzp_close(&chfp)) { logp("error closing %s in %s\n", sdirs->changed, __func__); ret=-1; } if(fzp_close(&ucfp)) { logp("error closing %s in %s\n", sdirs->unchanged, __func__); ret=-1; } free_w(&deltmppath); sbuf_free(&cb); sbuf_free(&p1b); sbuf_free(&rb); manio_free(&p1manio); fzp_close(&cmanfp); dpth_free(&dpth); if(!ret) unlink(sdirs->phase1data); logp("End phase2 (receive file data)\n"); return ret; }
int backup_phase2_server(struct asfd *asfd, struct sdirs *sdirs, struct conf *cconf, gzFile *cmanfp, struct dpthl *dpthl, int resume) { int ars=0; int ret=0; gzFile p1zp=NULL; char *deltmppath=NULL; char *last_requested=NULL; // Where to write phase2data. // Data is not getting written to a compressed file. // This is important for recovery if the power goes. FILE *p2fp=NULL; // unchanged data FILE *ucfp=NULL; struct sbuf *cb=NULL; // file list in current manifest struct sbuf *p1b=NULL; // file list from client struct sbuf *rb=NULL; // receiving file from client if(!(cb=sbuf_alloc(cconf)) || !(p1b=sbuf_alloc(cconf)) || !(rb=sbuf_alloc(cconf))) goto error; if(!(p1zp=gzopen_file(sdirs->phase1data, "rb"))) goto error; // Open in read+write mode, so that they can be read through if // we need to resume. // First, open them in a+ mode, so that they will be created if they // do not exist. if(!(ucfp=open_file(sdirs->unchangeddata, "a+b")) || !(p2fp=open_file(sdirs->phase2data, "a+b"))) goto error; close_fp(&ucfp); close_fp(&p2fp); if(!(ucfp=open_file(sdirs->unchangeddata, "r+b")) || !(p2fp=open_file(sdirs->phase2data, "r+b"))) goto error; if(resume && do_resume(p1zp, p2fp, ucfp, dpthl, cconf)) goto error; logp("Begin phase2 (receive file data)\n"); while(1) { int sts=0; //printf("in loop, %s %s %c\n", // *cmanfp?"got cmanfp":"no cmanfp", // rb->path.buf?:"no rb->path", // rb->path.buf?'X':rb->path.cmd); if(write_status(STATUS_BACKUP, rb->path.buf?rb->path.buf:p1b->path.buf, cconf)) goto error; if((last_requested || !p1zp || asfd->writebuflen) && (ars=do_stuff_to_receive(asfd, sdirs, cconf, rb, p2fp, dpthl, &last_requested))) { if(ars<0) goto error; // 1 means ok. break; } if((sts=do_stuff_to_send(asfd, p1b, &last_requested))<0) goto error; if(!sts && p1zp) { sbuf_free_content(p1b); if((ars=sbufl_fill_phase1(p1b, NULL, p1zp, cconf->cntr))) { if(ars<0) goto error; // ars==1 means it ended ok. gzclose_fp(&p1zp); //logp("ended OK - write phase2end"); if(asfd->write_str(asfd, CMD_GEN, "backupphase2end")) goto error; } //logp("check: %s\n", p1b.path); if(!*cmanfp) { // No old manifest, need to ask for a new file. //logp("no cmanfp\n"); if(process_new(sdirs, cconf, p1b, ucfp, dpthl)) goto error; } else { // Have an old manifest, look for it there. // Might already have it, or be ahead in the old // manifest. if(cb->path.buf) { if((ars=maybe_process_file(asfd, sdirs, cconf, cb, p1b, ucfp, dpthl))) { if(ars<0) goto error; // Do not free it - need to send stuff. continue; } //free_sbufl(&p1b); } while(*cmanfp) { sbuf_free_content(cb); if((ars=sbufl_fill(cb, asfd, NULL, *cmanfp, cconf->cntr))) { // ars==1 means it ended ok. if(ars<0) goto error; gzclose_fp(cmanfp); //logp("ran out of current manifest\n"); if(process_new(sdirs, cconf, p1b, ucfp, dpthl)) goto error; break; } //logp("against: %s\n", cb.path); if((ars=maybe_process_file(asfd, sdirs, cconf, cb, p1b, ucfp, dpthl))) { if(ars<0) goto error; // Do not free it - need to send stuff. break; } } } } } goto end; error: ret=-1; end: if(close_fp(&p2fp)) { logp("error closing %s in backup_phase2_server\n", sdirs->phase2data); ret=-1; } if(close_fp(&ucfp)) { logp("error closing %s in backup_phase2_server\n", sdirs->unchangeddata); ret=-1; } free(deltmppath); sbuf_free(cb); sbuf_free(p1b); sbuf_free(rb); gzclose_fp(&p1zp); if(!ret) unlink(sdirs->phase1data); logp("End phase2 (receive file data)\n"); return ret; }
int proc_do_fork() { return process_new(current_process->name, current_process)->id; }
proc *process_run(char executable[], char *args[], int timeout) { proc *retval = NULL; char *text; int status; tl_stream stdout_p; tl_stream stdin_p; SECURITY_ATTRIBUTES saAttr; PROCESS_INFORMATION pi; STARTUPINFO si; BOOL createproc_success = FALSE; BOOL timedout = FALSE; TCHAR *commandline = NULL; proc *p = process_new(); if (p == NULL) return NULL; /* Make sure pipe handles are inherited */ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; p->causeofdeath = PROC_PIPECREATE; DEBUG(("making pipes \n")); /* Child's Stdout */ if ( ! CreatePipe(&stdout_p.read, &stdout_p.write, &saAttr, 1) ) { printlasterror(); RETURN(p); } DEBUG(("stdout done \n")); /* read handle to the pipe for STDOUT is not inherited */ if ( ! SetHandleInformation(stdout_p.read, HANDLE_FLAG_INHERIT, 0) ) { printlasterror(); RETURN(p); } DEBUG(("stdout noinherit \n")); /* a pipe for the child process's STDIN */ if ( ! CreatePipe(&stdin_p.read, &stdin_p.write, &saAttr, 0) ) { printlasterror(); RETURN(p); } DEBUG(("stdin done \n")); /* write handle to the pipe for STDIN not inherited */ if ( ! SetHandleInformation(stdin_p.read, HANDLE_FLAG_INHERIT, 0) ) { printlasterror(); RETURN(p); } DEBUG(("pipes done \n")); p->causeofdeath = PROC_START; ZeroMemory( &si, sizeof(STARTUPINFO) ); ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) ); si.cb = sizeof(STARTUPINFO); si.hStdError = stdout_p.write; si.hStdOutput = stdout_p.write; /* Rather than use the stdin pipe, which would be si.hStdInput = stdin_p.read; Pass on talon's own standard input to the child process This helps with programs like xcopy which demand that they are attached to a console and not just any type of input file. */ si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si.dwFlags |= STARTF_USESTDHANDLES; DEBUG(("pre commandline \n")); /* create the commandline string */ int len = 0; int i = 0; while (args[i] != NULL) { len += strlen(args[i++]) + 1; } len+=2; commandline = malloc(len*2); if (! commandline) RETURN(p); commandline[0] = '\0'; i = 0; while (args[i] != NULL) { strcat(commandline, args[i]); strcat(commandline, " "); i++; } /* Get the read thread ready to go before creating * the process. */ ReadOpQ *ropq = malloc(sizeof(ReadOpQ)); ropq->first=NULL; ropq->last=NULL; ropq->semaphore = CreateSemaphore(NULL, 0, 1, NULL); DEBUG(("Creating read thread. \n")); DWORD readpipe_threadid; HANDLE h_readpipe_thread = CreateThread(NULL, 8192, (LPTHREAD_START_ROUTINE) readpipe_thread, (void*)ropq, 0, &readpipe_threadid); /* ready to run the process */ DEBUG(("process commandline:\n%s \n", commandline)); DEBUG(("\n")); createproc_success = CreateProcess(executable, commandline, // command line NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited 0, // creation flags NULL, // use parent's environment NULL, // use parent's current directory &si, // STARTUPINFO pointer &pi); // receives PROCESS_INFORMATION if (! createproc_success) { DEBUG(("Createprocess failed. \n")); p->causeofdeath = PROC_SOMEODDDEATH; RETURN(p); } int have_status = 0; DEBUG(("Closing Handles. \n")); if (!CloseHandle(stdout_p.write)) RETURN(p); if (!CloseHandle(stdin_p.read)) RETURN(p); DEBUG(("Closed Handles. \n")); static int id=0; do { char *space = buffer_makespace(p->output, READSIZE); DWORD waitres; ReadOp *iopipe_op = malloc(sizeof(ReadOp)); iopipe_op->semaphore = CreateSemaphore(NULL, 0, 1, NULL); iopipe_op->thread = h_readpipe_thread; iopipe_op->timeout = timeout; iopipe_op->file = stdout_p.read; iopipe_op->space = malloc(READSIZE); iopipe_op->id = id++; iopipe_op->nbytes = READSIZE; iopipe_op->next = NULL; if (!ropq->first) { ropq->first = iopipe_op; ropq->last = iopipe_op; } else { ropq->last->next = iopipe_op; ropq->last = iopipe_op; } ReleaseSemaphore(ropq->semaphore, 1, NULL); DEBUG(("waiting for read %d\n", timeout)); waitres = WaitForSingleObject(iopipe_op->semaphore, timeout); DEBUG(("read wait finished result= %d\n", waitres)); if (waitres != WAIT_OBJECT_0) { DEBUG(("timeout \n")); timedout = TRUE; break; } else { DEBUG(("read signalled: nbytes: %d \n", iopipe_op->nbytes)); if (iopipe_op->nbytes <= 0) { break; } memcpy(space, iopipe_op->space, iopipe_op->nbytes); buffer_usespace(p->output, iopipe_op->nbytes); DEBUG(("buffer took on nbytes: %d \n", iopipe_op->nbytes)); } } while (1); if (timedout == FALSE) { DEBUG(("Wait for process exit\n")); // Wait until child process exits. WaitForSingleObject(pi.hProcess, INFINITE); DEBUG(("Process exited\n")); DWORD exitcode; if (GetExitCodeProcess(pi.hProcess, &exitcode)) { p->causeofdeath = PROC_NORMALDEATH; p->returncode = exitcode; DEBUG(("process exited normally = %d:\n", p->returncode)); RETURN(p); } else { p->causeofdeath = PROC_SOMEODDDEATH; p->returncode = 128; DEBUG(("process terminated \n")); RETURN(p); } } else { TerminateProcess(pi.hProcess,1); p->causeofdeath = PROC_TIMEOUTDEATH; p->returncode = 128; DEBUG(("process timedout \n")); RETURN(p); } /* Clean up the read operation queue ReadOp *r = ropq.first; do { CloseHandle(r->semaphore); free(r->space); free(r); r = r->next; } while (r != NULL); */ CLEANUP(); if (retval == NULL) { if (p) process_free(&p); } if (commandline) free(commandline); return retval; }
/* Test the configure_proxy() function. */ static void test_pt_configure_proxy(void *arg) { int i, retval; managed_proxy_t *mp = NULL; (void) arg; dummy_state = tor_malloc_zero(sizeof(or_state_t)); MOCK(process_read_stdout, process_read_stdout_replacement); MOCK(get_or_state, get_or_state_replacement); MOCK(queue_control_event_string, queue_control_event_string_replacement); control_testing_set_global_event_mask(EVENT_TRANSPORT_LAUNCHED); mp = tor_malloc_zero(sizeof(managed_proxy_t)); mp->conf_state = PT_PROTO_ACCEPTING_METHODS; mp->transports = smartlist_new(); mp->transports_to_launch = smartlist_new(); mp->argv = tor_malloc_zero(sizeof(char*)*2); mp->argv[0] = tor_strdup("<testcase>"); mp->is_server = 1; /* Configure the process. */ mp->process = process_new(""); process_set_stdout_read_callback(mp->process, managed_proxy_stdout_callback); process_set_data(mp->process, mp); /* Test the return value of configure_proxy() by calling it some times while it is uninitialized and then finally finalizing its configuration. */ for (i = 0 ; i < 5 ; i++) { /* force a read from our mocked stdout reader. */ process_notify_event_stdout(mp->process); /* try to configure our proxy. */ retval = configure_proxy(mp); /* retval should be zero because proxy hasn't finished configuring yet */ tt_int_op(retval, OP_EQ, 0); /* check the number of registered transports */ tt_int_op(smartlist_len(mp->transports), OP_EQ, i+1); /* check that the mp is still waiting for transports */ tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); } /* Get the SMETHOD DONE written to the process. */ process_notify_event_stdout(mp->process); /* this last configure_proxy() should finalize the proxy configuration. */ retval = configure_proxy(mp); /* retval should be 1 since the proxy finished configuring */ tt_int_op(retval, OP_EQ, 1); /* check the mp state */ tt_assert(mp->conf_state == PT_PROTO_COMPLETED); tt_int_op(controlevent_n, OP_EQ, 5); tt_int_op(controlevent_event, OP_EQ, EVENT_TRANSPORT_LAUNCHED); tt_int_op(smartlist_len(controlevent_msgs), OP_EQ, 5); smartlist_sort_strings(controlevent_msgs); tt_str_op(smartlist_get(controlevent_msgs, 0), OP_EQ, "650 TRANSPORT_LAUNCHED server mock1 127.0.0.1 5551\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 1), OP_EQ, "650 TRANSPORT_LAUNCHED server mock2 127.0.0.1 5552\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 2), OP_EQ, "650 TRANSPORT_LAUNCHED server mock3 127.0.0.1 5553\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 3), OP_EQ, "650 TRANSPORT_LAUNCHED server mock4 127.0.0.1 5554\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 4), OP_EQ, "650 TRANSPORT_LAUNCHED server mock5 127.0.0.1 5555\r\n"); /* Get the log message out. */ process_notify_event_stdout(mp->process); tt_int_op(controlevent_n, OP_EQ, 10); tt_int_op(controlevent_event, OP_EQ, EVENT_PT_LOG); tt_int_op(smartlist_len(controlevent_msgs), OP_EQ, 10); tt_str_op(smartlist_get(controlevent_msgs, 5), OP_EQ, "650 PT_LOG PT=<testcase> SEVERITY=error " "MESSAGE=\"Oh noes, " "something bad happened. What do we do!?\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 6), OP_EQ, "650 PT_LOG PT=<testcase> SEVERITY=warning " "MESSAGE=\"warning msg\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 7), OP_EQ, "650 PT_LOG PT=<testcase> SEVERITY=notice " "MESSAGE=\"notice msg\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 8), OP_EQ, "650 PT_LOG PT=<testcase> SEVERITY=info " "MESSAGE=\"info msg\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 9), OP_EQ, "650 PT_LOG PT=<testcase> SEVERITY=debug " "MESSAGE=\"debug msg\"\r\n"); /* Get the STATUS messages out. */ process_notify_event_stdout(mp->process); tt_int_op(controlevent_n, OP_EQ, 13); tt_int_op(controlevent_event, OP_EQ, EVENT_PT_STATUS); tt_int_op(smartlist_len(controlevent_msgs), OP_EQ, 13); tt_str_op(smartlist_get(controlevent_msgs, 10), OP_EQ, "650 PT_STATUS " "PT=<testcase> TRANSPORT=a K_1=a K_2=b K_3=\"foo bar\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 11), OP_EQ, "650 PT_STATUS " "PT=<testcase> TRANSPORT=b K_1=a K_2=b K_3=\"foo bar\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 12), OP_EQ, "650 PT_STATUS " "PT=<testcase> TRANSPORT=c K_1=a K_2=b K_3=\"foo bar\"\r\n"); { /* check that the transport info were saved properly in the tor state */ config_line_t *transport_in_state = NULL; smartlist_t *transport_info_sl = smartlist_new(); char *name_of_transport = NULL; char *bindaddr = NULL; /* Get the bindaddr for "mock1" and check it against the bindaddr that the mocked tor_get_lines_from_handle() generated. */ transport_in_state = get_transport_in_state_by_name("mock1"); tt_assert(transport_in_state); smartlist_split_string(transport_info_sl, transport_in_state->value, NULL, 0, 0); name_of_transport = smartlist_get(transport_info_sl, 0); bindaddr = smartlist_get(transport_info_sl, 1); tt_str_op(name_of_transport, OP_EQ, "mock1"); tt_str_op(bindaddr, OP_EQ, "127.0.0.1:5551"); SMARTLIST_FOREACH(transport_info_sl, char *, cp, tor_free(cp)); smartlist_free(transport_info_sl); } done: or_state_free(dummy_state); UNMOCK(process_read_stdout); UNMOCK(get_or_state); UNMOCK(queue_control_event_string); if (controlevent_msgs) { SMARTLIST_FOREACH(controlevent_msgs, char *, cp, tor_free(cp)); smartlist_free(controlevent_msgs); controlevent_msgs = NULL; } if (mp->transports) { SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); smartlist_free(mp->transports); }
static int nl_handle_msg(struct cn_msg *cn_hdr) { /* The event to consider */ struct proc_event *ev; /* Return codes */ int ret = 0; /* Get the event data. We only care about two event types. */ ev = (struct proc_event*)cn_hdr->data; switch (ev->what) { case PROC_EVENT_NONE: g_debug("netlink: successfully subscribed for listening to proc events"); netlink_proc_listening = TRUE; break; // quite seldom events on old processes changing important parameters case PROC_EVENT_UID: // skip threads if(ev->event_data.id.process_tgid != ev->event_data.id.process_pid) break; u_trace("UID Event: PID = %d, tGID = %d, rUID = %d," " eUID = %d", ev->event_data.id.process_pid, ev->event_data.id.process_tgid, ev->event_data.id.r.ruid, ev->event_data.id.e.euid); process_new(ev->event_data.id.process_pid, FALSE); break; case PROC_EVENT_GID: // skip threads if(ev->event_data.id.process_tgid != ev->event_data.id.process_pid) break; u_trace("GID Event: PID = %d, tGID = %d, rGID = %d," " eGID = %d", ev->event_data.id.process_pid, ev->event_data.id.process_tgid, ev->event_data.id.r.rgid, ev->event_data.id.e.egid); process_new(ev->event_data.id.process_pid, FALSE); break; case PROC_EVENT_EXIT: /* * Skip threads, * We could remove thread from the thread leader tasks, but this is * currently useless, as we don't schedule tasks and we can wait for * the next iteration; tasks will be updated automatically. */ if(ev->event_data.exit.process_tgid != ev->event_data.exit.process_pid) break; u_trace("EXIT Event: PID = %d", ev->event_data.exit.process_pid); //g_ptr_array_foreach(stack, remove_pid_from_stack, &pid); // if the pid was found in the new stack, pid is set to 0 to indicate // the removal process_remove_by_pid(ev->event_data.exit.process_pid); break; case PROC_EVENT_EXEC: // skip threads, see above note if(ev->event_data.exec.process_tgid != ev->event_data.exec.process_pid) break; u_trace("EXEC Event: PID = %d, tGID = %d", ev->event_data.exec.process_pid, ev->event_data.exec.process_tgid); process_new_delay(ev->event_data.exec.process_tgid, 0); break; case PROC_EVENT_FORK: // skip threads, see above note if(ev->event_data.fork.child_tgid != ev->event_data.fork.child_pid) break; u_trace("FORK Event: PARENT = <PID: %d, TGID: %d>, CHILD = <PID: %d, TGID = %d>", ev->event_data.fork.parent_pid, ev->event_data.fork.parent_tgid, ev->event_data.fork.child_pid, ev->event_data.fork.child_tgid); process_new_delay(ev->event_data.fork.child_tgid, ev->event_data.fork.parent_tgid); break; default: return 0; } return ret; }
// return 1 to say that a file was processed static int maybe_process_file(struct asfd *asfd, struct sdirs *sdirs, struct conf *cconf, struct sbuf *cb, struct sbuf *p1b, FILE *ucfp, struct dpthl *dpthl) { int pcmp; if(!(pcmp=sbuf_pathcmp(cb, p1b))) { int oldcompressed=0; // If the file type changed, I think it is time to back it // up again (for example, EFS changing to normal file, or // back again). if(cb->path.cmd!=p1b->path.cmd) return process_new_file(sdirs, cconf, cb, p1b, ucfp, dpthl); // mtime is the actual file data. // ctime is the attributes or meta data. if(cb->statp.st_mtime==p1b->statp.st_mtime && cb->statp.st_ctime==p1b->statp.st_ctime) { // got an unchanged file //logp("got unchanged file: %s %c %c\n", cb->path, cb->cmd, p1b->cmd); return process_unchanged_file(cb, ucfp, cconf); } if(cb->statp.st_mtime==p1b->statp.st_mtime && cb->statp.st_ctime!=p1b->statp.st_ctime) { // File data stayed the same, but attributes or meta // data changed. We already have the attributes, but // may need to get extra meta data. if(cb->path.cmd==CMD_ENC_METADATA || p1b->path.cmd==CMD_ENC_METADATA // TODO: make unencrypted metadata use the librsync || cb->path.cmd==CMD_METADATA || p1b->path.cmd==CMD_METADATA || cb->path.cmd==CMD_VSS || p1b->path.cmd==CMD_VSS || cb->path.cmd==CMD_ENC_VSS || p1b->path.cmd==CMD_ENC_VSS || cb->path.cmd==CMD_VSS_T || p1b->path.cmd==CMD_VSS_T || cb->path.cmd==CMD_ENC_VSS_T || p1b->path.cmd==CMD_ENC_VSS_T || cb->path.cmd==CMD_EFS_FILE || p1b->path.cmd==CMD_EFS_FILE) return process_new_file(sdirs, cconf, cb, p1b, ucfp, dpthl); // On Windows, we have to back up the whole file if // ctime changed, otherwise things like permission // changes do not get noticed. So, in that case, fall // through to the changed stuff below. // Non-Windows clients finish here. else if(!cconf->client_is_windows) return process_unchanged_file(cb, ucfp, cconf); } // Got a changed file. //logp("got changed file: %s\n", p1b->path); // If either old or new is encrypted, or librsync is off, // we need to get a new file. if(!cconf->librsync || cb->path.cmd==CMD_ENC_FILE || p1b->path.cmd==CMD_ENC_FILE || cb->path.cmd==CMD_ENC_METADATA || p1b->path.cmd==CMD_ENC_METADATA || cb->path.cmd==CMD_EFS_FILE || p1b->path.cmd==CMD_EFS_FILE // TODO: make unencrypted metadata use the librsync || cb->path.cmd==CMD_METADATA || p1b->path.cmd==CMD_METADATA || cb->path.cmd==CMD_VSS || p1b->path.cmd==CMD_VSS || cb->path.cmd==CMD_ENC_VSS || p1b->path.cmd==CMD_ENC_VSS || cb->path.cmd==CMD_VSS_T || p1b->path.cmd==CMD_VSS_T || cb->path.cmd==CMD_ENC_VSS_T || p1b->path.cmd==CMD_ENC_VSS_T) return process_new_file(sdirs, cconf, cb, p1b, ucfp, dpthl); // Get new files if they have switched between compression on // or off. if(cb->burp1->datapth.buf && dpthl_is_compressed(cb->compression, cb->burp1->datapth.buf)) oldcompressed=1; if( ( oldcompressed && !cconf->compression) || (!oldcompressed && cconf->compression)) return process_new_file(sdirs, cconf, cb, p1b, ucfp, dpthl); // Otherwise, do the delta stuff (if possible). if(filedata(p1b->path.cmd)) { if(process_changed_file(asfd, sdirs, cconf, cb, p1b, sdirs->currentdata)) return -1; } else { if(changed_non_file(p1b, ucfp, p1b->path.cmd, cconf)) return -1; } sbuf_free_content(cb); return 1; } else if(pcmp>0) { //logp("ahead: %s\n", p1b->path); // ahead - need to get the whole file if(process_new(sdirs, cconf, p1b, ucfp, dpthl)) return -1; // do not free return 1; } else { //logp("behind: %s\n", p1b->path); // behind - need to read more from the old // manifest // Count a deleted file - it was in the old manifest but not // the new. cntr_add_deleted(cconf->cntr, cb->path.cmd); } return 0; }
static int nl_handle_msg(struct cn_msg *cn_hdr) { /* The event to consider */ struct proc_event *ev; /* Return codes */ int ret = 0; /* Get the event data. We only care about two event types. */ ev = (struct proc_event*)cn_hdr->data; switch (ev->what) { case PROC_EVENT_NONE: g_debug("netlink: successfully subscribed for listening to proc events"); netlink_proc_listening = TRUE; break; // quite seldom events on old processes changing important parameters case PROC_EVENT_UID: // skip threads if(ev->event_data.id.process_tgid != ev->event_data.id.process_pid) break; u_trace("UID Event: PID = %d, tGID = %d, rUID = %d," " eUID = %d", ev->event_data.id.process_pid, ev->event_data.id.process_tgid, ev->event_data.id.r.ruid, ev->event_data.id.e.euid); process_new(ev->event_data.id.process_pid, FALSE); break; case PROC_EVENT_GID: // skip threads if(ev->event_data.id.process_tgid != ev->event_data.id.process_pid) break; u_trace("GID Event: PID = %d, tGID = %d, rGID = %d," " eGID = %d", ev->event_data.id.process_pid, ev->event_data.id.process_tgid, ev->event_data.id.r.rgid, ev->event_data.id.e.egid); process_new(ev->event_data.id.process_pid, FALSE); break; case PROC_EVENT_EXIT: // skip threads if(ev->event_data.exit.process_tgid != ev->event_data.exit.process_pid) break; u_trace("EXIT Event: PID = %d", ev->event_data.exit.process_pid); //g_ptr_array_foreach(stack, remove_pid_from_stack, &pid); // if the pid was found in the new stack, pid is set to 0 to indicate // the removal process_remove_by_pid(ev->event_data.exit.process_pid); break; case PROC_EVENT_EXEC: // skip threads if(ev->event_data.exec.process_tgid != ev->event_data.exec.process_pid) break; u_trace("EXEC Event: PID = %d, tGID = %d", ev->event_data.exec.process_pid, ev->event_data.exec.process_tgid); process_new_delay(ev->event_data.exec.process_tgid, 0); break; case PROC_EVENT_FORK: // we skip new threads for now // FIXME need filter block to get those events if(ev->event_data.fork.parent_tgid != ev->event_data.fork.child_pid) break; u_trace("FORK Event: PARENT = %d PID = %d tGID = %d", ev->event_data.fork.parent_tgid, ev->event_data.fork.child_pid, ev->event_data.fork.child_tgid); // parent does not mean the parent of the new proc, but the parent of // the forking process. so we lookup the parent of the forking process // first u_proc *rparent = proc_by_pid(ev->event_data.fork.parent_tgid); if(rparent) { u_proc_ensure(rparent, BASIC, NOUPDATE); process_new_delay(ev->event_data.fork.child_tgid, rparent->proc->ppid); //ev->event_data.fork.parent_pid); } else process_new_delay(ev->event_data.fork.child_tgid, 0); break; default: return 0; } return ret; }
// return 1 to say that a file was processed static int maybe_process_file(struct sbuf *cb, struct sbuf *p1b, FILE *ucfp, const char *currentdata, const char *datadirtmp, const char *deltmppath, struct dpth *dpth, int *resume_partial, struct cntr *cntr, struct config *cconf) { int pcmp; // logp("in maybe_proc %s\n", p1b->path); if(!(pcmp=sbuf_pathcmp(cb, p1b))) { int oldcompressed=0; // If the file type changed, I think it is time to back it // up again (for example, EFS changing to normal file, or // back again). if(cb->cmd!=p1b->cmd) return process_new_file(cb, p1b, ucfp, currentdata, datadirtmp, deltmppath, dpth, resume_partial, cntr, cconf); // mtime is the actual file data. // ctime is the attributes or meta data. if(cb->statp.st_mtime==p1b->statp.st_mtime && cb->statp.st_ctime==p1b->statp.st_ctime) { // got an unchanged file //logp("got unchanged file: %s %c %c\n", cb->path, cb->cmd, p1b->cmd); return process_unchanged_file(cb, ucfp, cntr); } if(cb->statp.st_mtime==p1b->statp.st_mtime && cb->statp.st_ctime!=p1b->statp.st_ctime) { // File data stayed the same, but attributes or meta // data changed. We already have the attributes, but // may need to get extra meta data. if(cb->cmd==CMD_ENC_METADATA || p1b->cmd==CMD_ENC_METADATA // TODO: make unencrypted metadata use the librsync || cb->cmd==CMD_METADATA || p1b->cmd==CMD_METADATA || cb->cmd==CMD_VSS || p1b->cmd==CMD_VSS || cb->cmd==CMD_ENC_VSS || p1b->cmd==CMD_ENC_VSS || cb->cmd==CMD_VSS_T || p1b->cmd==CMD_VSS_T || cb->cmd==CMD_ENC_VSS_T || p1b->cmd==CMD_ENC_VSS_T || cb->cmd==CMD_EFS_FILE || p1b->cmd==CMD_EFS_FILE) return process_new_file(cb, p1b, ucfp, currentdata, datadirtmp, deltmppath, dpth, resume_partial, cntr, cconf); else return process_unchanged_file(cb, ucfp, cntr); } // Got a changed file. //logp("got changed file: %s\n", p1b->path); // If either old or new is encrypted, or librsync is off, // we need to get a new file. if(!cconf->librsync || cb->cmd==CMD_ENC_FILE || p1b->cmd==CMD_ENC_FILE || cb->cmd==CMD_ENC_METADATA || p1b->cmd==CMD_ENC_METADATA || cb->cmd==CMD_EFS_FILE || p1b->cmd==CMD_EFS_FILE // TODO: make unencrypted metadata use the librsync || cb->cmd==CMD_METADATA || p1b->cmd==CMD_METADATA || cb->cmd==CMD_VSS || p1b->cmd==CMD_VSS || cb->cmd==CMD_ENC_VSS || p1b->cmd==CMD_ENC_VSS || cb->cmd==CMD_VSS_T || p1b->cmd==CMD_VSS_T || cb->cmd==CMD_ENC_VSS_T || p1b->cmd==CMD_ENC_VSS_T) return process_new_file(cb, p1b, ucfp, currentdata, datadirtmp, deltmppath, dpth, resume_partial, cntr, cconf); // Get new files if they have switched between compression on // or off. if(cb->datapth && dpth_is_compressed(cb->compression, cb->datapth)) oldcompressed=1; if( ( oldcompressed && !cconf->compression) || (!oldcompressed && cconf->compression)) return process_new_file(cb, p1b, ucfp, currentdata, datadirtmp, deltmppath, dpth, resume_partial, cntr, cconf); // Otherwise, do the delta stuff (if possible). if(filedata(p1b->cmd)) { if(process_changed_file(cb, p1b, currentdata, datadirtmp, deltmppath, resume_partial, cntr, cconf)) return -1; } else { if(changed_non_file(p1b, ucfp, p1b->cmd, cntr)) return -1; } free_sbuf(cb); return 1; } else if(pcmp>0) { //logp("ahead: %s\n", p1b->path); // ahead - need to get the whole file if(process_new(p1b, ucfp, currentdata, datadirtmp, deltmppath, dpth, resume_partial, cntr, cconf)) return -1; // do not free return 1; } else { //logp("behind: %s\n", p1b->path); // behind - need to read more from the old // manifest // Count a deleted file - it was in the old manifest but not // the new. do_filecounter_deleted(cntr, cb->cmd); } return 0; }
int fork1(struct proc *p1, int exitsig, int flags, void *stack, size_t stacksize, void (*func)(void *), void *arg, register_t *retval, struct proc **rnewprocp) { struct proc *p2; uid_t uid; struct vmspace *vm; int count; vaddr_t uaddr; int s; extern void endtsleep(void *); extern void realitexpire(void *); /* * Although process entries are dynamically created, we still keep * a global limit on the maximum number we will create. We reserve * the last 5 processes to root. The variable nprocs is the current * number of processes, maxproc is the limit. */ uid = p1->p_cred->p_ruid; if ((nprocs >= maxproc - 5 && uid != 0) || nprocs >= maxproc) { static struct timeval lasttfm; if (ratecheck(&lasttfm, &fork_tfmrate)) tablefull("proc"); return (EAGAIN); } nprocs++; /* * Increment the count of procs running with this uid. Don't allow * a nonprivileged user to exceed their current limit. */ count = chgproccnt(uid, 1); if (uid != 0 && count > p1->p_rlimit[RLIMIT_NPROC].rlim_cur) { (void)chgproccnt(uid, -1); nprocs--; return (EAGAIN); } uaddr = uvm_km_alloc1(kernel_map, USPACE, USPACE_ALIGN, 1); if (uaddr == 0) { chgproccnt(uid, -1); nprocs--; return (ENOMEM); } /* * From now on, we're committed to the fork and cannot fail. */ /* Allocate new proc. */ p2 = pool_get(&proc_pool, PR_WAITOK); p2->p_stat = SIDL; /* protect against others */ p2->p_exitsig = exitsig; p2->p_forw = p2->p_back = NULL; #ifdef RTHREADS if (flags & FORK_THREAD) { atomic_setbits_int(&p2->p_flag, P_THREAD); p2->p_p = p1->p_p; TAILQ_INSERT_TAIL(&p2->p_p->ps_threads, p2, p_thr_link); } else { process_new(p2, p1); } #else process_new(p2, p1); #endif /* * Make a proc table entry for the new process. * Start by zeroing the section of proc that is zero-initialized, * then copy the section that is copied directly from the parent. */ bzero(&p2->p_startzero, (unsigned) ((caddr_t)&p2->p_endzero - (caddr_t)&p2->p_startzero)); bcopy(&p1->p_startcopy, &p2->p_startcopy, (unsigned) ((caddr_t)&p2->p_endcopy - (caddr_t)&p2->p_startcopy)); /* * Initialize the timeouts. */ timeout_set(&p2->p_sleep_to, endtsleep, p2); timeout_set(&p2->p_realit_to, realitexpire, p2); #if defined(__HAVE_CPUINFO) p2->p_cpu = p1->p_cpu; #endif /* * Duplicate sub-structures as needed. * Increase reference counts on shared objects. * The p_stats and p_sigacts substructs are set in vm_fork. */ p2->p_flag = 0; p2->p_emul = p1->p_emul; if (p1->p_flag & P_PROFIL) startprofclock(p2); atomic_setbits_int(&p2->p_flag, p1->p_flag & (P_SUGID | P_SUGIDEXEC)); if (flags & FORK_PTRACE) atomic_setbits_int(&p2->p_flag, p1->p_flag & P_TRACED); #ifdef RTHREADS if (flags & FORK_THREAD) { /* nothing */ } else #endif { p2->p_p->ps_cred = pool_get(&pcred_pool, PR_WAITOK); bcopy(p1->p_p->ps_cred, p2->p_p->ps_cred, sizeof(*p2->p_p->ps_cred)); p2->p_p->ps_cred->p_refcnt = 1; crhold(p1->p_ucred); } TAILQ_INIT(&p2->p_selects); /* bump references to the text vnode (for procfs) */ p2->p_textvp = p1->p_textvp; if (p2->p_textvp) VREF(p2->p_textvp); if (flags & FORK_CLEANFILES) p2->p_fd = fdinit(p1); else if (flags & FORK_SHAREFILES) p2->p_fd = fdshare(p1); else p2->p_fd = fdcopy(p1); /* * If ps_limit is still copy-on-write, bump refcnt, * otherwise get a copy that won't be modified. * (If PL_SHAREMOD is clear, the structure is shared * copy-on-write.) */ #ifdef RTHREADS if (flags & FORK_THREAD) { /* nothing */ } else #endif { if (p1->p_p->ps_limit->p_lflags & PL_SHAREMOD) p2->p_p->ps_limit = limcopy(p1->p_p->ps_limit); else { p2->p_p->ps_limit = p1->p_p->ps_limit; p2->p_p->ps_limit->p_refcnt++; } } if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT) atomic_setbits_int(&p2->p_flag, P_CONTROLT); if (flags & FORK_PPWAIT) atomic_setbits_int(&p2->p_flag, P_PPWAIT); p2->p_pptr = p1; if (flags & FORK_NOZOMBIE) atomic_setbits_int(&p2->p_flag, P_NOZOMBIE); LIST_INIT(&p2->p_children); #ifdef KTRACE /* * Copy traceflag and tracefile if enabled. * If not inherited, these were zeroed above. */ if (p1->p_traceflag & KTRFAC_INHERIT) { p2->p_traceflag = p1->p_traceflag; if ((p2->p_tracep = p1->p_tracep) != NULL) VREF(p2->p_tracep); } #endif /* * set priority of child to be that of parent * XXX should move p_estcpu into the region of struct proc which gets * copied. */ scheduler_fork_hook(p1, p2); /* * Create signal actions for the child process. */ if (flags & FORK_SIGHAND) sigactsshare(p1, p2); else p2->p_sigacts = sigactsinit(p1); /* * If emulation has process fork hook, call it now. */ if (p2->p_emul->e_proc_fork) (*p2->p_emul->e_proc_fork)(p2, p1); p2->p_addr = (struct user *)uaddr; /* * Finish creating the child process. It will return through a * different path later. */ uvm_fork(p1, p2, ((flags & FORK_SHAREVM) ? TRUE : FALSE), stack, stacksize, func ? func : child_return, arg ? arg : p2); timeout_set(&p2->p_stats->p_virt_to, virttimer_trampoline, p2); timeout_set(&p2->p_stats->p_prof_to, proftimer_trampoline, p2); vm = p2->p_vmspace; if (flags & FORK_FORK) { forkstat.cntfork++; forkstat.sizfork += vm->vm_dsize + vm->vm_ssize; } else if (flags & FORK_VFORK) { forkstat.cntvfork++; forkstat.sizvfork += vm->vm_dsize + vm->vm_ssize; } else if (flags & FORK_RFORK) { forkstat.cntrfork++; forkstat.sizrfork += vm->vm_dsize + vm->vm_ssize; } else { forkstat.cntkthread++; forkstat.sizkthread += vm->vm_dsize + vm->vm_ssize; } /* Find an unused pid satisfying 1 <= lastpid <= PID_MAX */ do { lastpid = 1 + (randompid ? arc4random() : lastpid) % PID_MAX; } while (pidtaken(lastpid)); p2->p_pid = lastpid; LIST_INSERT_HEAD(&allproc, p2, p_list); LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash); LIST_INSERT_HEAD(&p1->p_children, p2, p_sibling); LIST_INSERT_AFTER(p1, p2, p_pglist); if (p2->p_flag & P_TRACED) { p2->p_oppid = p1->p_pid; if (p2->p_pptr != p1->p_pptr) proc_reparent(p2, p1->p_pptr); /* * Set ptrace status. */ if (flags & FORK_FORK) { p2->p_ptstat = malloc(sizeof(*p2->p_ptstat), M_SUBPROC, M_WAITOK); p1->p_ptstat->pe_report_event = PTRACE_FORK; p2->p_ptstat->pe_report_event = PTRACE_FORK; p1->p_ptstat->pe_other_pid = p2->p_pid; p2->p_ptstat->pe_other_pid = p1->p_pid; } } #if NSYSTRACE > 0 if (ISSET(p1->p_flag, P_SYSTRACE)) systrace_fork(p1, p2); #endif /* * Make child runnable, set start time, and add to run queue. */ SCHED_LOCK(s); getmicrotime(&p2->p_stats->p_start); p2->p_acflag = AFORK; p2->p_stat = SRUN; setrunqueue(p2); SCHED_UNLOCK(s); /* * Notify any interested parties about the new process. */ KNOTE(&p1->p_klist, NOTE_FORK | p2->p_pid); /* * Update stats now that we know the fork was successfull. */ uvmexp.forks++; if (flags & FORK_PPWAIT) uvmexp.forks_ppwait++; if (flags & FORK_SHAREVM) uvmexp.forks_sharevm++; /* * Pass a pointer to the new process to the caller. */ if (rnewprocp != NULL) *rnewprocp = p2; /* * Preserve synchronization semantics of vfork. If waiting for * child to exec or exit, set P_PPWAIT on child, and sleep on our * proc (in case of exit). */ if (flags & FORK_PPWAIT) while (p2->p_flag & P_PPWAIT) tsleep(p1, PWAIT, "ppwait", 0); /* * If we're tracing the child, alert the parent too. */ if ((flags & FORK_PTRACE) && (p1->p_flag & P_TRACED)) psignal(p1, SIGTRAP); /* * Return child pid to parent process, * marking us as parent via retval[1]. */ if (retval != NULL) { retval[0] = p2->p_pid; retval[1] = 0; } return (0); }
int backup_phase2_server(gzFile *cmanfp, const char *phase1data, const char *phase2data, const char *unchangeddata, const char *datadirtmp, struct dpth *dpth, const char *currentdata, const char *working, const char *client, struct cntr *p1cntr, int resume, struct cntr *cntr, struct config *cconf) { int ars=0; int ret=0; gzFile p1zp=NULL; char *deltmppath=NULL; char *last_requested=NULL; // Where to write phase2data. // Data is not getting written to a compressed file. // This is important for recovery if the power goes. FILE *p2fp=NULL; // unchanged data FILE *ucfp=NULL; int resume_partial=resume; struct sbuf cb; // file list in current manifest struct sbuf p1b; // file list from client struct sbuf rb; // receiving file from client init_sbuf(&cb); init_sbuf(&p1b); init_sbuf(&rb); if(!(p1zp=gzopen_file(phase1data, "rb"))) goto error; // Open in read+write mode, so that they can be read through if // we need to resume. // First, open them in a+ mode, so that they will be created if they // do not exist. if(!(ucfp=open_file(unchangeddata, "a+b"))) goto error; if(!(p2fp=open_file(phase2data, "a+b"))) goto error; close_fp(&ucfp); close_fp(&p2fp); if(!(ucfp=open_file(unchangeddata, "r+b"))) goto error; if(!(p2fp=open_file(phase2data, "r+b"))) goto error; if(resume && do_resume(p1zp, p2fp, ucfp, dpth, cconf, client, p1cntr, cntr)) goto error; logp("Begin phase2 (receive file data)\n"); if(!(deltmppath=prepend_s(working, "delta.tmp", strlen("delta.tmp")))) goto error; while(1) { int sts=0; // logp("in loop, %s %s %c\n", // *cmanfp?"got cmanfp":"no cmanfp", // rb.path?:"no rb.path", rb.path?'X':rb.cmd); if(rb.path) write_status(client, STATUS_BACKUP, rb.path, p1cntr, cntr); else write_status(client, STATUS_BACKUP, p1b.path, p1cntr, cntr); if((last_requested || !p1zp || writebuflen) && (ars=do_stuff_to_receive(&rb, p2fp, datadirtmp, dpth, working, &last_requested, deltmppath, cntr, cconf))) { if(ars<0) goto error; // 1 means ok. break; } if((sts=do_stuff_to_send(&p1b, &last_requested))<0) goto error; if(!sts && p1zp) { free_sbuf(&p1b); if((ars=sbuf_fill_phase1(NULL, p1zp, &p1b, cntr))) { if(ars<0) goto error; // ars==1 means it ended ok. gzclose_fp(&p1zp); //logp("ended OK - write phase2end"); if(async_write_str(CMD_GEN, "backupphase2end")) goto error; } //logp("check: %s\n", p1b.path); if(!*cmanfp) { // No old manifest, need to ask for a new file. //logp("no cmanfp\n"); if(process_new(&p1b, ucfp, currentdata, datadirtmp, deltmppath, dpth, &resume_partial, cntr, cconf)) goto error; } else { // Have an old manifest, look for it there. // Might already have it, or be ahead in the old // manifest. if(cb.path) { if((ars=maybe_process_file(&cb, &p1b, ucfp, currentdata, datadirtmp, deltmppath, dpth, &resume_partial, cntr, cconf))) { if(ars<0) goto error; // Do not free it - need to send stuff. continue; } //free_sbuf(&p1b); } while(*cmanfp) { free_sbuf(&cb); if((ars=sbuf_fill(NULL, *cmanfp, &cb, cntr))) { // ars==1 means it ended ok. if(ars<0) goto error; gzclose_fp(cmanfp); //logp("ran out of current manifest\n"); if(process_new(&p1b, ucfp, currentdata, datadirtmp, deltmppath, dpth, &resume_partial, cntr, cconf)) goto error; break; } //logp("against: %s\n", cb.path); if((ars=maybe_process_file(&cb, &p1b, ucfp, currentdata, datadirtmp, deltmppath, dpth, &resume_partial, cntr, cconf))) { if(ars<0) goto error; // Do not free it - need to send stuff. break; } } } } } goto end; error: ret=-1; end: if(close_fp(&p2fp)) { logp("error closing %s in backup_phase2_server\n", phase2data); ret=-1; } if(close_fp(&ucfp)) { logp("error closing %s in backup_phase2_server\n", unchangeddata); ret=-1; } free(deltmppath); free_sbuf(&cb); free_sbuf(&p1b); free_sbuf(&rb); gzclose_fp(&p1zp); if(!ret) unlink(phase1data); logp("End phase2 (receive file data)\n"); return ret; }