void trigproc_run_deferred(void) { jmp_buf ejbuf; char *pkgname; debug(dbg_triggers, "trigproc_run_deferred"); while (!pkg_queue_is_empty(&deferred)) { struct pkginfo *pkg; pkg = pkg_queue_pop(&deferred); if (!pkg) continue; pkgname = m_strdup(pkg_describe(pkg, pdo_foreign)); if (setjmp(ejbuf)) { pop_error_context(ehflag_bombout); free(pkgname); continue; } push_error_context_jump(&ejbuf, print_error_perpackage, pkgname); pkg->clientdata->trigprocdeferred = NULL; trigproc(pkg); pop_error_context(ehflag_normaltidy); free(pkgname); } }
void trigproc_run_deferred(void) { jmp_buf ejbuf; debug(dbg_triggers, "trigproc_run_deferred"); while (!pkg_queue_is_empty(&deferred)) { struct pkginfo *pkg; pkg = pkg_queue_pop(&deferred); if (!pkg) continue; if (setjmp(ejbuf)) { pop_error_context(ehflag_bombout); continue; } push_error_context_jump(&ejbuf, print_error_perpackage, pkg_name(pkg, pnaw_nonambig)); pkg->clientdata->trigprocdeferred = NULL; trigproc(pkg, TRIGPROC_TRY); pop_error_context(ehflag_normaltidy); } }
int main(int argc, char **argv) { struct tar_archive tar; struct tar_context tar_ctx; const char *tar_name = argv[1]; setvbuf(stdout, NULL, _IOLBF, 0); push_error_context(); if (tar_name) { tar_ctx.tar_fd = open(tar_name, O_RDONLY); if (tar_ctx.tar_fd < 0) ohshite("cannot open file '%s'", tar_name); } else { tar_ctx.tar_fd = STDIN_FILENO; } tar.err = DPKG_ERROR_OBJECT; tar.ctx = &tar_ctx; tar.ops = &tar_ops; if (tar_extractor(&tar)) ohshite("extracting tar"); if (tar_name) close(tar_ctx.tar_fd); pop_error_context(ehflag_normaltidy); return 0; }
/** * @brief Clean up after dpkg operations */ void dpkg_teardown(struct pkg_array *packages) { pkg_array_destroy(packages); pkg_db_reset(); modstatdb_done(); pop_error_context(ehflag_normaltidy); }
int main(int argc, char **argv) { const char *admindir = argv[1]; int ret; setvbuf(stdout, NULL, _IOLBF, 0); push_error_context(); if (admindir == NULL) ohshit("missing triggers deferred admindir"); ret = test_trigdeferred_parser(admindir); pop_error_context(ehflag_normaltidy); return ret; }
int commandfd(const char *const *argv) { struct varbuf linevb = VARBUF_INIT; const char * pipein; const char **newargs = NULL; char *ptr, *endptr; FILE *in; long infd; int ret = 0; int c, lno, i; bool skipchar; pipein = *argv++; if (pipein == NULL || *argv) badusage(_("--%s takes exactly one argument"), cipaction->olong); infd = dpkg_options_parse_arg_int(cipaction, pipein); in = fdopen(infd, "r"); if (in == NULL) ohshite(_("couldn't open '%i' for stream"), (int)infd); for (;;) { bool mode = false; int argc= 1; lno= 0; push_error_context(); do { c = getc(in); if (c == '\n') lno++; } while (c != EOF && c_isspace(c)); if (c == EOF) break; if (c == '#') { do { c= getc(in); if (c == '\n') lno++; } while (c != EOF && c != '\n'); continue; } varbuf_reset(&linevb); do { varbuf_add_char(&linevb, c); c= getc(in); if (c == '\n') lno++; /* This isn't fully accurate, but overestimating can't hurt. */ if (c_isspace(c)) argc++; } while (c != EOF && c != '\n'); if (c == EOF) ohshit(_("unexpected end of file before end of line %d"), lno); if (!argc) continue; varbuf_end_str(&linevb); newargs = m_realloc(newargs, sizeof(const char *) * (argc + 1)); argc= 1; ptr= linevb.buf; endptr = ptr + linevb.used + 1; skipchar = false; while(ptr < endptr) { if (skipchar) { skipchar = false; } else if (*ptr == '\\') { memmove(ptr, (ptr+1), (linevb.used-(linevb.buf - ptr)-1)); endptr--; skipchar = true; continue; } else if (c_isspace(*ptr)) { if (mode == true) { *ptr = '\0'; mode = false; } } else { if (mode == false) { newargs[argc]= ptr; argc++; mode = true; } } ptr++; } *ptr = '\0'; newargs[argc++] = NULL; /* We strdup() each argument, but never free it, because the * error messages contain references back to these strings. * Freeing them, and reusing the memory, would make those * error messages confusing, to say the least. */ for(i=1;i<argc;i++) if (newargs[i]) newargs[i] = m_strdup(newargs[i]); setaction(NULL, NULL); dpkg_options_parse((const char *const **)&newargs, cmdinfos, printforhelp); if (!cipaction) badusage(_("need an action option")); ret |= cipaction->action(newargs); pop_error_context(ehflag_normaltidy); } return ret; }
void commandfd(const char *const *argv) { struct varbuf linevb = VARBUF_INIT; const char * pipein; const char **newargs = NULL; char *ptr, *endptr; FILE *in; unsigned long infd; int c, lno, i; bool skipchar; void (*actionfunction)(const char *const *argv); pipein = *argv++; if (pipein == NULL) badusage(_("--command-fd takes one argument, not zero")); if (*argv) badusage(_("--command-fd only takes one argument")); errno = 0; infd = strtoul(pipein, &endptr, 10); if (pipein == endptr || *endptr || infd > INT_MAX) ohshite(_("invalid integer for --%s: `%.250s'"), "command-fd", pipein); if ((in= fdopen(infd, "r")) == NULL) ohshite(_("couldn't open `%i' for stream"), (int) infd); for (;;) { bool mode = false; int argc= 1; lno= 0; push_error_context(); do { c= getc(in); if (c == '\n') lno++; } while (c != EOF && isspace(c)); if (c == EOF) break; if (c == '#') { do { c= getc(in); if (c == '\n') lno++; } while (c != EOF && c != '\n'); continue; } varbufreset(&linevb); do { varbufaddc(&linevb,c); c= getc(in); if (c == '\n') lno++; /* This isn't fully accurate, but overestimating can't hurt. */ if (isspace(c)) argc++; } while (c != EOF && c != '\n'); if (c == EOF) ohshit(_("unexpected eof before end of line %d"),lno); if (!argc) continue; varbufaddc(&linevb,0); newargs = m_realloc(newargs, sizeof(const char *) * (argc + 1)); argc= 1; ptr= linevb.buf; endptr= ptr + linevb.used; skipchar = false; while(ptr < endptr) { if (skipchar) { skipchar = false; } else if (*ptr == '\\') { memmove(ptr, (ptr+1), (linevb.used-(linevb.buf - ptr)-1)); endptr--; skipchar = true; continue; } else if (isspace(*ptr)) { if (mode == true) { *ptr = '\0'; mode = false; } } else { if (mode == false) { newargs[argc]= ptr; argc++; mode = true; } } ptr++; } *ptr = '\0'; newargs[argc++] = NULL; /* We strdup() each argument, but never free it, because the * error messages contain references back to these strings. * Freeing them, and reusing the memory, would make those * error messages confusing, to say the least. */ for(i=1;i<argc;i++) if (newargs[i]) newargs[i] = m_strdup(newargs[i]); setaction(NULL, NULL); myopt((const char *const**)&newargs,cmdinfos); if (!cipaction) badusage(_("need an action option")); actionfunction= (void (*)(const char* const*))cipaction->farg; actionfunction(newargs); pop_error_context(ehflag_normaltidy); } }
void process_queue(void) { struct pkg_list *rundown; struct pkginfo *volatile pkg; volatile enum action action_todo; jmp_buf ejbuf; enum pkg_istobe istobe = PKG_ISTOBE_NORMAL; if (abort_processing) return; clear_istobes(); switch (cipaction->arg_int) { case act_triggers: case act_configure: case act_install: istobe = PKG_ISTOBE_INSTALLNEW; break; case act_remove: case act_purge: istobe = PKG_ISTOBE_REMOVE; break; default: internerr("unknown action '%d'", cipaction->arg_int); } for (rundown = queue.head; rundown; rundown = rundown->next) { ensure_package_clientdata(rundown->pkg); /* We have processed this package more than once. There are no duplicates * as we make sure of that when enqueuing them. */ if (rundown->pkg->clientdata->cmdline_seen > 1) { switch (cipaction->arg_int) { case act_triggers: case act_configure: case act_remove: case act_purge: printf(_("Package %s listed more than once, only processing once.\n"), pkg_name(rundown->pkg, pnaw_nonambig)); break; case act_install: printf(_("More than one copy of package %s has been unpacked\n" " in this run ! Only configuring it once.\n"), pkg_name(rundown->pkg, pnaw_nonambig)); break; default: internerr("unknown action '%d'", cipaction->arg_int); } } rundown->pkg->clientdata->istobe = istobe; } while (!pkg_queue_is_empty(&queue)) { pkg = pkg_queue_pop(&queue); if (!pkg) continue; /* Duplicate, which we removed earlier. */ ensure_package_clientdata(pkg); pkg->clientdata->enqueued = false; action_todo = cipaction->arg_int; if (sincenothing++ > queue.length * 3 + 2) { /* Make sure that even if we have exceeded the queue since not having * made any progress, we are not getting stuck trying to progress by * trigger processing, w/o jumping into the next dependtry. */ dependtry++; sincenothing = 0; if (dependtry >= DEPEND_TRY_LAST) internerr("exceeded dependtry %d (sincenothing=%d; queue.length=%d)", dependtry, sincenothing, queue.length); } else if (sincenothing > queue.length * 2 + 2) { if (dependtry >= DEPEND_TRY_TRIGGERS && progress_bytrigproc && progress_bytrigproc->trigpend_head) { enqueue_package(pkg); pkg = progress_bytrigproc; progress_bytrigproc = NULL; action_todo = act_configure; } else { dependtry++; sincenothing = 0; if (dependtry >= DEPEND_TRY_LAST) internerr("exceeded dependtry %d (sincenothing=%d, queue.length=%d)", dependtry, sincenothing, queue.length); } } debug(dbg_general, "process queue pkg %s queue.len %d progress %d, try %d", pkg_name(pkg, pnaw_always), queue.length, sincenothing, dependtry); if (pkg->status > PKG_STAT_INSTALLED) internerr("package %s status %d is out-of-bounds", pkg_name(pkg, pnaw_always), pkg->status); if (setjmp(ejbuf)) { /* Give up on it from the point of view of other packages, i.e. reset * istobe. */ pkg->clientdata->istobe = PKG_ISTOBE_NORMAL; pop_error_context(ehflag_bombout); if (abort_processing) return; continue; } push_error_context_jump(&ejbuf, print_error_perpackage, pkg_name(pkg, pnaw_nonambig)); switch (action_todo) { case act_triggers: if (!pkg->trigpend_head) ohshit(_("package %.250s is not ready for trigger processing\n" " (current status '%.250s' with no pending triggers)"), pkg_name(pkg, pnaw_nonambig), pkg_status_name(pkg)); /* Fall through. */ case act_install: /* Don't try to configure pkgs that we've just disappeared. */ if (pkg->status == PKG_STAT_NOTINSTALLED) break; /* Fall through. */ case act_configure: /* Do whatever is most needed. */ if (pkg->trigpend_head) trigproc(pkg, TRIGPROC_TRY_QUEUED); else deferred_configure(pkg); break; case act_remove: case act_purge: deferred_remove(pkg); break; default: internerr("unknown action '%d'", cipaction->arg_int); } m_output(stdout, _("<standard output>")); m_output(stderr, _("<standard error>")); pop_error_context(ehflag_normaltidy); } if (queue.length) internerr("finished package processing with non-empty queue length %d", queue.length); }
void archivefiles(const char *const *argv) { const char *volatile thisarg; const char *const *volatile argp; jmp_buf ejbuf; int pi[2], fc, nfiles, c, i, r; FILE *pf; static struct varbuf findoutput; const char **arglist; char *p; trigproc_install_hooks(); modstatdb_init(admindir, f_noact ? msdbrw_readonly : cipaction->arg == act_avail ? msdbrw_write : fc_nonroot ? msdbrw_write : msdbrw_needsuperuser); checkpath(); log_message("startup archives %s", cipaction->olong); if (f_recursive) { if (!*argv) badusage(_("--%s --recursive needs at least one path argument"),cipaction->olong); m_pipe(pi); fc = subproc_fork(); if (!fc) { struct command cmd; const char *const *ap; m_dup2(pi[1],1); close(pi[0]); close(pi[1]); command_init(&cmd, FIND, _("find for dpkg --recursive")); command_add_args(&cmd, FIND, "-L", NULL); for (ap = argv; *ap; ap++) { if (strchr(FIND_EXPRSTARTCHARS,(*ap)[0])) { char *a; a= m_malloc(strlen(*ap)+10); strcpy(a,"./"); strcat(a,*ap); command_add_arg(&cmd, a); } else { command_add_arg(&cmd, (const char *)*ap); } } command_add_args(&cmd, "-name", "*.deb", "-type", "f", "-print0", NULL); command_exec(&cmd); } close(pi[1]); nfiles= 0; pf= fdopen(pi[0],"r"); if (!pf) ohshite(_("failed to fdopen find's pipe")); varbufreset(&findoutput); while ((c= fgetc(pf)) != EOF) { varbufaddc(&findoutput,c); if (!c) nfiles++; } if (ferror(pf)) ohshite(_("error reading find's pipe")); if (fclose(pf)) ohshite(_("error closing find's pipe")); r = subproc_wait_check(fc, "find", PROCNOERR); if (r != 0) ohshit(_("find for --recursive returned unhandled error %i"),r); if (!nfiles) ohshit(_("searched, but found no packages (files matching *.deb)")); varbufaddc(&findoutput,0); varbufaddc(&findoutput,0); arglist= m_malloc(sizeof(char*)*(nfiles+1)); p= findoutput.buf; i=0; while (*p) { arglist[i++]= p; while (*p++ != '\0') ; } arglist[i] = NULL; argp= arglist; } else { if (!*argv) badusage(_("--%s needs at least one package archive file argument"), cipaction->olong); argp= argv; } currenttime = time(NULL); /* Initialize fname variables contents. */ varbufreset(&fnamevb); varbufreset(&fnametmpvb); varbufreset(&fnamenewvb); varbufaddstr(&fnamevb,instdir); varbufaddc(&fnamevb,'/'); varbufaddstr(&fnametmpvb,instdir); varbufaddc(&fnametmpvb,'/'); varbufaddstr(&fnamenewvb,instdir); varbufaddc(&fnamenewvb,'/'); fnameidlu= fnamevb.used; ensure_diversions(); ensure_statoverrides(); while ((thisarg = *argp++) != NULL) { if (setjmp(ejbuf)) { pop_error_context(ehflag_bombout); if (abort_processing) break; continue; } push_error_context_jump(&ejbuf, print_error_perpackage, thisarg); process_archive(thisarg); onerr_abort++; m_output(stdout, _("<standard output>")); m_output(stderr, _("<standard error>")); onerr_abort--; pop_error_context(ehflag_normaltidy); } switch (cipaction->arg) { case act_install: case act_configure: case act_triggers: case act_remove: case act_purge: process_queue(); case act_unpack: case act_avail: break; default: internerr("unknown action '%d'", cipaction->arg); } trigproc_run_deferred(); modstatdb_shutdown(); }
/** * Default fatal error handler. * * This handler performs all error unwinding for the current context, and * terminates the program with an error exit code. */ void catch_fatal_error(void) { pop_error_context(ehflag_bombout); exit(2); }
void process_queue(void) { struct pkg_list *rundown; struct pkginfo *volatile pkg; volatile enum action action_todo; jmp_buf ejbuf; enum istobes istobe= itb_normal; if (abort_processing) return; clear_istobes(); switch (cipaction->arg_int) { case act_triggers: case act_configure: case act_install: istobe= itb_installnew; break; case act_remove: case act_purge: istobe= itb_remove; break; default: internerr("unknown action '%d'", cipaction->arg_int); } for (rundown = queue.head; rundown; rundown = rundown->next) { ensure_package_clientdata(rundown->pkg); if (rundown->pkg->clientdata->istobe == istobe) { /* Erase the queue entry - this is a second copy! */ switch (cipaction->arg_int) { case act_triggers: case act_configure: case act_remove: case act_purge: printf(_("Package %s listed more than once, only processing once.\n"), pkg_name(rundown->pkg, pnaw_nonambig)); break; case act_install: printf(_("More than one copy of package %s has been unpacked\n" " in this run ! Only configuring it once.\n"), pkg_name(rundown->pkg, pnaw_nonambig)); break; default: internerr("unknown action '%d'", cipaction->arg_int); } rundown->pkg = NULL; } else { rundown->pkg->clientdata->istobe= istobe; } } while (!pkg_queue_is_empty(&queue)) { pkg = pkg_queue_pop(&queue); if (!pkg) continue; /* Duplicate, which we removed earlier. */ action_todo = cipaction->arg_int; if (sincenothing++ > queue.length * 2 + 2) { if (progress_bytrigproc && progress_bytrigproc->trigpend_head) { enqueue_package(pkg); pkg = progress_bytrigproc; action_todo = act_configure; } else { dependtry++; sincenothing = 0; assert(dependtry <= 4); } } assert(pkg->status <= stat_installed); if (setjmp(ejbuf)) { /* Give up on it from the point of view of other packages, i.e. reset * istobe. */ pkg->clientdata->istobe= itb_normal; pop_error_context(ehflag_bombout); if (abort_processing) return; continue; } push_error_context_jump(&ejbuf, print_error_perpackage, pkg_name(pkg, pnaw_nonambig)); switch (action_todo) { case act_triggers: if (!pkg->trigpend_head) ohshit(_("package %.250s is not ready for trigger processing\n" " (current status `%.250s' with no pending triggers)"), pkg_name(pkg, pnaw_nonambig), statusinfos[pkg->status].name); /* Fall through. */ case act_install: /* Don't try to configure pkgs that we've just disappeared. */ if (pkg->status == stat_notinstalled) break; /* Fall through. */ case act_configure: /* Do whatever is most needed. */ if (pkg->trigpend_head) trigproc(pkg); else deferred_configure(pkg); break; case act_remove: case act_purge: deferred_remove(pkg); break; default: internerr("unknown action '%d'", cipaction->arg_int); } m_output(stdout, _("<standard output>")); m_output(stderr, _("<standard error>")); pop_error_context(ehflag_normaltidy); } assert(!queue.length); }