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

Re: Bug#504880: Disambiguate "installed" for packages



On Wed, Jul 21, 2010 at 01:52:50PM -0700, Russ Allbery wrote:
> diff --git a/policy.sgml b/policy.sgml
> index 847f716..eb458fe 100644
> --- a/policy.sgml
> +++ b/policy.sgml
> @@ -1079,10 +1079,10 @@
>  	</p>
>  
>  	<p>
> -	  Sometimes, a package requires another package to be installed
> -	  <em>and</em> configured before it can be installed. In this
> -	  case, you must specify a <tt>Pre-Depends</tt> entry for
> -	  the package.
> +	  Sometimes, a package requires another package to be unpacked
> +	  <em>and</em> configured before it can be unpacked.  In this
> +	  case, the dependent package must specify this dependency in
> +	  the <tt>Pre-Depends</tt> control field.
>  	</p>
>  
>  	<p>

I think "depending package" is clearer than "dependent package", since
there's less possibility of confusion with "dependency".  (The usage
"dependent package" does not currently exist elsewhere in Policy.)

> +	      The package will not yet be unpacked, so
> +	      the <prgn>preinst</prgn> script cannot rely on any files
> +	      included in its package.  Only essential packages and
> +	      pre-dependencies (<tt>Pre-Depends</tt>) may be assumed to be
> +	      available.  Pre-dependencies will be at least unpacked.
> +	      They may be only unpacked or "Half-Configured", not
> +	      completely configured, but only if a previous version of the
> +	      pre-dependency was completely configured and the
> +	      pre-dependency had not been removed since then.
>  	    </item>

Maybe it would be clearer to write it this way?

  Pre-dependencies will have been configured at least once, but at the time
  the preinst is called they may only be in an unpacked or "Half-Configured"
  state if a previous version of the pre-dependency was completely
  configured and has not been removed (uninstalled?) since then.

Does dpkg provide any guarantee that the dependencies of the pre-dependency
are also present at this point?  If it doesn't, I think that should be
considered a bug in dpkg, since you may be invoking a command that links
against a library whose soname has changed since the last time the pre-dep
package was configured.  If it /does/ provide this guarantee, I think it
should be documented in Policy.


> +	  The <prgn>postinst</prgn> script may be called in the following
> +	  ways:
> +	  <taglist>
> +	    <tag><var>postinst</var> <tt>configure</tt>
> +	      <var>most-recently-configured-version</var></tag>
>  	    <item>
> -		<var>conflictor's-prerm</var> <tt>remove</tt>
> -		<tt>in-favour</tt> <var>package</var>
> -		<var>new-version</var>
> +	      The files contained in the package will be unpacked.  All
> +	      package dependencies will at least be unpacked.  If there
> +	      are no circular dependencies involved, all package
> +	      dependencies will be configured.
>  	    </item>

Should this include a pointer to the section documenting the rules for
breaking circular dependencies?

> +	      unpacked in some error situations.<footnote>
> +		For example, suppose packages foo and bar are installed
> +		with foo depending on bar.  If an upgrade of bar were
> +		started and then aborted, and then an attempt to remove
> +		foo failed because its <prgn>prerm</prgn> script failed,
> +		foo's <tt>postinst abort-remove</tt> would be called with
> +		bar only "Half-Installed".
> +	      </footnote>
>  	    </item>
> -	  </list>
> +	  </taglist>
> +	</p>

This footnote is interesting to me because although it accurately documents
dpkg's behavior, I'm not sure what implications it has for how packages
should guard against this case.  I think I've always ignored this possibility
in my maintainer scripts, and will continue to do so on the grounds that any
attempt to handle this gracefully is likely to introduce much greater
complexity (and therefore bugs) with very little upside (when all is said
and done, a package you were trying to remove is still installed, so do we
care if it configures successfully?)

If we can make a straightforward recommendation to maintainers for how to
handle this case, I think we should include that in the footnote.
Otherwise, if it shouldn't affect how we write maintainer scripts, perhaps
it's better not to have this footnote at all since it would only lead to
maintainers trying to be too clever and shooting themselves in the foot?

> +	<p>
> +	  The <prgn>postrm</prgn> script may be called in the following
> +	  ways:
> +	  <taglist>
> +	    <tag><var>postrm</var> <tt>remove</tt></tag>
> +	    <tag><var>postrm</var> <tt>purge</tt></tag>
> +	    <tag><var>old-postrm</var> <tt>upgrade</tt>
> +	      <var>new-version</var></tag>
> +	    <tag><var>disappearer's-postrm</var> <tt>disappear</tt>
> +		<var>overwriter</var> <var>overwriter-version</var></tag>
>  	    <item>
> -		<var>new-postrm</var> <tt>abort-install</tt>
> -		<var>old-version</var>
> +	      The <prgn>postrm</prgn> script is called after the package's
> +	      files have been removed or replaced.  The package
> +	      whose <prgn>postrm</prgn> is being called may have
> +	      previously been deconfigured and only be unpacked, at which
> +	      point subsequent package changes do not consider its
> +	      dependencies.  Therefore, all <prgn>postrm</prgn> actions
> +	      may only rely on essential packages and cannot assume that
> +	      the package's dependencies are available.
>  	    </item>

True as written, but less helpful than it should be.  There are a number of
cases where postrm scripts still need to *try* to invoke non-essential
functionality, and fail gracefully if it's unavailable; this should be
explicitly encouraged so that maintainers don't come away thinking they
shouldn't try to clean up after themselves.

Ex.: if you have a package that manages a config file with ucf, you *must*
call ucf --purge from "postrm purge" if ucf is present on the system at this
point; failure to do so will give completely unintuitive handling of the
config file on package purge && reinstall.

Proposed wording (improvements requested):

   Therefore, all <prgn>postrm</prgn> actions may only rely on essential
   packages and must gracefully omit anything requiring the package's
   dependencies when those dependencies are unavailable.

> -	  The <tt>Depends</tt> field thus allows package maintainers
> -	  to impose an order in which packages should be configured.
> +	  If there is a circular dependency among packages being installed
> +	  or removed, installation or removal order honoring the
> +	  dependency order is impossible, requiring the dependency loop be
> +	  broken at some point and the dependency requirements violated
> +	  for at least one package.  Packages involved in circular
> +	  dependencies may not be able to rely on their dependencies being
> +	  configured when being configured depending on which side of the
> +	  break of the circular dependency loop they happen to be on.  If
> +	  one of the packages in the loop has no <prgn>postinst</prgn>
> +	  script, then the cycle will be broken at that package; this
> +	  ensures that all <prgn>postinst</prgn> scripts are run with
> +	  their dependencies properly configured if this is possible.
> +	  Otherwise the breaking point is arbitrary.  Packages should
> +	  therefore avoid circular dependencies where possible,
> +	  particularly if they have <prgn>postinst</prgn> scripts.
>  	</p>
>  
>  	<p>

  --> Packages involved in circular dependencies may not be able to rely on
      their dependencies being configured before they themselves are
      configured, depending on which side of the break of the circular
      dependency loop they happen to be on.

> @@ -4588,12 +4651,17 @@ Build-Depends: foo [linux-any], bar [any-i386], baz [!linux-any]
>  
>  	      <p>
>  		The <tt>Depends</tt> field should also be used if the
> -		<prgn>postinst</prgn>, <prgn>prerm</prgn> or
> -		<prgn>postrm</prgn> scripts require the package to be
> -		present in order to run.  Note, however, that the
> -		<prgn>postrm</prgn> cannot rely on any non-essential
> -		packages to be present during the <tt>purge</tt>
> -		phase.
> +		<prgn>postinst</prgn> or <prgn>prerm</prgn> scripts
> +		require the depended-on package to be unpacked or
> +		configured in order to run.  In the case of <tt>postinst
> +		configure</tt>, the depended-on packages will be unpacked
> +		and configured first.  (If both packages are involved in a
> +		dependency loop, this might not work as expected; see the
> +		explanation a few paragraphs back.)  In the case
> +		of <prgn>prerm</prgn> or other <prgn>postinst</prgn>
> +		actions, the package dependencies will be at least
> +		unpacked or "Half-Installed".
> +	      </p>
>  	    </item>

I disagree with this change.  If you are making use of non-essential
packages in your postrm, you *should* use the Depends: field; you just
*also* have to have a clean fallback plan if the dependency is not satisfied
when the postrm is called.

The normal use case is "whichever of the two packages is removed first must
clean up".  While I can't think of a case where the cleanup interface called
from the postrm isn't already a dependency for other reasons (e.g., for use
in the postinst), I'd like this to be explicit all the same.


The rest looks good to me.

Thanks,
-- 
Steve Langasek                   Give me a lever long enough and a Free OS
Debian Developer                   to set it on, and I can move the world.
Ubuntu Developer                                    http://www.debian.org/
slangasek@ubuntu.com                                     vorlon@debian.org

Attachment: signature.asc
Description: Digital signature


Reply to: