summaryrefslogtreecommitdiff
path: root/cmdline/apt-mark.cc
diff options
context:
space:
mode:
authorDavid Kalnischkies <david@kalnischkies.de>2014-11-09 15:40:19 +0100
committerDavid Kalnischkies <david@kalnischkies.de>2014-11-09 21:45:55 +0100
commit374f8492e6f109e8427816a8f513e5e8feda9049 (patch)
tree886df5303b11fbde0ea895abc26336bb4705fb91 /cmdline/apt-mark.cc
parent7824564bfde681eddf6969174bba7604d6f34848 (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/apt-mark.cc')
-rw-r--r--cmdline/apt-mark.cc63
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)