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