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