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