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