Imported Upstream version 0.7.27
[platform/upstream/libsolv.git] / tools / installcheck.c
1 /*
2  * Copyright (c) 2009-2015, SUSE LLC
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8
9 #define _GNU_SOURCE
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <string.h>
15
16 #include "pool.h"
17 #include "poolarch.h"
18 #include "repo_solv.h"
19 #ifdef ENABLE_SUSEREPO
20 #include "repo_susetags.h"
21 #endif
22 #ifdef ENABLE_RPMMD
23 #include "repo_rpmmd.h"
24 #endif
25 #ifdef ENABLE_DEBIAN
26 #include "repo_deb.h"
27 #endif
28 #ifdef ENABLE_ARCHREPO
29 #include "repo_arch.h"
30 #endif
31 #include "solver.h"
32 #include "solv_xfopen.h"
33
34 #ifdef _WIN32
35 #include "strfncs.h"
36 #endif
37
38 void
39 usage(char** argv)
40 {
41   printf("Usage:\n%s: <arch> [options..] repo [--nocheck repo]...\n"
42          "\t--exclude <pattern>\twhitespace-separated list of (sub-)"
43          "packagenames to ignore\n"
44          "\t--withobsoletes\t\tCheck for obsoletes on packages contained in repos\n"
45          "\t--nocheck\t\tDo not warn about all following repos (only use them to fulfill dependencies)\n"
46          "\t--withsrc\t\tAlso check dependencies of src.rpm\n\n"
47          , argv[0]);
48   exit(1);
49 }
50
51 #if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_DEBIAN) || defined(ENABLE_ARCHREPO)
52 static size_t
53 strlen_comp(const char *str)
54 {
55   const char *suf = strrchr(str, '.');
56   return strlen(str) - (suf && solv_xfopen_iscompressed(suf) ? strlen(suf) : 0);
57 }
58 #endif
59
60 int
61 main(int argc, char **argv)
62 {
63   Pool *pool;
64   Solver *solv;
65   Repo *repo;
66   Queue job;
67   Queue rids;
68   Queue cand;
69   char *arch, *exclude_pat;
70   int i, j;
71   Id p;
72   Id archid, noarchid;
73   Id rpmrel;
74 #ifndef DEBIAN
75   Id rpmid;
76 #endif
77   int status = 0;
78   int nocheck = 0;
79   int withsrc = 0;
80   int obsoletepkgcheck = 0;
81
82   exclude_pat = 0;
83   if (argc < 3)
84     usage(argv);
85
86   arch = argv[1];
87   pool = pool_create();
88   pool_setarch(pool, arch);
89   noarchid = pool->solvables[SYSTEMSOLVABLE].arch;
90   for (i = 2; i < argc; i++)
91     {
92       FILE *fp;
93       int r;
94 #if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_DEBIAN) || defined(ENABLE_ARCHREPO)
95       size_t l;
96 #endif
97
98       if (!strcmp(argv[i], "--withsrc"))
99         {
100           withsrc++;
101           continue;
102         }
103       if (!strcmp(argv[i], "--withobsoletes"))
104         {
105           obsoletepkgcheck++;
106           continue;
107         }
108       if (!strcmp(argv[i], "--nocheck"))
109         {
110           if (!nocheck)
111             nocheck = pool->nsolvables;
112           continue;
113         }
114       if (!strcmp(argv[i], "--exclude"))
115         {
116           if (i + 1 >= argc)
117             {
118               printf("--exclude needs a whitespace separated list of substrings as parameter\n");
119               exit(1);
120             }
121           exclude_pat = argv[i + 1];
122           ++i;
123           continue;
124         }
125 #if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_DEBIAN) || defined(ENABLE_ARCHREPO)
126       l = strlen_comp(argv[i]);
127 #endif
128       if (!strcmp(argv[i], "-"))
129         fp = stdin;
130       else if ((fp = solv_xfopen(argv[i], 0)) == 0)
131         {
132           perror(argv[i]);
133           exit(1);
134         }
135       repo = repo_create(pool, argv[i]);
136       r = 0;
137       if (0)
138         {
139         }
140 #ifdef ENABLE_SUSEREPO
141       else if (l >= 8 && !strncmp(argv[i] + l - 8, "packages", 8))
142         {
143           r = repo_add_susetags(repo, fp, 0, 0, 0);
144         }
145 #endif
146 #ifdef ENABLE_RPMMD
147       else if (l >= 11 && !strncmp(argv[i] + l - 11, "primary.xml", 11))
148         {
149           r = repo_add_rpmmd(repo, fp, 0, 0);
150           if (!r && i + 1 < argc)
151             {
152               l = strlen_comp(argv[i + 1]);
153               if (l >= 13 && !strncmp(argv[i + 1] + l - 13, "filelists.xml", 13))
154                 {
155                   i++;
156                   fclose(fp);
157                   if ((fp = solv_xfopen(argv[i], 0)) == 0)
158                     {
159                       perror(argv[i]);
160                       exit(1);
161                     }
162                   r = repo_add_rpmmd(repo, fp, 0, REPO_EXTEND_SOLVABLES|REPO_LOCALPOOL);
163                 }
164             }
165         }
166 #endif
167 #ifdef ENABLE_DEBIAN
168       else if (l >= 8 && !strncmp(argv[i] + l - 8, "Packages", 8))
169         {
170           r = repo_add_debpackages(repo, fp, 0);
171         }
172 #endif
173 #ifdef ENABLE_ARCHREPO
174       else if (l >= 7 && (!strncmp(argv[i] + l - 7, ".db.tar", 7)))
175         {
176           r = repo_add_arch_repo(repo, fp, 0);
177         }
178 #endif
179       else
180         r = repo_add_solv(repo, fp, 0);
181       if (r)
182         {
183           fprintf(stderr, "could not add repo %s: %s\n", argv[i], pool_errstr(pool));
184           exit(1);
185         }
186       if (fp != stdin)
187         fclose(fp);
188     }
189   pool_addfileprovides(pool);
190   pool_createwhatprovides(pool);
191   archid = pool_str2id(pool, arch, 0);
192 #ifndef DEBIAN
193   rpmid = pool_str2id(pool, "rpm", 0);
194   rpmrel = 0;
195   if (rpmid && archid)
196     {
197       for (p = 1; p < pool->nsolvables; p++)
198         {
199           Solvable *s = pool->solvables + p;
200           if (s->name == rpmid && s->arch == archid && pool_installable(pool, s))
201             break;
202         }
203       if (p < pool->nsolvables)
204         rpmrel = pool_rel2id(pool, rpmid, archid, REL_ARCH, 1);
205     }
206 #else
207   rpmrel = 0;
208 #endif
209   
210   queue_init(&job);
211   queue_init(&rids);
212   queue_init(&cand);
213   for (p = 1; p < (nocheck ? nocheck : pool->nsolvables); p++)
214     {
215       Solvable *s = pool->solvables + p;
216       if (!s->repo)
217         continue;
218       if (withsrc && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC))
219         {
220           queue_push(&cand, p);
221           continue;
222         }
223       if (!pool_installable(pool, s))
224         continue;
225       if (archid && s->arch != archid && s->arch != noarchid)
226         {
227           /* check if we will conflict with a infarch rule, if yes,
228            * don't bother checking the package */
229           Id rp, rpp;
230           FOR_PROVIDES(rp, rpp, s->name)
231             {
232               if (pool->solvables[rp].name != s->name)
233                 continue;
234               if (pool->solvables[rp].arch == archid)
235                 break;
236             }
237           if (rp)
238             continue;
239         }
240       queue_push(&cand, p);
241     }
242   if (obsoletepkgcheck)
243     {
244       int obsoleteusesprovides = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESPROVIDES);
245       int obsoleteusescolors = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESCOLORS);
246
247       for (i = 0; i < cand.count; i++)
248         {
249           Solvable *s;
250           s = pool->solvables + cand.elements[i];
251
252           if (s->obsoletes)
253             {
254               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
255
256               while ((obs = *obsp++) != 0)
257                 {
258                   Id op, opp;
259                   FOR_PROVIDES(op, opp, obs)
260                     {
261                       Solvable *os = pool->solvables + op;
262                       if (nocheck && op >= nocheck)
263                         continue;
264                       if (solvable_identical(s, os))
265                         continue;
266                       if (!obsoleteusesprovides && !pool_match_nevr(pool, os, obs))
267                         continue;
268                       if (obsoleteusescolors && !pool_colormatch(pool, s, os))
269                         continue;
270                       status = 2;
271                       printf("can't install %s:\n", pool_solvid2str(pool, op));
272                       printf("  package is obsoleted by %s\n", pool_solvable2str(pool, s));
273                     }
274                 }
275             }
276         }
277     }
278
279   solv = solver_create(pool);
280
281   /* prune cand by doing weak installs */
282   while (cand.count)
283     {
284       queue_empty(&job);
285       for (i = 0; i < cand.count; i++)
286         {
287           p = cand.elements[i];
288           queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK, p);
289         }
290       if (rpmrel)
291         queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, rpmrel);
292       solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1);
293       solver_solve(solv, &job);
294       /* prune... */
295       for (i = j = 0; i < cand.count; i++)
296         {
297           p = cand.elements[i];
298           if (solver_get_decisionlevel(solv, p) <= 0)
299             {
300               cand.elements[j++] = p;
301               continue;
302             }
303         }
304       cand.count = j;
305       if (i == j)
306         break;
307     }
308
309   /* now check every candidate */
310   for (i = 0; i < cand.count; i++)
311     {
312       Solvable *s;
313       int problemcount;
314
315       p = cand.elements[i];
316       if (exclude_pat)
317         {
318           char *ptr, *save = 0, *pattern;
319           int match = 0;
320           pattern = solv_strdup(exclude_pat);
321
322           for (ptr = strtok_r(pattern, " ", &save);
323               ptr;
324               ptr = strtok_r(NULL, " ", &save))
325             {
326               if (*ptr && strstr(pool_solvid2str(pool, p), ptr))
327                 {
328                   match = 1;
329                   break;
330                 }
331             }
332           solv_free(pattern);
333           if (match)
334             continue;
335         }
336       s = pool->solvables + p;
337       queue_empty(&job);
338       queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE, p);
339       if (rpmrel)
340         queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, rpmrel);
341       solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1);
342       problemcount = solver_solve(solv, &job);
343       if (problemcount)
344         {
345           Id problem = 0;
346
347           status = 1;
348           printf("can't install %s:\n", pool_solvable2str(pool, s));
349           while ((problem = solver_next_problem(solv, problem)) != 0)
350             {
351               solver_findallproblemrules(solv, problem, &rids);
352               for (j = 0; j < rids.count; j++)
353                 {
354                   Id probr = rids.elements[j];
355                   int k;
356                   Queue rinfo;
357                   queue_init(&rinfo);
358
359                   solver_allruleinfos(solv, probr, &rinfo);
360                   for (k = 0; k < rinfo.count; k += 4)
361                     {
362                       Id type, dep, source, target;
363                       type = rinfo.elements[k];
364                       source = rinfo.elements[k + 1];
365                       target = rinfo.elements[k + 2];
366                       dep = rinfo.elements[k + 3];
367
368                       /* special casing */
369                       switch (type)
370                         {
371                         case SOLVER_RULE_DISTUPGRADE:
372                         case SOLVER_RULE_JOB:
373                         case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM:
374                         case SOLVER_RULE_JOB_UNKNOWN_PACKAGE:
375                         case SOLVER_RULE_JOB_UNSUPPORTED:
376                           break;
377                         case SOLVER_RULE_UPDATE:
378                           printf("  %s can not be updated\n", pool_solvid2str(pool, source));
379                           break;
380                         case SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP:
381                           printf("  %s\n", solver_problemruleinfo2str(solv, type, source, target, dep));
382                           if (ISRELDEP(dep))
383                             {
384                               Reldep *rd = GETRELDEP(pool, dep);
385                               if (!ISRELDEP(rd->name))
386                                 {
387                                   Id rp, rpp;
388                                   FOR_PROVIDES(rp, rpp, rd->name)
389                                     printf("    (we have %s)\n", pool_solvable2str(pool, pool->solvables + rp));
390                                 }
391                             }
392                           break;
393                         default:
394                           printf("  %s\n", solver_problemruleinfo2str(solv, type, source, target, dep));
395                           break;
396                         }
397                     }
398                 }
399             }
400         }
401     }
402   solver_free(solv);
403   exit(status);
404 }