[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#282278: apt mixes essential flag from all sources



retitle 282278 apt: please clarify warning about removing packages that are essential in another suite
# warning message
severity 282278 minor
quit

Vincent Lefevre wrote:

> WARNING: The following packages were essential in the past and will
> be removed. Though no longer essential, these packages may still be
> needed by other (older) packages. Please look at the description of
> these packages to see if it is safe to remove them.

Sounds fine to me, with the caveat that it's not safe to assume that
the release in which the package was essential is older.  This
condition could be tripped just as easily by the following sequence of
events:

 1. Package "foo", which exists but is not essential in squeeze,
    becomes essential in wheezy.

 2. Sysadmin downgrades foo to the version in squeeze (which is not
    flagged as Essential: yes).

 3. Sysadmin tries to remove foo.

Now, how to get the message in?  Might be better to ask an APT expert
that.  If I were doing it, the logic would be vaguely like this
(except probably I'd factor out a "spawn" function to decrease the
boilerplate).  Hopefully there's some appropriate APT API to look at
the dpkg status database or the appropriate Packages file for the
version of a package being removed.

Untested and probably broken in many ways.  Maybe it can inspire
something sane.

 cmdline/apt-get.cc |   74 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 74 insertions(+), 0 deletions(-)

diff --git i/cmdline/apt-get.cc w/cmdline/apt-get.cc
index 88e7346..7ca4b1b 100644
--- i/cmdline/apt-get.cc
+++ w/cmdline/apt-get.cc
@@ -505,6 +505,77 @@ bool ShowHold(ostream &out,CacheFile &Cache)
    return ShowList(out,_("The following held packages will be changed:"),List,VersionsList);
 }
 									/*}}}*/
+// StatusEssential - Ask dpkg whether a package is essential		/*{{{*/
+// ---------------------------------------------------------------------
+// Returns true on error, too.
+static bool StatusEssential(const pkgCache::PkgIterator &Pkg)
+{
+  string PkgName = Pkg.FullName(false);
+  int Pipes[2];
+
+  if (pipe(Pipes) != 0) {
+    _error->Errno("pipe",_("Failed to create pipes"));
+    return true;
+  }
+
+  pid_t Child = ExecFork();
+
+  if (Child == 0)
+  {
+    int Fd = open("/dev/null",O_RDWR);
+    if (Fd == -1)
+      _exit(101);
+    dup2(Fd,0);
+    dup2(Pipes[1],1);
+    dup2(Fd,2);
+    close(Fd);
+    close(Pipes[0]);
+    close(Pipes[1]);
+
+    const char *Args[5];
+    Args[0] = "dpkg-query";
+    Args[1] = "-W";
+    Args[2] = "-f=${Essential}";
+    Args[3] = PkgName.c_str();
+    Args[4] = 0;
+    execvp(Args[0],(char **)Args);
+    cerr << _("Failed to exec dpkg-query") << endl;
+    _exit(100);
+  }
+
+  FileFd InFd(Pipes[0]);
+  close(Pipes[1]);
+
+  bool Result;
+  unsigned char Buf[16];
+  unsigned long long Size
+
+  if (InFd.Read(Buf,sizeof(Buf),&Size) == false)
+    return true;
+  if (InFd.Eof() == false)
+  {
+    _error->Error(_("Unexpected output from dpkg-query"));
+    Result = true;
+  }
+  else if (Size == strlen("yes\n") && !memcmp(Buf, "yes\n", strlen("yes\n")))
+  {
+    Result = true;
+  }
+  else if (Size == strlen("no\n") && !memcmp(Buf, "no\n", strlen("no\n")))
+  {
+    Result = false;
+  }
+  else
+  {
+    _error->Error(_("Unexpected output from dpkg-query"));
+    Result = true;
+  }
+  InFd.Close();
+  if (ExecWait(Child,"dpkg-query",false))
+    return true;
+  return Result;
+}
+									/*}}}*/
 // ShowEssential - Show an essential package warning			/*{{{*/
 // ---------------------------------------------------------------------
 /* This prints out a warning message that is not to be ignored. It shows
@@ -541,6 +612,9 @@ bool ShowEssential(ostream &out,CacheFile &Cache)
       if (I->CurrentVer == 0)
 	 continue;
 
+      if (!StatusEssential(I))
+	List += " (only essential in another suite) ";
+
       // Print out any essential package depenendents that are to be removed
       for (pkgCache::DepIterator D = I.CurrentVer().DependsList(); D.end() == false; ++D)
       {
-- 



Reply to: