4 #include <sys/utsname.h>
9 #include <apt-pkg/pkgcache.h>
10 #include <apt-pkg/cachefile.h>
11 #include <apt-pkg/dpkgdb.h>
12 #include <apt-pkg/progress.h>
13 #include <apt-pkg/init.h>
14 #include <apt-pkg/error.h>
15 #include <apt-pkg/algorithms.h>
16 #include <apt-pkg/sptr.h>
17 #include <apt-pkg/acquire-item.h>
21 #include "contrib/acqprogress.h"
25 static struct option opts[] = {
26 { "help", 0, NULL, 'h' },
27 { "simulate", 0, NULL, 's' },
28 { "profile", 0, NULL, 'p' },
29 { "update", 0, NULL, 'l' },
30 { "upgrade", 0, NULL, 'u' },
31 { "check", 0, NULL, 'c' },
32 { "purge", 0, NULL, '!' },
33 { "clean", 0, NULL, 'e' },
34 { "option", 0, NULL, 'o' },
35 { NULL, 0, NULL, '\0' },
38 static bool run_install(pkgCacheFile &cache) {
39 if (_config->FindB("Inapt::Purge", false))
40 for (pkgCache::PkgIterator i = cache->PkgBegin(); !i.end(); i++)
41 if (!i.Purge() && cache[i].Mode == pkgDepCache::ModeDelete)
42 cache->MarkDelete(i, true);
44 if (cache->BrokenCount())
45 fatal("broken packages during install");
47 if (!cache->DelCount() && !cache->InstCount() && !cache->BadCount())
50 pkgRecords Recs (cache);
51 if (_error->PendingError())
55 Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
56 if (_error->PendingError())
57 return _error->Error("Unable to lock the download directory");
59 unsigned int width = 80;
60 AcqTextStatus status (width, 0);
61 pkgAcquire Fetcher (&status);
64 if (List.ReadMainList() == false)
65 return _error->Error("The list of sources could not be read");
67 SPtr<pkgPackageManager> PM = _system->CreatePM(cache);
68 if (PM->GetArchives(&Fetcher, &List, &Recs) == false ||
69 _error->PendingError())
72 if (Fetcher.Run() == pkgAcquire::Failed)
76 for (pkgAcquire::ItemIterator i = Fetcher.ItemsBegin(); i != Fetcher.ItemsEnd(); i++) {
77 if ((*i)->Status != pkgAcquire::Item::StatDone || (*i)->Complete != true)
82 return _error->Error("Unable to fetch some archives");
86 pkgPackageManager::OrderResult Res = PM->DoInstall(-1);
87 if (Res == pkgPackageManager::Completed)
93 static void run_autoremove(pkgCacheFile &cache) {
94 bool purge = _config->FindB("Inapt::Purge", false);
96 for (pkgCache::PkgIterator i = cache->PkgBegin(); !i.end(); i++) {
97 if (cache[i].Garbage) {
98 debug("autoremove: %s", i.Name());
99 cache->MarkDelete(i, purge);
103 if (cache->BrokenCount())
104 fatal("automatic removal broke packages");
107 static void usage() {
108 fprintf(stderr, "Usage: %s [options] [filename..]\n", prog);
112 static bool test_profile(const char *profile, std::set<std::string> *profiles) {
113 return (*profile != '!' && profiles->find(profile) != profiles->end())
114 || (*profile == '!' && profiles->find(profile + 1) == profiles->end());
117 static bool test_anyprofile(std::string &profile, std::set<std::string> *profiles) {
118 char *s = xstrdup(profile.c_str());
119 const char *c = strtok(s, "/");
121 if (test_profile(c, profiles)) {
126 while ((c = strtok(NULL, "/")) != NULL) {
127 if (test_profile(c, profiles)) {
137 static pkgCache::PkgIterator eval_pkg(inapt_package *package, pkgCacheFile &cache) {
138 pkgCache::PkgIterator pkg;
140 for (std::vector<std::string>::iterator i = package->alternates.begin(); i != package->alternates.end(); i++) {
141 pkgCache::PkgIterator tmp = cache->FindPkg(*i);
143 /* no such package */
148 if (cache[tmp].CandidateVer) {
153 /* virtual package */
154 if (tmp->ProvidesList) {
155 if (!tmp.ProvidesList()->NextProvides) {
156 pkgCache::PkgIterator provide = tmp.ProvidesList().OwnerPkg();
157 if (package->action == inapt_action::INSTALL) {
158 debug("selecting %s instead of %s", provide.Name(), tmp.Name());
162 debug("will not remove %s instead of virtual package %s", provide.Name(), tmp.Name());
165 debug("%s is a virtual package", tmp.Name());
168 debug("%s is a virtual packages with no provides", tmp.Name());
173 if (package->alternates.size() == 1) {
174 _error->Error("%s:%d: No such package: %s", package->filename, package->linenum, package->alternates[0].c_str());
176 std::vector<std::string>::iterator i = package->alternates.begin();
177 std::string message = *(i++);
178 while (i != package->alternates.end()) {
179 message.append(", ").append(*(i++));
181 _error->Error("%s:%d: No alternative available: %s", package->filename, package->linenum, message.c_str());
188 static bool test_profiles(vector<std::string> *test_profiles, std::set<std::string> *profiles) {
190 for (vector<std::string>::iterator j = test_profiles->begin(); j < test_profiles->end(); j++) {
191 if (!test_anyprofile(*j, profiles)) {
199 static void eval_action(inapt_action *action, std::set<std::string> *profiles, std::vector<inapt_package *> *final_actions) {
200 for (vector<inapt_package *>::iterator i = action->packages.begin(); i < action->packages.end(); i++) {
201 if (test_profiles(&(*i)->predicates, profiles))
202 final_actions->push_back(*i);
206 static void eval_block(inapt_block *block, std::set<std::string> *profiles, std::vector<inapt_package *> *final_actions) {
210 for (vector<inapt_action *>::iterator i = block->actions.begin(); i < block->actions.end(); i++)
211 if (test_profiles(&(*i)->predicates, profiles))
212 eval_action(*i, profiles, final_actions);
214 for (vector<inapt_conditional *>::iterator i = block->children.begin(); i < block->children.end(); i++) {
215 if (test_profiles(&(*i)->predicates, profiles))
216 eval_block((*i)->then_block, profiles, final_actions);
218 eval_block((*i)->else_block, profiles, final_actions);
222 static void eval_profiles(inapt_block *block, std::set<std::string> *profiles) {
226 for (vector<inapt_profiles *>::iterator i = block->profiles.begin(); i < block->profiles.end(); i++)
227 if (test_profiles(&(*i)->predicates, profiles))
228 for (vector<std::string>::iterator j = (*i)->profiles.begin(); j != (*i)->profiles.end(); j++)
229 profiles->insert(*j);
231 for (vector<inapt_conditional *>::iterator i = block->children.begin(); i < block->children.end(); i++) {
232 if (test_profiles(&(*i)->predicates, profiles))
233 eval_profiles((*i)->then_block, profiles);
235 eval_profiles((*i)->else_block, profiles);
239 static void dump_nondownloadable(pkgCacheFile &cache) {
240 for (pkgCache::PkgIterator i = cache->PkgBegin(); !i.end(); i++)
241 if (i.CurrentVer() && !i.CurrentVer().Downloadable())
242 debug("package %s version %s is not downloadable", i.Name(), i.CurrentVer().VerStr());
245 static void dump_actions(pkgCacheFile &cache) {
246 debug("inst %lu del %lu keep %lu broken %lu bad %lu",
247 cache->InstCount(), cache->DelCount(), cache->KeepCount(),
248 cache->BrokenCount(), cache->BadCount());
249 for (pkgCache::PkgIterator i = cache->PkgBegin(); !i.end(); i++) {
250 if (cache[i].Install())
251 debug("installing %s", i.Name());
252 if (cache[i].Delete())
253 debug("removing %s", i.Name());
254 if (cache[i].InstBroken())
255 debug("install broken %s", i.Name());
256 if (cache[i].NowBroken())
257 debug("now broken %s", i.Name());
261 static bool sanity_check(std::vector<inapt_package *> *final_actions, pkgCacheFile &cache) {
263 std::map<std::string, inapt_package *> packages;
265 for (vector<inapt_package *>::iterator i = final_actions->begin(); i != final_actions->end(); i++) {
266 if (packages.find((*i)->pkg.Name()) != packages.end()) {
267 inapt_package *first = packages[(*i)->pkg.Name()];
268 inapt_package *current = *i;
269 _error->Error("Multiple directives for package %s at %s:%d and %s:%d",
270 (*i)->pkg.Name(), first->filename, first->linenum, current->filename, current->linenum);
274 packages[(*i)->pkg.Name()] = *i;
277 for (pkgCache::PkgIterator i = cache->PkgBegin(); !i.end(); i++) {
278 if (cache[i].Delete() && (i->Flags & pkgCache::Flag::Essential || i->Flags & pkgCache::Flag::Important)) {
279 _error->Error("Removing essential package %s", i.Name());
287 static void show_breakage(pkgCacheFile &cache) {
289 for (pkgCache::PkgIterator i = cache->PkgBegin(); !i.end(); i++)
290 if (cache[i].NowBroken() || cache[i].InstBroken())
291 broken.append(" ").append(i.Name());
293 _error->Error("Broken packages:%s", broken.c_str());
296 static void exec_actions(std::vector<inapt_package *> *final_actions) {
298 bool purge = _config->FindB("Inapt::Purge", false);
300 pkgInitConfig(*_config);
301 pkgInitSystem(*_config, _system);
306 if (cache.Open(prog) == false)
309 pkgDepCache::ActionGroup group (cache);
311 for (vector<inapt_package *>::iterator i = final_actions->begin(); i != final_actions->end(); i++)
312 (*i)->pkg = eval_pkg(*i, cache);
314 if (_error->PendingError())
317 // preliminary loop (auto-installs, includes recommends - could do this manually)
318 for (vector<inapt_package *>::iterator i = final_actions->begin(); i < final_actions->end(); i++) {
319 pkgCache::PkgIterator k = (*i)->pkg;
320 switch ((*i)->action) {
321 case inapt_action::INSTALL:
322 if (!k.CurrentVer() || cache[k].Delete()) {
323 debug("install %s %s:%d", (*i)->pkg.Name(), (*i)->filename, (*i)->linenum);
324 cache->MarkInstall(k, true);
327 case inapt_action::REMOVE:
330 fatal("uninitialized action");
334 // secondary loop (removes package and reinstalls auto-removed packages)
335 for (vector<inapt_package *>::iterator i = final_actions->begin(); i < final_actions->end(); i++) {
336 pkgCache::PkgIterator k = (*i)->pkg;
337 switch ((*i)->action) {
338 case inapt_action::INSTALL:
339 if ((!k.CurrentVer() && !cache[k].Install()) || cache[k].Delete()) {
340 debug("force install %s %s:%d", (*i)->pkg.Name(), (*i)->filename, (*i)->linenum);
341 cache->MarkInstall(k, false);
343 if (cache[k].Flags & pkgCache::Flag::Auto) {
344 debug("marking %s as manually installed", (*i)->pkg.Name());
345 cache->MarkAuto(k, false);
349 case inapt_action::REMOVE:
350 if ((k.CurrentVer() && !cache[k].Delete()) || cache[k].Install())
351 debug("remove %s %s:%d", (*i)->pkg.Name(), (*i)->filename, (*i)->linenum);
353 /* always mark so purge works */
354 cache->MarkDelete(k, purge);
357 fatal("uninitialized action");
361 if (_error->PendingError())
364 dump_nondownloadable(cache);
367 if (cache->BrokenCount()) {
368 pkgProblemResolver fix (cache);
369 for (vector<inapt_package *>::iterator i = final_actions->begin(); i < final_actions->end(); i++)
370 fix.Protect((*i)->pkg);
373 if (cache->BrokenCount()) {
374 show_breakage(cache);
379 cache->MarkAndSweep();
380 run_autoremove(cache);
382 if (!sanity_check(final_actions, cache))
385 if (_config->FindB("Inapt::Simulate", false)) {
386 pkgSimulate PM (cache);
392 if (_error->PendingError())
396 if (_config->FindB("Inapt::Simulate", false)) {
397 debug("marked %d packages", marked);
399 debug("marked %d packages, writing state file", marked);
400 cache->writeStateFile(NULL);
405 static void debug_profiles(std::set<std::string> *profiles) {
406 std::string s = "profiles:";
408 for (std::set<std::string>::iterator i = profiles->begin(); i != profiles->end(); i++) {
413 debug("%s", s.c_str());
416 static void auto_profiles(std::set<std::string> *profiles) {
420 profiles->insert(uts.nodename);
423 static void set_option(char *opt) {
424 char *eq = strchr(opt, '=');
426 fatal("invalid syntax for '%s': must be <option>=<value>", opt);
428 std::string option (opt, eq - opt);
429 std::string value (eq + 1);
431 _config->Set(option, value);
434 int main(int argc, char *argv[]) {
437 std::set<std::string> profiles;
439 prog = xstrdup(basename(argv[0]));
440 while ((opt = getopt_long(argc, argv, "?hp:slucedo:", opts, NULL)) != -1) {
447 profiles.insert(optarg);
450 _config->Set("Inapt::Simulate", true);
453 _config->Set("Inapt::Purge", true);
456 _config->Set("Inapt::Update", true);
459 _config->Set("Inapt::Upgrade", true);
462 _config->Set("Inapt::Check", true);
465 _config->Set("Inapt::Clean", true);
474 fatal("error parsing arguments");
478 int num_files = argc - optind;
481 std::vector<inapt_package *> final_actions;
484 parser(NULL, &context);
487 parser(argv[optind++], &context);
489 auto_profiles(&profiles);
490 eval_profiles(&context, &profiles);
491 debug_profiles(&profiles);
492 eval_block(&context, &profiles, &final_actions);
493 exec_actions(&final_actions);
495 if (_error->PendingError()) {
496 _error->DumpErrors();