awful debugging hacking
[dpkg] / src / enquiry.c
1 /*
2 * dpkg - main program for package management
3 * enquiry.c - status enquiry and listing options
4 *
5 * Copyright © 1995,1996 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 * Copyright © 2006, 2008-2016 Guillem Jover <guillem@debian.org>
7 * Copyright © 2011 Linaro Limited
8 * Copyright © 2011 Raphaël Hertzog <hertzog@debian.org>
9 *
10 * This is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
24 #include <config.h>
25 #include <compat.h>
26
27 #include <sys/types.h>
28
29 #include <assert.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <stdbool.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36
37 #include <dpkg/i18n.h>
38 #include <dpkg/dpkg.h>
39 #include <dpkg/dpkg-db.h>
40 #include <dpkg/arch.h>
41 #include <dpkg/pkg-array.h>
42 #include <dpkg/pkg-show.h>
43 #include <dpkg/triglib.h>
44 #include <dpkg/string.h>
45 #include <dpkg/options.h>
46
47 #include "filesdb.h"
48 #include "infodb.h"
49 #include "main.h"
50
51 struct audit_problem {
52 bool (*check)(struct pkginfo *, const struct audit_problem *problem);
53 union {
54 int number;
55 const char *string;
56 } value;
57 const char *explanation;
58 };
59
60 static bool
61 audit_reinstreq(struct pkginfo *pkg, const struct audit_problem *problem)
62 {
63 return pkg->eflag & PKG_EFLAG_REINSTREQ;
64 }
65
66 static bool
67 audit_status(struct pkginfo *pkg, const struct audit_problem *problem)
68 {
69 if (pkg->eflag & PKG_EFLAG_REINSTREQ)
70 return false;
71 return (int)pkg->status == problem->value.number;
72 }
73
74 static bool
75 audit_infofile(struct pkginfo *pkg, const struct audit_problem *problem)
76 {
77 if (pkg->status < PKG_STAT_HALFINSTALLED)
78 return false;
79 return !pkg_infodb_has_file(pkg, &pkg->installed, problem->value.string);
80 }
81
82 static bool
83 audit_arch(struct pkginfo *pkg, const struct audit_problem *problem)
84 {
85 if (pkg->status < PKG_STAT_HALFINSTALLED)
86 return false;
87 return pkg->installed.arch->type == (enum dpkg_arch_type)problem->value.number;
88 }
89
90 static const struct audit_problem audit_problems[] = {
91 {
92 .check = audit_reinstreq,
93 .value.number = 0,
94 .explanation = N_(
95 "The following packages are in a mess due to serious problems during\n"
96 "installation. They must be reinstalled for them (and any packages\n"
97 "that depend on them) to function properly:\n")
98 }, {
99 .check = audit_status,
100 .value.number = PKG_STAT_UNPACKED,
101 .explanation = N_(
102 "The following packages have been unpacked but not yet configured.\n"
103 "They must be configured using dpkg --configure or the configure\n"
104 "menu option in dselect for them to work:\n")
105 }, {
106 .check = audit_status,
107 .value.number = PKG_STAT_HALFCONFIGURED,
108 .explanation = N_(
109 "The following packages are only half configured, probably due to problems\n"
110 "configuring them the first time. The configuration should be retried using\n"
111 "dpkg --configure <package> or the configure menu option in dselect:\n")
112 }, {
113 .check = audit_status,
114 .value.number = PKG_STAT_HALFINSTALLED,
115 .explanation = N_(
116 "The following packages are only half installed, due to problems during\n"
117 "installation. The installation can probably be completed by retrying it;\n"
118 "the packages can be removed using dselect or dpkg --remove:\n")
119 }, {
120 .check = audit_status,
121 .value.number = PKG_STAT_TRIGGERSAWAITED,
122 .explanation = N_(
123 "The following packages are awaiting processing of triggers that they\n"
124 "have activated in other packages. This processing can be requested using\n"
125 "dselect or dpkg --configure --pending (or dpkg --triggers-only):\n")
126 }, {
127 .check = audit_status,
128 .value.number = PKG_STAT_TRIGGERSPENDING,
129 .explanation = N_(
130 "The following packages have been triggered, but the trigger processing\n"
131 "has not yet been done. Trigger processing can be requested using\n"
132 "dselect or dpkg --configure --pending (or dpkg --triggers-only):\n")
133 }, {
134 .check = audit_infofile,
135 .value.string = LISTFILE,
136 .explanation = N_(
137 "The following packages are missing the list control file in the\n"
138 "database, they need to be reinstalled:\n")
139 }, {
140 .check = audit_infofile,
141 .value.string = HASHFILE,
142 .explanation = N_(
143 "The following packages are missing the md5sums control file in the\n"
144 "database, they need to be reinstalled:\n")
145 }, {
146 .check = audit_arch,
147 .value.number = DPKG_ARCH_EMPTY,
148 .explanation = N_("The following packages do not have an architecture:\n")
149 }, {
150 .check = audit_arch,
151 .value.number = DPKG_ARCH_ILLEGAL,
152 .explanation = N_("The following packages have an illegal architecture:\n")
153 }, {
154 .check = audit_arch,
155 .value.number = DPKG_ARCH_UNKNOWN,
156 .explanation = N_(
157 "The following packages have an unknown foreign architecture, which will\n"
158 "cause dependency issues on front-ends. This can be fixed by registering\n"
159 "the foreign architecture with dpkg --add-architecture:\n")
160 }, {
161 .check = NULL
162 }
163 };
164
165 static void describebriefly(struct pkginfo *pkg) {
166 int maxl, l;
167 const char *pdesc;
168
169 maxl= 57;
170 l= strlen(pkg->set->name);
171 if (l>20) maxl -= (l-20);
172
173 pdesc = pkgbin_summary(pkg, &pkg->installed, &l);
174 l = min(l, maxl);
175
176 printf(" %-20s %.*s\n", pkg_name(pkg, pnaw_nonambig), l, pdesc);
177 }
178
179 static struct pkginfo *
180 pkg_array_mapper(const char *name)
181 {
182 struct pkginfo *pkg;
183
184 pkg = dpkg_options_parse_pkgname(cipaction, name);
185 if (pkg->status == PKG_STAT_NOTINSTALLED)
186 notice(_("package '%s' is not installed"), pkg_name(pkg, pnaw_nonambig));
187
188 return pkg;
189 }
190
191 int
192 audit(const char *const *argv)
193 {
194 const struct audit_problem *problem;
195 struct pkg_array array;
196 bool head_running = false;
197 int i;
198
199 modstatdb_open(msdbrw_readonly);
200
201 if (!*argv)
202 pkg_array_init_from_db(&array);
203 else
204 pkg_array_init_from_names(&array, pkg_array_mapper, (const char **)argv);
205
206 pkg_array_sort(&array, pkg_sorter_by_nonambig_name_arch);
207
208 for (problem = audit_problems; problem->check; problem++) {
209 bool head = false;
210
211 for (i = 0; i < array.n_pkgs; i++) {
212 struct pkginfo *pkg = array.pkgs[i];
213
214 if (!problem->check(pkg, problem))
215 continue;
216 if (!head_running) {
217 if (modstatdb_is_locked())
218 puts(_(
219 "Another process has locked the database for writing, and might currently be\n"
220 "modifying it, some of the following problems might just be due to that.\n"));
221 head_running = true;
222 }
223 if (!head) {
224 fputs(gettext(problem->explanation), stdout);
225 head = true;
226 }
227 describebriefly(pkg);
228 }
229
230 if (head) putchar('\n');
231 }
232
233 pkg_array_destroy(&array);
234
235 m_output(stdout, _("<standard output>"));
236
237 return 0;
238 }
239
240 struct sectionentry {
241 struct sectionentry *next;
242 const char *name;
243 int count;
244 };
245
246 static bool
247 yettobeunpacked(struct pkginfo *pkg, const char **thissect)
248 {
249 if (pkg->want != PKG_WANT_INSTALL)
250 return false;
251
252 switch (pkg->status) {
253 case PKG_STAT_UNPACKED:
254 case PKG_STAT_INSTALLED:
255 case PKG_STAT_HALFCONFIGURED:
256 case PKG_STAT_TRIGGERSPENDING:
257 case PKG_STAT_TRIGGERSAWAITED:
258 return false;
259 case PKG_STAT_NOTINSTALLED:
260 case PKG_STAT_HALFINSTALLED:
261 case PKG_STAT_CONFIGFILES:
262 if (thissect)
263 *thissect = str_is_set(pkg->section) ? pkg->section :
264 C_("section", "<unknown>");
265 return true;
266 default:
267 internerr("unknown package status '%d'", pkg->status);
268 }
269 return false;
270 }
271
272 int
273 unpackchk(const char *const *argv)
274 {
275 int totalcount, sects;
276 struct sectionentry *sectionentries, *se, **sep;
277 struct pkgiterator *iter;
278 struct pkginfo *pkg;
279 const char *thissect;
280 char buf[20];
281 int width;
282
283 if (*argv)
284 badusage(_("--%s takes no arguments"), cipaction->olong);
285
286 modstatdb_open(msdbrw_readonly);
287
288 totalcount= 0;
289 sectionentries = NULL;
290 sects= 0;
291 iter = pkg_db_iter_new();
292 while ((pkg = pkg_db_iter_next_pkg(iter))) {
293 if (!yettobeunpacked(pkg, &thissect)) continue;
294 for (se= sectionentries; se && strcasecmp(thissect,se->name); se= se->next);
295 if (!se) {
296 se= nfmalloc(sizeof(struct sectionentry));
297 for (sep= &sectionentries;
298 *sep && strcasecmp(thissect,(*sep)->name) > 0;
299 sep= &(*sep)->next);
300 se->name= thissect;
301 se->count= 0;
302 se->next= *sep;
303 *sep= se;
304 sects++;
305 }
306 se->count++; totalcount++;
307 }
308 pkg_db_iter_free(iter);
309
310 if (totalcount == 0)
311 return 0;
312
313 if (totalcount <= 12) {
314 iter = pkg_db_iter_new();
315 while ((pkg = pkg_db_iter_next_pkg(iter))) {
316 if (!yettobeunpacked(pkg, NULL))
317 continue;
318 describebriefly(pkg);
319 }
320 pkg_db_iter_free(iter);
321 } else if (sects <= 12) {
322 for (se= sectionentries; se; se= se->next) {
323 sprintf(buf,"%d",se->count);
324 printf(_(" %d in %s: "),se->count,se->name);
325 width= 70-strlen(se->name)-strlen(buf);
326 while (width > 59) { putchar(' '); width--; }
327 iter = pkg_db_iter_new();
328 while ((pkg = pkg_db_iter_next_pkg(iter))) {
329 const char *pkgname;
330
331 if (!yettobeunpacked(pkg,&thissect)) continue;
332 if (strcasecmp(thissect,se->name)) continue;
333 pkgname = pkg_name(pkg, pnaw_nonambig);
334 width -= strlen(pkgname);
335 width--;
336 if (width < 4) { printf(" ..."); break; }
337 printf(" %s", pkgname);
338 }
339 pkg_db_iter_free(iter);
340 putchar('\n');
341 }
342 } else {
343 printf(P_(" %d package, from the following section:",
344 " %d packages, from the following sections:", totalcount),
345 totalcount);
346 width= 0;
347 for (se= sectionentries; se; se= se->next) {
348 sprintf(buf,"%d",se->count);
349 width -= (6 + strlen(se->name) + strlen(buf));
350 if (width < 0) { putchar('\n'); width= 73 - strlen(se->name) - strlen(buf); }
351 printf(" %s (%d)",se->name,se->count);
352 }
353 putchar('\n');
354 }
355
356 m_output(stdout, _("<standard output>"));
357
358 return 0;
359 }
360
361 static int
362 assert_version_support(const char *const *argv,
363 struct dpkg_version *version,
364 const char *feature_name)
365 {
366 struct pkginfo *pkg;
367
368 if (*argv)
369 badusage(_("--%s takes no arguments"), cipaction->olong);
370
371 modstatdb_open(msdbrw_readonly);
372
373 pkg = pkg_db_find_singleton("dpkg");
374 switch (pkg->status) {
375 case PKG_STAT_INSTALLED:
376 case PKG_STAT_TRIGGERSPENDING:
377 return 0;
378 case PKG_STAT_UNPACKED:
379 case PKG_STAT_HALFCONFIGURED:
380 case PKG_STAT_HALFINSTALLED:
381 case PKG_STAT_TRIGGERSAWAITED:
382 if (dpkg_version_relate(&pkg->configversion, DPKG_RELATION_GE, version))
383 return 0;
384 printf(_("Version of dpkg with working %s support not yet configured.\n"
385 " Please use 'dpkg --configure dpkg', and then try again.\n"),
386 feature_name);
387 return 1;
388 default:
389 printf(_("dpkg not recorded as installed, cannot check for %s support!\n"),
390 feature_name);
391 return 1;
392 }
393 }
394
395 int
396 assertpredep(const char *const *argv)
397 {
398 struct dpkg_version version = { 0, "1.1.0", NULL };
399
400 return assert_version_support(argv, &version, _("Pre-Depends field"));
401 }
402
403 int
404 assertepoch(const char *const *argv)
405 {
406 struct dpkg_version version = { 0, "1.4.0.7", NULL };
407
408 return assert_version_support(argv, &version, _("epoch"));
409 }
410
411 int
412 assertlongfilenames(const char *const *argv)
413 {
414 struct dpkg_version version = { 0, "1.4.1.17", NULL };
415
416 return assert_version_support(argv, &version, _("long filenames"));
417 }
418
419 int
420 assertmulticonrep(const char *const *argv)
421 {
422 struct dpkg_version version = { 0, "1.4.1.19", NULL };
423
424 return assert_version_support(argv, &version,
425 _("multiple Conflicts and Replaces"));
426 }
427
428 int
429 assertmultiarch(const char *const *argv)
430 {
431 struct dpkg_version version = { 0, "1.16.2", NULL };
432
433 return assert_version_support(argv, &version, _("multi-arch"));
434 }
435
436 int
437 assertverprovides(const char *const *argv)
438 {
439 struct dpkg_version version = { 0, "1.17.11", NULL };
440
441 return assert_version_support(argv, &version, _("versioned Provides"));
442 }
443
444 /**
445 * Print a single package which:
446 * (a) is the target of one or more relevant predependencies.
447 * (b) has itself no unsatisfied pre-dependencies.
448 *
449 * If such a package is present output is the Packages file entry,
450 * which can be massaged as appropriate.
451 *
452 * Exit status:
453 * 0 = a package printed, OK
454 * 1 = no suitable package available
455 * 2 = error
456 */
457 int
458 predeppackage(const char *const *argv)
459 {
460 static struct varbuf vb;
461
462 struct pkgiterator *iter;
463 struct pkginfo *pkg = NULL, *startpkg, *trypkg;
464 struct dependency *dep;
465 struct deppossi *possi, *provider;
466
467 if (*argv)
468 badusage(_("--%s takes no arguments"), cipaction->olong);
469
470 modstatdb_open(msdbrw_readonly | msdbrw_available_readonly);
471 /* We use clientdata->istobe to detect loops. */
472 clear_istobes();
473
474 dep = NULL;
475 iter = pkg_db_iter_new();
476 while (!dep && (pkg = pkg_db_iter_next_pkg(iter))) {
477 /* Ignore packages user doesn't want. */
478 if (pkg->want != PKG_WANT_INSTALL)
479 continue;
480 /* Ignore packages not available. */
481 if (!pkg->files)
482 continue;
483 pkg->clientdata->istobe = PKG_ISTOBE_PREINSTALL;
484 for (dep= pkg->available.depends; dep; dep= dep->next) {
485 if (dep->type != dep_predepends) continue;
486 if (depisok(dep, &vb, NULL, NULL, true))
487 continue;
488 /* This will leave dep non-NULL, and so exit the loop. */
489 break;
490 }
491 pkg->clientdata->istobe = PKG_ISTOBE_NORMAL;
492 /* If dep is NULL we go and get the next package. */
493 }
494 pkg_db_iter_free(iter);
495
496 if (!dep)
497 return 1; /* Not found. */
498 assert(pkg);
499 startpkg= pkg;
500 pkg->clientdata->istobe = PKG_ISTOBE_PREINSTALL;
501
502 /* OK, we have found an unsatisfied predependency.
503 * Now go and find the first thing we need to install, as a first step
504 * towards satisfying it. */
505 do {
506 /* We search for a package which would satisfy dep, and put it in pkg. */
507 for (possi = dep->list, pkg = NULL;
508 !pkg && possi;
509 possi=possi->next) {
510 struct deppossi_pkg_iterator *possi_iter;
511
512 possi_iter = deppossi_pkg_iter_new(possi, wpb_available);
513 while (!pkg && (trypkg = deppossi_pkg_iter_next(possi_iter))) {
514 if (trypkg->files &&
515 trypkg->clientdata->istobe == PKG_ISTOBE_NORMAL &&
516 versionsatisfied(&trypkg->available, possi)) {
517 pkg = trypkg;
518 break;
519 }
520 for (provider = possi->ed->depended.available;
521 !pkg && provider;
522 provider = provider->next) {
523 if (provider->up->type != dep_provides)
524 continue;
525 if (!pkg_virtual_deppossi_satisfied(possi, provider))
526 continue;
527 trypkg = provider->up->up;
528 if (!trypkg->files)
529 continue;
530 if (trypkg->clientdata->istobe == PKG_ISTOBE_NORMAL) {
531 pkg = trypkg;
532 break;
533 }
534 }
535 }
536 deppossi_pkg_iter_free(possi_iter);
537 }
538 if (!pkg) {
539 varbuf_reset(&vb);
540 describedepcon(&vb,dep);
541 varbuf_end_str(&vb);
542 notice(_("cannot see how to satisfy pre-dependency:\n %s"), vb.buf);
543 ohshit(_("cannot satisfy pre-dependencies for %.250s (wanted due to %.250s)"),
544 pkgbin_name(dep->up, &dep->up->available, pnaw_nonambig),
545 pkgbin_name(startpkg, &startpkg->available, pnaw_nonambig));
546 }
547 pkg->clientdata->istobe = PKG_ISTOBE_PREINSTALL;
548 for (dep= pkg->available.depends; dep; dep= dep->next) {
549 if (dep->type != dep_predepends) continue;
550 if (depisok(dep, &vb, NULL, NULL, true))
551 continue;
552 /* This will leave dep non-NULL, and so exit the loop. */
553 break;
554 }
555 } while (dep);
556
557 /* OK, we've found it - pkg has no unsatisfied pre-dependencies! */
558 writerecord(stdout, _("<standard output>"), pkg, &pkg->available);
559
560 m_output(stdout, _("<standard output>"));
561
562 return 0;
563 }
564
565 int
566 printarch(const char *const *argv)
567 {
568 if (*argv)
569 badusage(_("--%s takes no arguments"), cipaction->olong);
570
571 printf("%s\n", dpkg_arch_get(DPKG_ARCH_NATIVE)->name);
572
573 m_output(stdout, _("<standard output>"));
574
575 return 0;
576 }
577
578 int
579 print_foreign_arches(const char *const *argv)
580 {
581 struct dpkg_arch *arch;
582
583 if (*argv)
584 badusage(_("--%s takes no arguments"), cipaction->olong);
585
586 dpkg_arch_load_list();
587
588 for (arch = dpkg_arch_get_list(); arch; arch = arch->next) {
589 if (arch->type != DPKG_ARCH_FOREIGN)
590 continue;
591
592 printf("%s\n", arch->name);
593 }
594
595 m_output(stdout, _("<standard output>"));
596
597 return 0;
598 }
599
600 int
601 validate_pkgname(const char *const *argv)
602 {
603 const char *emsg;
604
605 if (!argv[0] || argv[1])
606 badusage(_("--%s takes one <pkgname> argument"), cipaction->olong);
607
608 emsg = pkg_name_is_illegal(argv[0]);
609 if (emsg)
610 ohshit(_("package name '%s' is invalid: %s"), argv[0], emsg);
611
612 return 0;
613 }
614
615 int
616 validate_trigname(const char *const *argv)
617 {
618 const char *emsg;
619
620 if (!argv[0] || argv[1])
621 badusage(_("--%s takes one <trigname> argument"), cipaction->olong);
622
623 emsg = trig_name_is_illegal(argv[0]);
624 if (emsg)
625 ohshit(_("trigger name '%s' is invalid: %s"), argv[0], emsg);
626
627 return 0;
628 }
629
630 int
631 validate_archname(const char *const *argv)
632 {
633 const char *emsg;
634
635 if (!argv[0] || argv[1])
636 badusage(_("--%s takes one <archname> argument"), cipaction->olong);
637
638 emsg = dpkg_arch_name_is_illegal(argv[0]);
639 if (emsg)
640 ohshit(_("architecture name '%s' is invalid: %s"), argv[0], emsg);
641
642 return 0;
643 }
644
645 int
646 validate_version(const char *const *argv)
647 {
648 struct dpkg_version version;
649 struct dpkg_error err;
650
651 if (!argv[0] || argv[1])
652 badusage(_("--%s takes one <version> argument"), cipaction->olong);
653
654 if (parseversion(&version, argv[0], &err) < 0) {
655 dpkg_error_print(&err, _("version '%s' has bad syntax"), argv[0]);
656 dpkg_error_destroy(&err);
657
658 return 1;
659 }
660
661 return 0;
662 }
663
664 int
665 cmpversions(const char *const *argv)
666 {
667 struct relationinfo {
668 const char *string;
669 /* These values are exit status codes, so 0 = true, 1 = false. */
670 int if_lesser, if_equal, if_greater;
671 int if_none_a, if_none_both, if_none_b;
672 bool obsolete;
673 };
674
675 static const struct relationinfo relationinfos[]= {
676 /* < = > !a!2!b */
677 { "le", 0,0,1, 0,0,1 },
678 { "lt", 0,1,1, 0,1,1 },
679 { "eq", 1,0,1, 1,0,1 },
680 { "ne", 0,1,0, 0,1,0 },
681 { "ge", 1,0,0, 1,0,0 },
682 { "gt", 1,1,0, 1,1,0 },
683
684 /* These treat an empty version as later than any version. */
685 { "le-nl", 0,0,1, 1,0,0 },
686 { "lt-nl", 0,1,1, 1,1,0 },
687 { "ge-nl", 1,0,0, 0,0,1 },
688 { "gt-nl", 1,1,0, 0,1,1 },
689
690 /* For compatibility with dpkg control file syntax. */
691 { "<", 0,0,1, 0,0,1, .obsolete = true },
692 { "<=", 0,0,1, 0,0,1 },
693 { "<<", 0,1,1, 0,1,1 },
694 { "=", 1,0,1, 1,0,1 },
695 { ">", 1,0,0, 1,0,0, .obsolete = true },
696 { ">=", 1,0,0, 1,0,0 },
697 { ">>", 1,1,0, 1,1,0 },
698 { NULL }
699 };
700
701 const struct relationinfo *rip;
702 struct dpkg_version a, b;
703 struct dpkg_error err;
704 int rc;
705
706 if (!argv[0] || !argv[1] || !argv[2] || argv[3])
707 badusage(_("--compare-versions takes three arguments:"
708 " <version> <relation> <version>"));
709
710 for (rip=relationinfos; rip->string && strcmp(rip->string,argv[1]); rip++);
711
712 if (!rip->string) badusage(_("--compare-versions bad relation"));
713
714 if (rip->obsolete)
715 warning(_("--%s used with obsolete relation operator '%s'"),
716 cipaction->olong, rip->string);
717
718 if (*argv[0] && strcmp(argv[0],"<unknown>")) {
719 if (parseversion(&a, argv[0], &err) < 0) {
720 dpkg_error_print(&err, _("version '%s' has bad syntax"), argv[0]);
721 dpkg_error_destroy(&err);
722 }
723 } else {
724 dpkg_version_blank(&a);
725 }
726 if (*argv[2] && strcmp(argv[2],"<unknown>")) {
727 if (parseversion(&b, argv[2], &err) < 0) {
728 dpkg_error_print(&err, _("version '%s' has bad syntax"), argv[2]);
729 dpkg_error_destroy(&err);
730 }
731 } else {
732 dpkg_version_blank(&b);
733 }
734 if (!dpkg_version_is_informative(&a)) {
735 if (dpkg_version_is_informative(&b))
736 return rip->if_none_a;
737 else
738 return rip->if_none_both;
739 } else if (!dpkg_version_is_informative(&b)) {
740 return rip->if_none_b;
741 }
742 rc = dpkg_version_compare(&a, &b);
743 debug(dbg_general, "cmpversions a='%s' b='%s' r=%d",
744 versiondescribe(&a,vdew_always),
745 versiondescribe(&b,vdew_always),
746 rc);
747 if (rc > 0)
748 return rip->if_greater;
749 else if (rc < 0)
750 return rip->if_lesser;
751 else
752 return rip->if_equal;
753 }