/* * dpkg - main program for package management * script.c - maintainer script routines * * Copyright © 1995 Ian Jackson * Copyright © 2007-2012 Guillem Jover * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "filesdb.h" #include "infodb.h" #include "main.h" void post_postinst_tasks(struct pkginfo *pkg, enum pkgstatus new_status) { if (new_status < stat_triggersawaited) pkg_set_status(pkg, new_status); else if (pkg->trigaw.head) pkg_set_status(pkg, stat_triggersawaited); else if (pkg->trigpend_head) pkg_set_status(pkg, stat_triggerspending); else pkg_set_status(pkg, stat_installed); post_postinst_tasks_core(pkg); } void post_postinst_tasks_core(struct pkginfo *pkg) { modstatdb_note(pkg); if (!f_noact) { debug(dbg_triggersdetail, "post_postinst_tasks_core - trig_incorporate"); trig_incorporate(msdbrw_write); } } static void post_script_tasks(void) { ensure_diversions(); debug(dbg_triggersdetail, "post_script_tasks - ensure_diversions; trig_incorporate"); trig_incorporate(msdbrw_write); } static void cu_post_script_tasks(int argc, void **argv) { post_script_tasks(); } static void setexecute(const char *path, struct stat *stab) { if ((stab->st_mode & 0555) == 0555) return; if (!chmod(path, 0755)) return; ohshite(_("unable to set execute permissions on `%.250s'"), path); } /** * Returns the path to the script inside the chroot. */ static const char * preexecscript(struct command *cmd) { const char *admindir = dpkg_db_get_dir(); size_t instdirl = strlen(instdir); if (*instdir) { if (strncmp(admindir, instdir, instdirl) != 0) ohshit(_("admindir must be inside instdir for dpkg to work properly")); if (setenv("DPKG_ADMINDIR", admindir + instdirl, 1) < 0) ohshite(_("unable to setenv for subprocesses")); if (chroot(instdir)) ohshite(_("failed to chroot to `%.250s'"), instdir); if (chdir("/")) ohshite(_("failed to chdir to `%.255s'"), "/"); } if (debug_has_flag(dbg_scripts)) { struct varbuf args = VARBUF_INIT; const char **argv = cmd->argv; while (*++argv) { varbuf_add_char(&args, ' '); varbuf_add_str(&args, *argv); } varbuf_end_str(&args); debug(dbg_scripts, "fork/exec %s (%s )", cmd->filename, args.buf); varbuf_destroy(&args); } if (!instdirl) return cmd->filename; assert(strlen(cmd->filename) >= instdirl); return cmd->filename + instdirl; } static int do_script(struct pkginfo *pkg, struct pkgbin *pkgbin, struct command *cmd, struct stat *stab, int warn) { pid_t pid; int r; setexecute(cmd->filename, stab); push_cleanup(cu_post_script_tasks, ehflag_bombout, NULL, 0, 0); pid = subproc_fork(); if (pid == 0) { if (setenv("DPKG_MAINTSCRIPT_PACKAGE", pkg->set->name, 1) || setenv("DPKG_MAINTSCRIPT_ARCH", pkgbin->arch->name, 1) || setenv("DPKG_MAINTSCRIPT_NAME", cmd->argv[0], 1) || setenv("DPKG_RUNNING_VERSION", PACKAGE_VERSION, 1)) ohshite(_("unable to setenv for maintainer script")); cmd->filename = cmd->argv[0] = preexecscript(cmd); command_exec(cmd); } subproc_signals_setup(cmd->name); /* This does a push_cleanup(). */ r = subproc_wait_check(pid, cmd->name, warn); pop_cleanup(ehflag_normaltidy); pop_cleanup(ehflag_normaltidy); return r; } static int vmaintainer_script_installed(struct pkginfo *pkg, const char *scriptname, const char *desc, va_list args) { struct command cmd; const char *scriptpath; struct stat stab; char buf[100]; scriptpath = pkg_infodb_get_file(pkg, &pkg->installed, scriptname); sprintf(buf, _("installed %s script"), desc); command_init(&cmd, scriptpath, buf); command_add_arg(&cmd, scriptname); command_add_argv(&cmd, args); if (stat(scriptpath, &stab)) { command_destroy(&cmd); if (errno == ENOENT) { debug(dbg_scripts, "vmaintainer_script_installed nonexistent %s", scriptname); return 0; } ohshite(_("unable to stat %s `%.250s'"), buf, scriptpath); } do_script(pkg, &pkg->installed, &cmd, &stab, 0); command_destroy(&cmd); return 1; } /* * All ...'s in maintainer_script_* are const char *'s. */ int maintainer_script_installed(struct pkginfo *pkg, const char *scriptname, const char *desc, ...) { va_list args; int r; va_start(args, desc); r = vmaintainer_script_installed(pkg, scriptname, desc, args); va_end(args); if (r) post_script_tasks(); return r; } int maintainer_script_postinst(struct pkginfo *pkg, ...) { va_list args; int r; va_start(args, pkg); r = vmaintainer_script_installed(pkg, POSTINSTFILE, "post-installation", args); va_end(args); if (r) ensure_diversions(); return r; } int maintainer_script_new(struct pkginfo *pkg, const char *scriptname, const char *desc, const char *cidir, char *cidirrest, ...) { struct command cmd; struct stat stab; va_list args; char buf[100]; strcpy(cidirrest, scriptname); sprintf(buf, _("new %s script"), desc); va_start(args, cidirrest); command_init(&cmd, cidir, buf); command_add_arg(&cmd, scriptname); command_add_argv(&cmd, args); va_end(args); if (stat(cidir, &stab)) { command_destroy(&cmd); if (errno == ENOENT) { debug(dbg_scripts, "maintainer_script_new nonexistent %s '%s'", scriptname, cidir); return 0; } ohshite(_("unable to stat %s `%.250s'"), buf, cidir); } do_script(pkg, &pkg->available, &cmd, &stab, 0); command_destroy(&cmd); post_script_tasks(); return 1; } int maintainer_script_alternative(struct pkginfo *pkg, const char *scriptname, const char *desc, const char *cidir, char *cidirrest, const char *ifok, const char *iffallback) { struct command cmd; const char *oldscriptpath; struct stat stab; char buf[100]; oldscriptpath = pkg_infodb_get_file(pkg, &pkg->installed, scriptname); sprintf(buf, _("old %s script"), desc); command_init(&cmd, oldscriptpath, buf); command_add_args(&cmd, scriptname, ifok, versiondescribe(&pkg->available.version, vdew_nonambig), NULL); if (stat(oldscriptpath, &stab)) { if (errno == ENOENT) { debug(dbg_scripts, "maintainer_script_alternative nonexistent %s '%s'", scriptname, oldscriptpath); command_destroy(&cmd); return 0; } warning(_("unable to stat %s '%.250s': %s"), cmd.name, oldscriptpath, strerror(errno)); } else { if (!do_script(pkg, &pkg->installed, &cmd, &stab, PROCWARN)) { command_destroy(&cmd); post_script_tasks(); return 1; } } fprintf(stderr, _("dpkg - trying script from the new package instead ...\n")); strcpy(cidirrest, scriptname); sprintf(buf, _("new %s script"), desc); command_destroy(&cmd); command_init(&cmd, cidir, buf); command_add_args(&cmd, scriptname, iffallback, versiondescribe(&pkg->installed.version, vdew_nonambig), NULL); if (stat(cidir, &stab)) { command_destroy(&cmd); if (errno == ENOENT) ohshit(_("there is no script in the new version of the package - giving up")); else ohshite(_("unable to stat %s `%.250s'"), buf, cidir); } do_script(pkg, &pkg->available, &cmd, &stab, 0); fprintf(stderr, _("dpkg: ... it looks like that went OK.\n")); command_destroy(&cmd); post_script_tasks(); return 1; }