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

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



Steve Langasek wrote:
> On Wed, Jul 21, 2010 at 01:52:50PM -0700, Russ Allbery wrote:

>>	                                                      In this
>> +	  case, the dependent package must specify this dependency in
>> +	  the <tt>Pre-Depends</tt> control field.
[...]
> I think "depending package" is clearer than "dependent package", since
> there's less possibility of confusion with "dependency".

Yes.  It is a case like the avoidance of “inflammable”.  Sometimes
people need an answer from policy without enough time to think about
etymology.

>> +	                  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.

Your phrasing is more straightforward.

I prefer removed over uninstalled because the corresponding dpkg
action is “dpkg --remove”.  Anyway, such a change throughout policy
would be a separate topic.

> Does dpkg provide any guarantee that the dependencies of the pre-dependency
> are also present at this point?

Sure: that is part of what it means to configure a package.

Except *new* dependencies of an upgraded pre-depedency may not be
present.  This is part of the philosophy behind pseudo-essential
packages generally using pre-depends for one release when they
acquire new dependencies.

> 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.

Should I file a policy bug to clarify this?

>> +	    <tag><var>postinst</var> <tt>configure</tt>
[...]
>>	                                                       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?

Maybe something as simple as “(See also <ref id="binarydeps">)”.

>> +	      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.

Hopefully Russ can say something useful on this.  My guess is “make
sure you error out with an appropriate message if functionality from a
dependency fails”.  That way, the recovery process can error out and
the operator can deal with the problem, for example by reinstalling
the dependency.

Instead, let me mention how rare this problem should be in practice:
the problem we are describing is that an upgrade (for a dependency)
can be interrupted in the middle of unpacking.

dpkg unpacks in three stages: first it writes some temporary files,
then a storm of renames, then deletion of removed files.  The
problem we are describing is that the renames (or deletions) can be
interrupted in the middle.

The impact is that some files might be from the old version and others
from the new version of the dependency.  As luck has it, most packages
still Just Work™ in this scenario.

> 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?

Maybe something to this effect:

	With luck, such a partially upgraded package would still
	work fine, but maintainer scripts should be prepared to
	report and error out on resulting errors if they occur.

If there is a way to test this automatically (an enhancement to piuparts,
maybe?), that would be ideal.

[...]
>> +	      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.
[...]
> 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

Yes, that is worth mentioning.  Actually it has very little to do with
dependencies.

For example, many packages only use “Suggests: doc-base” but have
snippets like the following in prerm:

	# Automatically added by dh_installdocs
	if [ "$1" = remove ] || [ "$1" = upgrade ] && \
	   which install-docs >/dev/null 2>&1; then
		install-docs -r whatever
	fi

Maybe a footnote would be appropriate?  Something along these lines:

	This is not intended to excuse packages from the obligation
	to clean up after themselves when they have placed some
	state in a non-essential package's care.  The usual strategy
	for that is as follows:

	If you have a package that manages a configuration file
	with ucf, you must call "ucf --purge" from postrm if ucf is
	present on the system at that point.  If ucf is not present,
	then the configuration file is in its care and will be
	removed when ucf is purged.

>   --> 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.

I’ve tried to incorporate this text below.

>> @@ -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.
>> +		<prgn>postinst</prgn> or <prgn>prerm</prgn> scripts
>> +		require the depended-on package to be unpacked or
>> +		configured in order to run.
[...]
> I disagree with this change.
[...]
> 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.

Given the explanation above, do you still think Depends should be used
this way?

> The rest looks good to me.

Thanks for the review.  Suggested changes follow; thoughts welcome.
-- 8< --
Subject: Further improvements to maintainer script state requirements
    
Based on feedback from Steve Langasek.
---
Should be applicable to bug504880-rra with “git am -i --scissors”.

diff --git a/policy.sgml b/policy.sgml
index 20c0c84..9bfb652 100644
--- a/policy.sgml
+++ b/policy.sgml
@@ -1081,7 +1081,7 @@
 	<p>
 	  Sometimes, unpacking one package requires that another package
 	  be first unpacked <em>and</em> configured.  In this case, the
-	  dependent package must specify this dependency in
+	  depending package must specify this dependency in
 	  the <tt>Pre-Depends</tt> control field.
 	</p>
 
@@ -3791,11 +3791,11 @@ Checksums-Sha256:
 	      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.
+	      available.  Pre-dependencies will have been configured at
+	      least once, but at the time the <prgn>preinst</prgn> script
+	      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 since then.
 	    </item>
 
 	    <tag><var>old-preinst</var> <tt>abort-upgrade</tt>
@@ -3829,6 +3829,7 @@ Checksums-Sha256:
 	      package dependencies will at least be unpacked.  If there
 	      are no circular dependencies involved, all package
 	      dependencies will be configured.
+	      (See also <ref id="binarydeps">.)
 	    </item>
 
 	    <tag><var>old-postinst</var> <tt>abort-upgrade</tt>
@@ -3848,12 +3849,20 @@ Checksums-Sha256:
 	      will have previously been configured and not removed.
 	      However, dependencies may not be configured or even fully
 	      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".
+	        <p>
+		  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".
+		</p>
+
+		<p>
+		  With luck, the partially upgraded dependency would still
+		  work fine, but <prgn>postinst</prgn> should be prepared to
+		  report and error out on resulting errors when they occur.
+		</p>
 	      </footnote>
 	    </item>
 	  </taglist>
@@ -3911,7 +3920,21 @@ Checksums-Sha256:
 	      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.
+	      the package's dependencies are available.<footnote>
+		<p>
+		  This is not intended to excuse packages from the
+		  obligation to clean up after themselves when they have
+		  placed some state in a non-essential package's care.
+		  The usual strategy for that is as follows:
+		</p>
+		<p>
+		  If you have a package that manages a configuration file
+		  with ucf, you must call "ucf --purge" from postrm if
+		  ucf is present on the system at that point.
+		  If ucf is not present, then the configuration file is
+		  in its care and will be removed when ucf is purged.
+		</p>
+	      </footnote>
 	    </item>
 
 	    <tag><var>new-postrm</var> <tt>failed-upgrade</tt>
@@ -4645,9 +4668,16 @@ Build-Depends: foo [linux-any], bar [any-i386], baz [!linux-any]
 	  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.
+	  Otherwise the breaking point is arbitrary.
+	</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.
+	  Packages should therefore avoid circular dependencies where
+	  possible, particularly if they have <prgn>postinst</prgn> scripts.
 	</p>
 
 	<p>
-- 


Reply to: