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