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