diff options
author | David Kalnischkies <david@kalnischkies.de> | 2014-11-09 15:40:19 +0100 |
---|---|---|
committer | David Kalnischkies <david@kalnischkies.de> | 2014-11-09 21:45:55 +0100 |
commit | 374f8492e6f109e8427816a8f513e5e8feda9049 (patch) | |
tree | 886df5303b11fbde0ea895abc26336bb4705fb91 /cmdline | |
parent | 7824564bfde681eddf6969174bba7604d6f34848 (diff) |
allow uninstalled packages to be put on hold
dpkg wants to know about a package before it can be put on hold, so we
have to at least hint about its existance in the available file it
"maintaince" to know about such stuff. The simple thing would probably
be to just feed all Packages files into dpkg as well, but what would be
the point really? Exactly, so we take a shortcut here and just create
dummies in the available file if we need to which isn't going to be that
common as usually you are holding packages back and not off.
Who would have thought that a simple feature like setting a package on
hold requires more than 200 lines of codeā¦ at least with the testcase it
is now explicitly tested code.
Diffstat (limited to 'cmdline')
-rw-r--r-- | cmdline/apt-mark.cc | 63 |
1 files changed, 57 insertions, 6 deletions
diff --git a/cmdline/apt-mark.cc b/cmdline/apt-mark.cc index 2702dbbd3..860982f9e 100644 --- a/cmdline/apt-mark.cc +++ b/cmdline/apt-mark.cc @@ -275,11 +275,65 @@ static bool DoHold(CommandLine &CmdL) } Args.erase(Args.begin() + BaseArgs, Args.end()); - Args.push_back("--set-selections"); + Args.push_back("--merge-avail"); + Args.push_back("-"); Args.push_back(NULL); int external[2] = {-1, -1}; if (pipe(external) != 0) + return _error->WarningE("DoHold", "Can't create IPC pipe for dpkg --merge-avail"); + + pid_t dpkgMergeAvail = ExecFork(); + if (dpkgMergeAvail == 0) + { + close(external[1]); + std::string const chrootDir = _config->FindDir("DPkg::Chroot-Directory"); + if (chrootDir != "/" && chroot(chrootDir.c_str()) != 0 && chdir("/") != 0) + _error->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --merge-avail", chrootDir.c_str()); + dup2(external[0], STDIN_FILENO); + int const nullfd = open("/dev/null", O_RDONLY); + dup2(nullfd, STDOUT_FILENO); + execvp(Args[0], (char**) &Args[0]); + _error->WarningE("dpkgGo", "Can't get dpkg --merge-avail running!"); + _exit(2); + } + + FILE* dpkg = fdopen(external[1], "w"); + for (APT::PackageList::iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg) + { + if (Pkg->CurrentVer != 0) + continue; + char const * Arch; + if (Pkg->VersionList != 0) + Arch = Pkg.VersionList().Arch(); + else + Arch = Pkg.Arch(); + fprintf(dpkg, "Package: %s\nVersion: 0~\nArchitecture: %s\nMaintainer: Dummy Example <dummy@example.org>\n" + "Description: dummy package record\n A record is needed to put a package on hold, so here it is.\n\n", Pkg.Name(), Arch); + } + fclose(dpkg); + + if (dpkgMergeAvail > 0) + { + int Status = 0; + while (waitpid(dpkgMergeAvail, &Status, 0) != dpkgMergeAvail) + { + if (errno == EINTR) + continue; + _error->WarningE("dpkgGo", _("Waited for %s but it wasn't there"), "dpkg --merge-avail"); + break; + } + if (WIFEXITED(Status) == false || WEXITSTATUS(Status) != 0) + return _error->Error(_("Executing dpkg failed. Are you root?")); + } + + Args.erase(Args.begin() + BaseArgs, Args.end()); + Args.push_back("--set-selections"); + Args.push_back(NULL); + + external[0] = -1; + external[1] = -1; + if (pipe(external) != 0) return _error->WarningE("DoHold", "Can't create IPC pipe for dpkg --set-selections"); pid_t dpkgSelection = ExecFork(); @@ -289,16 +343,13 @@ static bool DoHold(CommandLine &CmdL) std::string const chrootDir = _config->FindDir("DPkg::Chroot-Directory"); if (chrootDir != "/" && chroot(chrootDir.c_str()) != 0 && chdir("/") != 0) _error->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --set-selections", chrootDir.c_str()); - int const nullfd = open("/dev/null", O_RDONLY); dup2(external[0], STDIN_FILENO); - dup2(nullfd, STDOUT_FILENO); - dup2(nullfd, STDERR_FILENO); execvp(Args[0], (char**) &Args[0]); - _error->WarningE("dpkgGo", "Can't detect if dpkg supports multi-arch!"); + _error->WarningE("dpkgGo", "Can't get dpkg --set-selections running!"); _exit(2); } - FILE* dpkg = fdopen(external[1], "w"); + dpkg = fdopen(external[1], "w"); for (APT::PackageList::iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg) { if (dpkgMultiArch == false) |