inline static retvalue aptmethod_startup(struct aptmethod *method) { pid_t f; int mstdin[2]; int mstdout[2]; int r; /* When there is nothing to get, there is no reason to startup * the method. */ if (method->tobedone == NULL) { return RET_NOTHING; } /* when we are already running, we are already ready...*/ if (method->child > 0) { return RET_OK; } method->status = ams_waitforcapabilities; r = pipe(mstdin); if (r < 0) { int e = errno; fprintf(stderr, "Error %d creating pipe: %s\n", e, strerror(e)); return RET_ERRNO(e); } r = pipe(mstdout); if (r < 0) { int e = errno; (void)close(mstdin[0]); (void)close(mstdin[1]); fprintf(stderr, "Error %d in pipe syscall: %s\n", e, strerror(e)); return RET_ERRNO(e); } if (interrupted()) { (void)close(mstdin[0]);(void)close(mstdin[1]); (void)close(mstdout[0]);(void)close(mstdout[1]); return RET_ERROR_INTERRUPTED; } f = fork(); if (f < 0) { int e = errno; (void)close(mstdin[0]); (void)close(mstdin[1]); (void)close(mstdout[0]); (void)close(mstdout[1]); fprintf(stderr, "Error %d forking: %s\n", e, strerror(e)); return RET_ERRNO(e); } if (f == 0) { char *methodname; int e; /* child: */ (void)close(mstdin[1]); (void)close(mstdout[0]); if (dup2(mstdin[0], 0) < 0) { e = errno; fprintf(stderr, "Error %d while setting stdin: %s\n", e, strerror(e)); exit(255); } if (dup2(mstdout[1], 1) < 0) { e = errno; fprintf(stderr, "Error %d while setting stdout: %s\n", e, strerror(e)); exit(255); } closefrom(3); methodname = calc_dirconcat(global.methoddir, method->name); if (FAILEDTOALLOC(methodname)) exit(255); /* not really useful here, unless someone write reprepro * specific modules (which I hope noone will) */ sethookenvironment(NULL, NULL, NULL, NULL); /* actually call the method without any arguments: */ (void)execl(methodname, methodname, ENDOFARGUMENTS); e = errno; fprintf(stderr, "Error %d while executing '%s': %s\n", e, methodname, strerror(e)); exit(255); } /* the main program continues... */ method->child = f; if (verbose > 10) fprintf(stderr, "Method '%s' started as %d\n", method->baseuri, (int)f); (void)close(mstdin[0]); (void)close(mstdout[1]); markcloseonexec(mstdin[1]); markcloseonexec(mstdout[0]); method->mstdin = mstdin[1]; method->mstdout = mstdout[0]; method->inputbuffer = NULL; method->input_size = 0; method->alreadyread = 0; method->command = NULL; method->output_length = 0; method->alreadywritten = 0; return RET_OK; }
static retvalue callexporthook(/*@null@*/const char *hook, const char *relfilename, const char *mode, struct release *release) { pid_t f, c; int status; int io[2]; char buffer[1000]; int already = 0; if (hook == NULL) return RET_NOTHING; status = pipe(io); if (status < 0) { int e = errno; fprintf(stderr, "Error %d creating pipe: %s!\n", e, strerror(e)); return RET_ERRNO(e); } f = fork(); if (f < 0) { int e = errno; (void)close(io[0]); (void)close(io[1]); fprintf(stderr, "Error %d while forking for exporthook: %s\n", e, strerror(e)); return RET_ERRNO(e); } if (f == 0) { char *reltmpfilename; int e; if (dup2(io[1], 3) < 0) { e = errno; fprintf(stderr, "Error %d dup2'ing fd %d to 3: %s\n", e, io[1], strerror(e)); exit(255); } /* "Doppelt haelt besser": */ if (io[0] != 3) (void)close(io[0]); if (io[1] != 3) (void)close(io[1]); closefrom(4); /* backward compatibilty */ reltmpfilename = calc_addsuffix(relfilename, "new"); if (reltmpfilename == NULL) { exit(255); } setenv("REPREPRO_BASE_DIR", global.basedir, true); setenv("REPREPRO_OUT_DIR", global.outdir, true); setenv("REPREPRO_CONF_DIR", global.confdir, true); setenv("REPREPRO_DIST_DIR", global.distdir, true); setenv("REPREPRO_LOG_DIR", global.logdir, true); (void)execl(hook, hook, release_dirofdist(release), reltmpfilename, relfilename, mode, ENDOFARGUMENTS); e = errno; fprintf(stderr, "Error %d while executing '%s': %s\n", e, hook, strerror(e)); exit(255); } close(io[1]); markcloseonexec(io[0]); if (verbose > 6) printf("Called %s '%s' '%s.new' '%s' '%s'\n", hook, release_dirofdist(release), relfilename, relfilename, mode); /* read what comes from the client */ while (true) { ssize_t r; int last, j; r = read(io[0], buffer + already, 999 - already); if (r < 0) { int e = errno; fprintf(stderr, "Error %d reading from exporthook: %s!\n", e, strerror(e)); break; } already += r; if (r == 0) { buffer[already] = '\0'; already++; } last = 0; for (j = 0 ; j < already ; j++) { if (buffer[j] == '\n' || buffer[j] == '\0') { int next = j+1; int e = (j>0)?(j-1):j; retvalue ret; while (last < j && xisspace(buffer[last])) last++; if (last >= j) { last = next; continue; } while (xisspace(buffer[e])) { e--; assert (e >= last); } ret = gotfilename(buffer + last, e - last + 1, release); if (RET_WAS_ERROR(ret)) { (void)close(io[0]); return ret; } last = next; } } if (last > 0) { if (already > last) memmove(buffer, buffer + last, already - last); already -= last; } if (r == 0) break; } (void)close(io[0]); do { c = waitpid(f, &status, WUNTRACED); if (c < 0) { int e = errno; fprintf(stderr, "Error %d while waiting for hook '%s' to finish: %s\n", e, hook, strerror(e)); return RET_ERRNO(e); } } while (c != f); if (WIFEXITED(status)) { if (WEXITSTATUS(status) == 0) { if (verbose > 6) printf("Exporthook successfully returned!\n"); return RET_OK; } else { fprintf(stderr, "Exporthook failed with exitcode %d!\n", (int)WEXITSTATUS(status)); return RET_ERROR; } } else if (WIFSIGNALED(status)) { fprintf(stderr, "Exporthook killed by signal %d!\n", (int)(WTERMSIG(status))); return RET_ERROR; } else { fprintf(stderr, "Exporthook terminated abnormally. (status is %x)!\n", status); return RET_ERROR; } }