/** * Check if a pkg is informative. * * Used by dselect and dpkg query options as an aid to decide whether to * display things, and by dump to decide whether to write them out. */ bool pkg_is_informative(struct pkginfo *pkg, struct pkgbin *pkgbin) { /* We ignore Section and Priority, as these tend to hang around. */ if (pkgbin == &pkg->installed && (pkg->want != want_unknown || pkg->eflag != eflag_ok || pkg->status != stat_notinstalled || informativeversion(&pkg->configversion))) return true; if (pkgbin->depends || nes(pkgbin->description) || nes(pkgbin->maintainer) || nes(pkgbin->origin) || nes(pkgbin->bugs) || nes(pkgbin->installedsize) || nes(pkgbin->source) || informativeversion(&pkgbin->version) || pkgbin->conffiles || pkgbin->arbs) return true; return false; }
int informative(struct pkginfo *pkg, struct pkginfoperfile *info) { /* Used by dselect and dpkg query options as an aid to decide * whether to display things, and by dump to decide whether to write them * out. */ if (info == &pkg->installed && (pkg->want != want_unknown || pkg->eflag != eflagv_ok || pkg->status != stat_notinstalled || informativeversion(&pkg->configversion))) /* We ignore Section and Priority, as these tend to hang around. */ return 1; if (!info->valid) return 0; if (info->depends || nes(info->description) || nes(info->maintainer) || nes(info->origin) || nes(info->bugs) || nes(info->installedsize) || nes(info->source) || informativeversion(&info->version) || info->conffiles || info->arbs) return 1; return 0; }
const char *versiondescribe (const struct versionrevision *version, enum versiondisplayepochwhen vdew) { static struct varbuf bufs[10]; static int bufnum=0; struct varbuf *vb; if (!informativeversion(version)) return _("<none>"); vb= &bufs[bufnum]; bufnum++; if (bufnum == 10) bufnum= 0; varbufreset(vb); varbufversion(vb,version,vdew); varbufaddc(vb,0); return vb->buf; }
/* * *whynot must already have been initialized; it need not be * empty though - it will be reset before use. * * If depisok returns false for ‘not OK’ it will contain a description, * newline-terminated BUT NOT NUL-TERMINATED, of the reason. * * If depisok returns true it will contain garbage. * allowunconfigd should be non-zero during the ‘Pre-Depends’ checking * before a package is unpacked, when it is sufficient for the package * to be unpacked provided that both the unpacked and previously-configured * versions are acceptable. * * On false return (‘not OK’), *canfixbyremove refers to a package which * if removed (dep_conflicts) or deconfigured (dep_breaks) will fix * the problem. Caller may pass NULL for canfixbyremove and need not * initialize *canfixbyremove. */ bool depisok(struct dependency *dep, struct varbuf *whynot, struct pkginfo **canfixbyremove, bool allowunconfigd) { struct deppossi *possi; struct deppossi *provider; int nconflicts; /* Use this buffer so that when internationalisation comes along we * don't have to rewrite the code completely, only redo the sprintf strings * (assuming we have the fancy argument-number-specifiers). * Allow 250x3 for package names, versions, &c, + 250 for ourselves. */ char linebuf[1024]; assert(dep->type == dep_depends || dep->type == dep_predepends || dep->type == dep_breaks || dep->type == dep_conflicts || dep->type == dep_recommends || dep->type == dep_suggests || dep->type == dep_enhances); if (canfixbyremove) *canfixbyremove = NULL; /* The dependency is always OK if we're trying to remove the depend*ing* * package. */ switch (dep->up->clientdata->istobe) { case itb_remove: case itb_deconfigure: return true; case itb_normal: /* Only installed packages can be make dependency problems. */ switch (dep->up->status) { case stat_installed: case stat_triggerspending: case stat_triggersawaited: break; case stat_notinstalled: case stat_configfiles: case stat_halfinstalled: case stat_halfconfigured: case stat_unpacked: return true; default: internerr("unknown status depending '%d'", dep->up->status); } break; case itb_installnew: case itb_preinstall: break; default: internerr("unknown istobe depending '%d'", dep->up->clientdata->istobe); } /* Describe the dependency, in case we have to moan about it. */ varbufreset(whynot); varbufaddc(whynot, ' '); describedepcon(whynot, dep); varbufaddc(whynot,'\n'); /* TODO: Check dep_enhances as well. */ if (dep->type == dep_depends || dep->type == dep_predepends || dep->type == dep_recommends || dep->type == dep_suggests ) { /* Go through the alternatives. As soon as we find one that * we like, we return ‘true’ straight away. Otherwise, when we get to * the end we'll have accumulated all the reasons in whynot and * can return ‘false’. */ for (possi= dep->list; possi; possi= possi->next) { switch (possi->ed->clientdata->istobe) { case itb_remove: sprintf(linebuf,_(" %.250s is to be removed.\n"),possi->ed->name); break; case itb_deconfigure: sprintf(linebuf,_(" %.250s is to be deconfigured.\n"),possi->ed->name); break; case itb_installnew: if (versionsatisfied(&possi->ed->available, possi)) return true; sprintf(linebuf,_(" %.250s is to be installed, but is version %.250s.\n"), possi->ed->name, versiondescribe(&possi->ed->available.version,vdew_nonambig)); break; case itb_normal: case itb_preinstall: switch (possi->ed->status) { case stat_installed: case stat_triggerspending: if (versionsatisfied(&possi->ed->installed, possi)) return true; sprintf(linebuf,_(" %.250s is installed, but is version %.250s.\n"), possi->ed->name, versiondescribe(&possi->ed->installed.version,vdew_nonambig)); break; case stat_notinstalled: /* Don't say anything about this yet - it might be a virtual package. * Later on, if nothing has put anything in linebuf, we know that it * isn't and issue a diagnostic then. */ *linebuf = '\0'; break; case stat_unpacked: case stat_halfconfigured: case stat_triggersawaited: if (allowunconfigd) { if (!informativeversion(&possi->ed->configversion)) { sprintf(linebuf, _(" %.250s is unpacked, but has never been configured.\n"), possi->ed->name); break; } else if (!versionsatisfied(&possi->ed->installed, possi)) { sprintf(linebuf, _(" %.250s is unpacked, but is version %.250s.\n"), possi->ed->name, versiondescribe(&possi->ed->available.version,vdew_nonambig)); break; } else if (!versionsatisfied3(&possi->ed->configversion, &possi->version,possi->verrel)) { sprintf(linebuf, _(" %.250s latest configured version is %.250s.\n"), possi->ed->name, versiondescribe(&possi->ed->configversion,vdew_nonambig)); break; } else { return true; } } /* Fall through. */ default: sprintf(linebuf, _(" %.250s is %s.\n"), possi->ed->name, gettext(statusstrings[possi->ed->status])); break; } break; default: internerr("unknown istobe depended '%d'", possi->ed->clientdata->istobe); } varbufaddstr(whynot, linebuf); /* If there was no version specified we try looking for Providers. */ if (possi->verrel == dvr_none) { /* See if the package we're about to install Provides it. */ for (provider= possi->ed->available.depended; provider; provider = provider->rev_next) { if (provider->up->type != dep_provides) continue; if (provider->up->up->clientdata->istobe == itb_installnew) return true; } /* Now look at the packages already on the system. */ for (provider= possi->ed->installed.depended; provider; provider = provider->rev_next) { if (provider->up->type != dep_provides) continue; switch (provider->up->up->clientdata->istobe) { case itb_installnew: /* Don't pay any attention to the Provides field of the * currently-installed version of the package we're trying * to install. We dealt with that by using the available * information above. */ continue; case itb_remove: sprintf(linebuf, _(" %.250s provides %.250s but is to be removed.\n"), provider->up->up->name, possi->ed->name); break; case itb_deconfigure: sprintf(linebuf, _(" %.250s provides %.250s but is to be deconfigured.\n"), provider->up->up->name, possi->ed->name); break; case itb_normal: case itb_preinstall: if (provider->up->up->status == stat_installed) return true; sprintf(linebuf, _(" %.250s provides %.250s but is %s.\n"), provider->up->up->name, possi->ed->name, gettext(statusstrings[provider->up->up->status])); break; default: internerr("unknown istobe provider '%d'", provider->up->up->clientdata->istobe); } varbufaddstr(whynot, linebuf); } if (!*linebuf) { /* If the package wasn't installed at all, and we haven't said * yet why this isn't satisfied, we should say so now. */ sprintf(linebuf, _(" %.250s is not installed.\n"), possi->ed->name); varbufaddstr(whynot, linebuf); } } } return false; } else { /* It's conflicts or breaks. There's only one main alternative, * but we also have to consider Providers. We return ‘false’ as soon * as we find something that matches the conflict, and only describe * it then. If we get to the end without finding anything we return * ‘true’. */ possi= dep->list; nconflicts= 0; if (possi->ed != possi->up->up) { /* If the package conflicts with or breaks itself it must mean * other packages which provide the same virtual name. We * therefore don't look at the real package and go on to the * virtual ones. */ switch (possi->ed->clientdata->istobe) { case itb_remove: break; case itb_installnew: if (!versionsatisfied(&possi->ed->available, possi)) break; sprintf(linebuf, _(" %.250s (version %.250s) is to be installed.\n"), possi->ed->name, versiondescribe(&possi->ed->available.version,vdew_nonambig)); varbufaddstr(whynot, linebuf); if (!canfixbyremove) return false; nconflicts++; *canfixbyremove= possi->ed; break; case itb_deconfigure: if (dep->type == dep_breaks) break; /* Already deconfiguring this. */ /* Fall through. */ case itb_normal: case itb_preinstall: switch (possi->ed->status) { case stat_notinstalled: case stat_configfiles: break; case stat_halfinstalled: case stat_unpacked: case stat_halfconfigured: if (dep->type == dep_breaks) break; /* No problem. */ case stat_installed: case stat_triggerspending: case stat_triggersawaited: if (!versionsatisfied(&possi->ed->installed, possi)) break; sprintf(linebuf, _(" %.250s (version %.250s) is present and %s.\n"), possi->ed->name, versiondescribe(&possi->ed->installed.version,vdew_nonambig), gettext(statusstrings[possi->ed->status])); varbufaddstr(whynot, linebuf); if (!canfixbyremove) return false; nconflicts++; *canfixbyremove= possi->ed; } break; default: internerr("unknown istobe conflict '%d'", possi->ed->clientdata->istobe); } } /* If there was no version specified we try looking for Providers. */ if (possi->verrel == dvr_none) { /* See if the package we're about to install Provides it. */ for (provider= possi->ed->available.depended; provider; provider = provider->rev_next) { if (provider->up->type != dep_provides) continue; if (provider->up->up->clientdata->istobe != itb_installnew) continue; if (provider->up->up == dep->up) continue; /* Conflicts and provides the same. */ sprintf(linebuf, _(" %.250s provides %.250s and is to be installed.\n"), provider->up->up->name, possi->ed->name); varbufaddstr(whynot, linebuf); /* We can't remove the one we're about to install: */ if (canfixbyremove) *canfixbyremove = NULL; return false; } /* Now look at the packages already on the system. */ for (provider= possi->ed->installed.depended; provider; provider = provider->rev_next) { if (provider->up->type != dep_provides) continue; if (provider->up->up == dep->up) continue; /* Conflicts and provides the same. */ switch (provider->up->up->clientdata->istobe) { case itb_installnew: /* Don't pay any attention to the Provides field of the * currently-installed version of the package we're trying * to install. We dealt with that package by using the * available information above. */ continue; case itb_remove: continue; case itb_deconfigure: if (dep->type == dep_breaks) continue; /* Already deconfiguring. */ case itb_normal: case itb_preinstall: switch (provider->up->up->status) { case stat_notinstalled: case stat_configfiles: continue; case stat_halfinstalled: case stat_unpacked: case stat_halfconfigured: if (dep->type == dep_breaks) break; /* No problem. */ case stat_installed: case stat_triggerspending: case stat_triggersawaited: sprintf(linebuf, _(" %.250s provides %.250s and is present and %s.\n"), provider->up->up->name, possi->ed->name, gettext(statusstrings[provider->up->up->status])); varbufaddstr(whynot, linebuf); if (!canfixbyremove) return false; nconflicts++; *canfixbyremove= provider->up->up; break; } break; default: internerr("unknown istobe conflict provider '%d'", provider->up->up->clientdata->istobe); } } } if (!nconflicts) return true; if (nconflicts > 1) *canfixbyremove = NULL; return false; } /* if (dependency) {...} else {...} */ }
void cmpversions(const char *const *argv) { struct relationinfo { const char *string; /* These values are exit status codes, so 0 = true, 1 = false. */ int if_lesser, if_equal, if_greater; int if_none_a, if_none_both, if_none_b; }; static const struct relationinfo relationinfos[]= { /* < = > !a!2!b */ { "le", 0,0,1, 0,0,1 }, { "lt", 0,1,1, 0,1,1 }, { "eq", 1,0,1, 1,0,1 }, { "ne", 0,1,0, 0,1,0 }, { "ge", 1,0,0, 1,0,0 }, { "gt", 1,1,0, 1,1,0 }, /* These treat an empty version as later than any version. */ { "le-nl", 0,0,1, 1,0,0 }, { "lt-nl", 0,1,1, 1,1,0 }, { "ge-nl", 1,0,0, 0,0,1 }, { "gt-nl", 1,1,0, 0,1,1 }, /* For compatibility with dpkg control file syntax. */ { "<", 0,0,1, 0,0,1 }, { "<=", 0,0,1, 0,0,1 }, { "<<", 0,1,1, 0,1,1 }, { "=", 1,0,1, 1,0,1 }, { ">", 1,0,0, 1,0,0 }, { ">=", 1,0,0, 1,0,0 }, { ">>", 1,1,0, 1,1,0 }, { NULL } }; const struct relationinfo *rip; const char *emsg; struct versionrevision a, b; int r; if (!argv[0] || !argv[1] || !argv[2] || argv[3]) badusage(_("--compare-versions takes three arguments:" " <version> <relation> <version>")); for (rip=relationinfos; rip->string && strcmp(rip->string,argv[1]); rip++); if (!rip->string) badusage(_("--compare-versions bad relation")); if (*argv[0] && strcmp(argv[0],"<unknown>")) { emsg= parseversion(&a,argv[0]); if (emsg) ohshit(_("version '%s' has bad syntax: %s"), argv[0], emsg); } else { blankversion(&a); } if (*argv[2] && strcmp(argv[2],"<unknown>")) { emsg= parseversion(&b,argv[2]); if (emsg) ohshit(_("version '%s' has bad syntax: %s"), argv[2], emsg); } else { blankversion(&b); } if (!informativeversion(&a)) { exit(informativeversion(&b) ? rip->if_none_a : rip->if_none_both); } else if (!informativeversion(&b)) { exit(rip->if_none_b); } r= versioncompare(&a,&b); debug(dbg_general,"cmpversions a=`%s' b=`%s' r=%d", versiondescribe(&a,vdew_always), versiondescribe(&b,vdew_always), r); if (r>0) exit(rip->if_greater); else if (r<0) exit(rip->if_lesser); else exit(rip->if_equal); }