implement --exclude parameter
[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 #include "repo_susetags.h"
24 #include "repo_rpmmd.h"
25 #include "solver.h"
26
27 static ssize_t
28 cookie_gzread(void *cookie, char *buf, size_t nbytes)
29 {
30   return gzread((gzFile *)cookie, buf, nbytes);
31 }
32
33 static int
34 cookie_gzclose(void *cookie)
35 {
36   return gzclose((gzFile *)cookie);
37 }
38
39 FILE *
40 myfopen(const char *fn)
41 {
42   cookie_io_functions_t cio;
43   char *suf;
44   gzFile *gzf;
45
46   if (!fn)
47     return 0;
48   suf = strrchr(fn, '.');
49   if (!suf || strcmp(suf, ".gz") != 0)
50     return fopen(fn, "r");
51   gzf = gzopen(fn, "r");
52   if (!gzf)
53     return 0;
54   memset(&cio, 0, sizeof(cio));
55   cio.read = cookie_gzread;
56   cio.close = cookie_gzclose;
57   return  fopencookie(gzf, "r", cio);
58 }
59
60 void
61 usage(char** argv)
62 {
63     printf("Usage:\n%s: <arch> repo [--nocheck repo]...\n",
64         argv[0]);
65     exit(1);
66 }
67
68
69 int
70 main(int argc, char **argv)
71 {
72   Pool *pool;
73   Solver *solv;
74   Queue job;
75   Queue rids;
76   Queue cand;
77   Queue archlocks;
78   char *arch, *exclude_pat;
79   int i, j;
80   Id p;
81   Id rpmid, rpmarch, rpmrel, archlock;
82   int status = 0;
83   int nocheck = 0;
84
85   exclude_pat = 0;
86   archlock = 0;
87   if (argc < 3)
88     usage(argv);
89
90   arch = argv[1];
91   pool = pool_create();
92   pool_setarch(pool, arch);
93   for (i = 2; i < argc; i++)
94     {
95       FILE *fp;
96       int l;
97
98       if (!strcmp(argv[i], "--nocheck"))
99         {
100           if (!nocheck)
101             nocheck = pool->nsolvables;
102           continue;
103         }
104       if (!strcmp(argv[i], "--exclude"))
105         {
106           if (i + 1 >= argc)
107             {
108               printf("--exclude needs a whitespace separated list of substrings as parameter\n");
109               exit(1);
110             }
111           exclude_pat = argv[i + 1];
112           ++i;
113           continue;
114         }
115       l = strlen(argv[i]);
116       if (!strcmp(argv[i], "-"))
117         fp = stdin;
118       else if ((fp = myfopen(argv[i])) == 0)
119         {
120           perror(argv[i]);
121           exit(1);
122         }
123       Repo *repo = repo_create(pool, argv[i]);
124       if (l >= 8 && !strcmp(argv[i] + l - 8, "packages"))
125         {
126           repo_add_susetags(repo, fp, 0, 0, 0);
127         }
128       else if (l >= 11 && !strcmp(argv[i] + l - 11, "packages.gz"))
129         {
130           repo_add_susetags(repo, fp, 0, 0, 0);
131         }
132       else if (l >= 14 && !strcmp(argv[i] + l - 14, "primary.xml.gz"))
133         {
134           repo_add_rpmmd(repo, fp, 0, 0);
135         }
136       else if (repo_add_solv(repo, fp))
137         {
138           fprintf(stderr, "could not add repo %s\n", argv[i]);
139           exit(1);
140         }
141       if (fp != stdin)
142         fclose(fp);
143     }
144   pool_addfileprovides(pool);
145   pool_createwhatprovides(pool);
146   rpmid = str2id(pool, "rpm", 0);
147   rpmarch = str2id(pool, arch, 0);
148   rpmrel = 0;
149   if (rpmid && rpmarch)
150     {
151       for (p = 1; p < pool->nsolvables; p++)
152         {
153           Solvable *s = pool->solvables + p;
154           if (s->name == rpmid && s->arch == rpmarch)
155             break;
156         }
157       if (p < pool->nsolvables)
158         rpmrel = rel2id(pool, rpmid, rpmarch, REL_ARCH, 1);
159     }
160   
161   queue_init(&job);
162   queue_init(&rids);
163   queue_init(&cand);
164   queue_init(&archlocks);
165   for (p = 1; p < pool->nsolvables; p++)
166     {
167       Solvable *s = pool->solvables + p;
168       if (!s->repo)
169         continue;
170       if (!pool_installable(pool, s))
171         continue;
172       if (rpmrel && s->arch != rpmarch)
173         {
174           Id rp, rpp;
175           FOR_PROVIDES(rp, rpp, s->name)
176             {
177               if (pool->solvables[rp].name != s->name)
178                 continue;
179               if (pool->solvables[rp].arch == rpmarch)
180                 break;
181             }
182           if (rp)
183             {
184               queue_push(&archlocks, p);
185               continue;
186             }
187         }
188       queue_push(&cand, p);
189     }
190   
191   if (archlocks.count)
192     {
193       archlock = pool_queuetowhatprovides(pool, &archlocks);
194     }
195   /* prune cand by doing weak installs */
196   while (cand.count)
197     {
198       solv = solver_create(pool);
199       queue_empty(&job);
200       for (i = 0; i < cand.count; i++)
201         {
202           p = cand.elements[i];
203           queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
204           queue_push(&job, p);
205         }
206       if (rpmrel)
207         {
208           queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME);
209           queue_push(&job, rpmrel);
210         }
211       if (archlock)
212         {
213           queue_push(&job, SOLVER_LOCK|SOLVER_SOLVABLE_ONE_OF);
214           queue_push(&job, archlock);
215         }
216       solv->dontinstallrecommended = 1;
217       solver_solve(solv, &job);
218       /* prune... */
219       for (i = j = 0; i < cand.count; i++)
220         {
221           p = cand.elements[i];
222           if (solv->decisionmap[p] <= 0)
223             {
224               cand.elements[j++] = p;
225               continue;
226             }
227 #if 0
228           Solvable *s = pool->solvables + p;
229           if (!strcmp(id2str(pool, s->name), "libusb-compat-devel"))
230             {
231               cand.elements[j++] = p;
232               continue;
233             }
234 #endif
235         }
236       cand.count = j;
237       if (i == j)
238         break;
239     }
240
241   /* now check every candidate */
242   for (i = 0; i < cand.count; i++)
243     {
244       Solvable *s;
245
246       p = cand.elements[i];
247       if (nocheck && p >= nocheck)
248         continue;
249       if (exclude_pat)
250         {
251           char *ptr, *save = 0, *pattern;
252           int match = 0;
253           pattern = strdup(exclude_pat);
254
255           for (ptr = strtok_r(pattern, " ", &save);
256               ptr;
257               ptr = strtok_r(NULL, " ", &save))
258             {
259               if (*ptr && strstr(solvid2str(pool, p), ptr))
260                 {
261                   match = 1;
262                   break;
263                 }
264             }
265           free(pattern);
266           if (match)
267             continue;
268         }
269       s = pool->solvables + p;
270       solv = solver_create(pool);
271       queue_empty(&job);
272       queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE);
273       queue_push(&job, p);
274       if (rpmrel)
275         {
276           queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME);
277           queue_push(&job, rpmrel);
278         }
279       if (archlock)
280         {
281           queue_push(&job, SOLVER_LOCK|SOLVER_SOLVABLE_ONE_OF);
282           queue_push(&job, archlock);
283         }
284       solv->dontinstallrecommended = 1;
285       solver_solve(solv, &job);
286       if (solv->problems.count)
287         {
288           Id problem = 0;
289           Solvable *s2;
290
291           status = 1;
292           printf("can't install %s:\n", solvable2str(pool, s));
293           while ((problem = solver_next_problem(solv, problem)) != 0)
294             {
295               solver_findallproblemrules(solv, problem, &rids);
296               for (j = 0; j < rids.count; j++)
297                 {
298                   Id probr = rids.elements[j];
299                   int k;
300                   Queue rinfo;
301                   queue_init(&rinfo);
302
303                   solver_allruleinfos(solv, probr, &rinfo);
304                   for (k = 0; k < rinfo.count; k += 4)
305                     {
306                       Id dep, source, target;
307                       source = rinfo.elements[k + 1];
308                       target = rinfo.elements[k + 2];
309                       dep = rinfo.elements[k + 3];
310                       switch (rinfo.elements[k])
311                         {
312                         case SOLVER_PROBLEM_DISTUPGRADE_RULE:
313                           break;
314                         case SOLVER_PROBLEM_INFARCH_RULE:
315                           s = pool_id2solvable(pool, source);
316                           printf("  %s has inferior architecture\n", solvable2str(pool, s));
317                           break;
318                         case SOLVER_PROBLEM_UPDATE_RULE:
319                           break;
320                         case SOLVER_PROBLEM_JOB_RULE:
321                           break;
322                         case SOLVER_PROBLEM_RPM_RULE:
323                           printf("  some dependency problem\n");
324                           break;
325                         case SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP:
326                           printf("  nothing provides requested %s\n", dep2str(pool, dep));
327                           break;
328                         case SOLVER_PROBLEM_NOT_INSTALLABLE:
329                           s = pool_id2solvable(pool, source);
330                           printf("  package %s is not installable\n", solvable2str(pool, s));
331                           break;
332                         case SOLVER_PROBLEM_NOTHING_PROVIDES_DEP:
333                           s = pool_id2solvable(pool, source);
334                           printf("  nothing provides %s needed by %s\n", dep2str(pool, dep), solvable2str(pool, s));
335                           if (ISRELDEP(dep))
336                             {
337                               Reldep *rd = GETRELDEP(pool, dep);
338                               if (!ISRELDEP(rd->name))
339                                 {
340                                   Id rp, rpp;
341                                   FOR_PROVIDES(rp, rpp, rd->name)
342                                     printf("    (we have %s)\n", solvable2str(pool, pool->solvables + rp));
343                                 }
344                             }
345                           break;
346                         case SOLVER_PROBLEM_SAME_NAME:
347                           s = pool_id2solvable(pool, source);
348                           s2 = pool_id2solvable(pool, target);
349                           printf("  cannot install both %s and %s\n", solvable2str(pool, s), solvable2str(pool, s2));
350                           break;
351                         case SOLVER_PROBLEM_PACKAGE_CONFLICT:
352                           s = pool_id2solvable(pool, source);
353                           s2 = pool_id2solvable(pool, target);
354                           printf("  package %s conflicts with %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
355                           break;
356                         case SOLVER_PROBLEM_PACKAGE_OBSOLETES:
357                           s = pool_id2solvable(pool, source);
358                           s2 = pool_id2solvable(pool, target);
359                           printf("  package %s obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
360                           break;
361                         case SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE:
362                           s = pool_id2solvable(pool, source);
363                           printf("  package %s requires %s, but none of the providers can be installed\n", solvable2str(pool, s), dep2str(pool, dep));
364                           break;
365                         case SOLVER_PROBLEM_SELF_CONFLICT:
366                           s = pool_id2solvable(pool, source);
367                           printf("  package %s conflicts with %s provided by itself\n", solvable2str(pool, s), dep2str(pool, dep));
368                           break;
369                         }
370                     }
371                 }
372             }
373         }
374 #if 0
375       else
376         {
377           if (!strcmp(id2str(pool, s->name), "libusb-compat-devel"))
378             {
379               solver_printdecisions(solv);
380             }
381         }
382 #endif
383       solver_free(solv);
384     }
385   exit(status);
386 }