- Change provide iterator from ID pointer to ID. Before, iterating
[platform/upstream/libsolv.git] / src / solvable.c
1 /*
2  * Copyright (c) 2008, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * solvable.c
10  *
11  * set/retrieve data from solvables
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <unistd.h>
18 #include <string.h>
19
20 #include "pool.h"
21 #include "repo.h"
22 #include "util.h"
23
24 const char *
25 solvable2str(Pool *pool, Solvable *s)
26 {
27   const char *n, *e, *a;
28   char *p;
29   n = id2str(pool, s->name);
30   e = id2str(pool, s->evr);
31   a = id2str(pool, s->arch);
32   p = pool_alloctmpspace(pool, strlen(n) + strlen(e) + strlen(a) + 3);
33   sprintf(p, "%s-%s.%s", n, e, a);
34   return p;
35 }
36
37 Id
38 solvable_lookup_id(Solvable *s, Id keyname)
39 {
40   Repo *repo = s->repo;
41   Pool *pool;
42   Repodata *data;
43   int i, j, n;
44
45   if (!repo)
46     return 0;
47   pool = repo->pool;
48   switch(keyname)
49     {
50     case SOLVABLE_NAME:
51       return s->name;
52     case SOLVABLE_ARCH:
53       return s->arch;
54     case SOLVABLE_EVR:
55       return s->evr;
56     case SOLVABLE_VENDOR:
57       return s->vendor;
58     }
59   n = s - pool->solvables;
60   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
61     {
62       if (n < data->start || n >= data->end)
63         continue;
64       for (j = 1; j < data->nkeys; j++)
65         {
66           if (data->keys[j].name == keyname && (data->keys[j].type == REPOKEY_TYPE_ID || data->keys[j].type == REPOKEY_TYPE_CONSTANTID))
67             {
68               Id id = repodata_lookup_id(data, n - data->start, j);
69               if (id)
70                 {
71                   if (data->localpool)
72                     id = repodata_globalize_id(data, id);
73                   return id;
74                 }
75             }
76         }
77     }
78   return 0;
79 }
80
81 const char *
82 solvable_lookup_str(Solvable *s, Id keyname)
83 {
84   Repo *repo = s->repo;
85   Pool *pool;
86   Repodata *data;
87   int i, j, n;
88   const char *str;
89
90   if (!repo)
91     return 0;
92   pool = repo->pool;
93   switch(keyname)
94     {
95     case SOLVABLE_NAME:
96       return id2str(pool, s->name);
97     case SOLVABLE_ARCH:
98       return id2str(pool, s->arch);
99     case SOLVABLE_EVR:
100       return id2str(pool, s->evr);
101     case SOLVABLE_VENDOR:
102       return id2str(pool, s->vendor);
103     }
104   n = s - pool->solvables;
105   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
106     {
107       if (n < data->start || n >= data->end)
108         continue;
109       for (j = 1; j < data->nkeys; j++)
110         {
111           if (data->keys[j].name == keyname && (data->keys[j].type == REPOKEY_TYPE_ID || data->keys[j].type == REPOKEY_TYPE_CONSTANTID || data->keys[j].type == REPOKEY_TYPE_STR))
112             {
113               str = repodata_lookup_str(data, n - data->start, j);
114               if (str)
115                 return str;
116             }
117         }
118     }
119   return 0;
120 }
121
122 const char *
123 solvable_lookup_str_poollang(Solvable *s, Id keyname)
124 {
125   Pool *pool;
126   int i, cols;
127   const char *str;
128   Id *row;
129
130   if (!s->repo)
131     return repo_lookup_str(s, keyname);
132   pool = s->repo->pool;
133   if (!pool->nlanguages)
134     return repo_lookup_str(s, keyname);
135   cols = pool->nlanguages + 1;
136   if (!pool->languagecache)
137     {
138       pool->languagecache = sat_calloc(cols * ID_NUM_INTERNAL, sizeof(Id));
139       pool->languagecacheother = 0;
140     }
141   if (keyname >= ID_NUM_INTERNAL)
142     {
143       row = pool->languagecache + ID_NUM_INTERNAL * cols;
144       for (i = 0; i < pool->languagecacheother; i++, row += cols)
145         if (*row == keyname)
146           break;
147       if (i >= pool->languagecacheother)
148         {
149           pool->languagecache = sat_realloc2(pool->languagecache, pool->languagecacheother + 1, cols * sizeof(Id));
150           pool->languagecacheother++;
151           row = pool->languagecache + cols * (ID_NUM_INTERNAL + pool->languagecacheother++);
152         }
153     }
154   else
155     row = pool->languagecache + keyname * cols;
156   row++;        /* skip keyname */
157   for (i = 0; i < pool->nlanguages; i++, row++)
158     {
159       if (!*row)
160         {
161           char *p;
162           const char *kn;
163
164           kn = id2str(pool, keyname);
165           p = sat_malloc(strlen(kn) + strlen(pool->languages[i]) + 2);
166           sprintf(p, "%s:%s", kn, pool->languages[i]);
167           *row = str2id(pool, p, 1);
168           sat_free(p);
169         }
170       str = repo_lookup_str(s, *row);
171       if (str)
172         return str;
173     }
174   return repo_lookup_str(s, keyname);
175 }
176
177 const char *
178 solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang)
179 {
180   if (s->repo)
181     {
182       const char *str;
183       Id id = pool_id2langid(s->repo->pool, keyname, lang, 0);
184       if (id && (str = repo_lookup_str(s, id)) != 0)
185         return str;
186     }
187   return repo_lookup_str(s, keyname);
188 }
189
190 unsigned int
191 solvable_lookup_num(Solvable *s, Id keyname, unsigned int notfound)
192 {
193   Repo *repo = s->repo;
194   Pool *pool;
195   Repodata *data;
196   int i, j, n;
197
198   if (!repo)
199     return 0;
200   pool = repo->pool;
201   if (keyname == RPM_RPMDBID)
202     {
203       if (repo->rpmdbid)
204         return repo->rpmdbid[(s - pool->solvables) - repo->start];
205       return notfound;
206     }
207   n = s - pool->solvables;
208   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
209     {
210       if (n < data->start || n >= data->end)
211         continue;
212       for (j = 1; j < data->nkeys; j++)
213         {
214           if (data->keys[j].name == keyname
215               && (data->keys[j].type == REPOKEY_TYPE_U32
216                   || data->keys[j].type == REPOKEY_TYPE_NUM
217                   || data->keys[j].type == REPOKEY_TYPE_CONSTANT))
218             {
219               unsigned int value;
220               if (repodata_lookup_num(data, n - data->start, j, &value))
221                 return value;
222             }
223         }
224     }
225   return notfound;
226 }
227
228 int
229 solvable_lookup_void(Solvable *s, Id keyname)
230 {
231   Repo *repo = s->repo;
232   Pool *pool;
233   Repodata *data;
234   int i, j, n;
235
236   if (!repo)
237     return 0;
238   pool = repo->pool;
239   n = s - pool->solvables;
240   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
241     {
242       if (n < data->start || n >= data->end)
243         continue;
244       for (j = 1; j < data->nkeys; j++)
245         {
246           if (data->keys[j].name == keyname
247               && (data->keys[j].type == REPOKEY_TYPE_VOID))
248             {
249               if (repodata_lookup_void(data, n - data->start, j))
250                 return 1;
251             }
252         }
253     }
254   return 0;
255 }
256
257 int
258 solvable_lookup_bool(Solvable *s, Id keyname)
259 {
260   Repo *repo = s->repo;
261   Pool *pool;
262   Repodata *data;
263   int i, j, n;
264
265   if (!repo)
266     return 0;
267   pool = repo->pool;
268   n = s - pool->solvables;
269   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
270     {
271       if (n < data->start || n >= data->end)
272         continue;
273       /* there are two ways of storing a bool */
274       for (j = 1; j < data->nkeys; j++)
275         {
276           /* as a num == 1 */
277           if (data->keys[j].name == keyname
278               && (data->keys[j].type == REPOKEY_TYPE_U32
279                   || data->keys[j].type == REPOKEY_TYPE_NUM
280                   || data->keys[j].type == REPOKEY_TYPE_CONSTANT))
281             {
282               unsigned int value;
283               if (repodata_lookup_num(data, n - data->start, j, &value))
284                 return value == 1;
285             }
286
287           /* as a void attribute, if it is there, then true */
288           if (data->keys[j].name == keyname
289               && (data->keys[j].type == REPOKEY_TYPE_VOID))
290             {
291               if (repodata_lookup_void(data, n - data->start, j))
292                 return 1;
293             }
294         }
295     }
296   return 0;
297 }
298
299 const unsigned char *
300 solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep)
301 {
302   Repo *repo = s->repo;
303   Pool *pool;
304   Repodata *data;
305   int i, j, n;
306
307   *typep = 0;
308   if (!repo)
309     return 0;
310   pool = repo->pool;
311   n = s - pool->solvables;
312   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
313     {
314       if (n < data->start || n >= data->end)
315         continue;
316       for (j = 1; j < data->nkeys; j++)
317         {
318           if (data->keys[j].name == keyname
319               && (data->keys[j].type == REPOKEY_TYPE_MD5
320                   || data->keys[j].type == REPOKEY_TYPE_SHA1
321                   || data->keys[j].type == REPOKEY_TYPE_SHA256))
322             {
323               const unsigned char *chk = repodata_lookup_bin_checksum(data, n - data->start, j, typep);
324               if (chk)
325                 return chk;
326             }
327         }
328     }
329   return 0;
330 }
331
332 const char *
333 solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep)
334 {
335   const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep);
336   /* we need the repodata just as a reference for a pool */
337   return chk ? repodata_chk2str(s->repo->repodata, *typep, chk) : 0;
338 }
339
340 char *
341 solvable_get_location(Solvable *s, unsigned int *medianrp)
342 {
343   Pool *pool;
344   int l = 0;
345   char *loc;
346   const char *mediadir, *mediafile;
347
348   *medianrp = 0;
349   if (!s->repo)
350     return 0;
351   pool = s->repo->pool;
352   *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 1);
353   if (solvable_lookup_void(s, SOLVABLE_MEDIADIR))
354     mediadir = id2str(pool, s->arch);
355   else
356     mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR);
357   if (mediadir)
358     l = strlen(mediadir) + 1;
359   if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE))
360     {
361       const char *name, *evr, *arch;
362       name = id2str(pool, s->name);
363       evr = id2str(pool, s->evr);
364       arch = id2str(pool, s->arch);
365       /* name-evr.arch.rpm */
366       loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7);
367       if (mediadir)
368         sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch);
369       else
370         sprintf(loc, "%s-%s.%s.rpm", name, evr, arch);
371     }
372   else
373     {
374       mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
375       if (!mediafile)
376         return 0;
377       loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1);
378       if (mediadir)
379         sprintf(loc, "%s/%s", mediadir, mediafile);
380       else
381         strcpy(loc, mediafile);
382     }
383   return loc;
384 }
385
386 /*****************************************************************************/
387
388 static inline Id dep2name(Pool *pool, Id dep)
389 {
390   while (ISRELDEP(dep))
391     {
392       Reldep *rd = rd = GETRELDEP(pool, dep);
393       dep = rd->name;
394     }
395   return dep;
396 }
397
398 static inline int providedbyinstalled(Pool *pool, Map *installed, Id dep)
399 {
400   Id p, pp;
401   FOR_PROVIDES(p, pp, dep)
402     {
403       if (p == SYSTEMSOLVABLE)
404         return -1;
405       if (MAPTST(installed, p))
406         return 1;
407     }
408   return 0;
409 }
410
411 /*
412  * solvable_trivial_installable_map - anwers is a solvable is installable
413  * without any other installs/deinstalls.
414  * The packages considered to be installed are provided via the
415  * installedmap bitmap. A additional "conflictsmap" bitmap providing
416  * information about the conflicts of the installed packages can be
417  * used for extra speed up. Provide a NULL pointer if you do not
418  * have this information.
419  * Both maps can be created with pool_create_state_maps() or
420  * solver_create_state_maps().
421  *
422  * returns:
423  * 1:  solvable is installable without any other package changes
424  * 0:  solvable is not installable
425  * -1: solvable is installable, but doesn't constrain any installed packages
426  */
427 int
428 solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap)
429 {
430   Pool *pool = s->repo->pool;
431   Solvable *s2;
432   Id p, pp, *dp;
433   Id *reqp, req;
434   Id *conp, con;
435   Id *obsp, obs;
436   int r, interesting = 0;
437
438   if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables))
439     return 0;
440   if (s->requires)
441     {
442       reqp = s->repo->idarraydata + s->requires;
443       while ((req = *reqp++) != 0)
444         {
445           if (req == SOLVABLE_PREREQMARKER)
446             continue;
447           r = providedbyinstalled(pool, installedmap, req);
448           if (!r)
449             return 0;
450           if (r > 0)
451             interesting = 1;
452         }
453     }
454   if (s->conflicts)
455     {
456       conp = s->repo->idarraydata + s->conflicts;
457       while ((con = *conp++) != 0)
458         {
459           if (providedbyinstalled(pool, installedmap, con))
460             return 0;
461           if (!interesting && ISRELDEP(con))
462             {
463               con = dep2name(pool, con);
464               if (providedbyinstalled(pool, installedmap, con))
465                 interesting = 1;
466             }
467         }
468     }
469   if (s->repo)
470     {
471       Repo *installed = 0;
472       if (s->obsoletes && s->repo != installed)
473         {
474           obsp = s->repo->idarraydata + s->obsoletes;
475           while ((obs = *obsp++) != 0)
476             {
477               if (providedbyinstalled(pool, installedmap, obs))
478                 return 0;
479             }
480         }
481       if (s->repo != installed)
482         {
483           FOR_PROVIDES(p, pp, s->name)
484             {
485               s2 = pool->solvables + p;
486               if (s2->repo == installed && s2->name == s->name)
487                 return 0;
488             }
489         }
490     }
491   if (!conflictsmap)
492     {
493       int i;
494
495       p = s - pool->solvables;
496       for (i = 1; i < pool->nsolvables; i++)
497         {
498           if (!MAPTST(installedmap, i))
499             continue;
500           s2 = pool->solvables + i;
501           if (!s2->conflicts)
502             continue;
503           conp = s2->repo->idarraydata + s2->conflicts;
504           while ((con = *conp++) != 0)
505             {
506               dp = pool->whatprovidesdata + pool_whatprovides(pool, con);
507               for (; *dp; dp++)
508                 if (*dp == p)
509                   return 0;
510             }
511         }
512      }
513   return interesting ? 1 : -1;
514 }
515
516 /*
517  * different interface for solvable_trivial_installable_map, where
518  * the information about the installed packages is provided
519  * by a queue.
520  */
521 int
522 solvable_trivial_installable_queue(Solvable *s, Queue *installed)
523 {
524   Pool *pool = s->repo->pool;
525   int i;
526   Id p;
527   Map installedmap;
528   int r;
529
530   map_init(&installedmap, pool->nsolvables);
531   for (i = 0; i < installed->count; i++)
532     {
533       p = installed->elements[i];
534       if (p > 0)                /* makes it work with decisionq */
535         MAPSET(&installedmap, p);
536     }
537   r = solvable_trivial_installable_map(s, &installedmap, 0);
538   map_free(&installedmap);
539   return r;
540 }
541
542 /*
543  * different interface for solvable_trivial_installable_map, where
544  * the information about the installed packages is provided
545  * by a repo containing the installed solvables.
546  */
547 int
548 solvable_trivial_installable_repo(Solvable *s, Repo *installed)
549 {
550   Pool *pool = s->repo->pool;
551   Id p;
552   Solvable *s2;
553   Map installedmap;
554   int r;
555
556   map_init(&installedmap, pool->nsolvables);
557   FOR_REPO_SOLVABLES(installed, p, s2)
558     MAPSET(&installedmap, p);
559   r = solvable_trivial_installable_map(s, &installedmap, 0);
560   map_free(&installedmap);
561   return r;
562 }
563
564
565 /*****************************************************************************/
566
567 /*
568  * Create maps containing the state of each solvable. Input is a "installed" queue,
569  * it contains all solvable ids that are considered to be installed.
570  * 
571  * The created maps can be used for solvable_trivial_installable_map(),
572  * pool_calc_duchanges(), pool_calc_installsizechange().
573  *
574  */
575 void
576 pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap)
577 {
578   int i;
579   Solvable *s;
580   Id p, *dp;
581   Id *conp, con;
582
583   map_init(installedmap, pool->nsolvables);
584   if (conflictsmap)
585     map_init(conflictsmap, pool->nsolvables);
586   for (i = 0; i < installed->count; i++)
587     {
588       p = installed->elements[i];
589       if (p <= 0)       /* makes it work with decisionq */
590         continue;
591       MAPSET(installedmap, p);
592       if (!conflictsmap)
593         continue;
594       s = pool->solvables + p;
595       if (!s->conflicts)
596         continue;
597       conp = s->repo->idarraydata + s->conflicts;
598       while ((con = *conp++) != 0)
599         {
600           dp = pool->whatprovidesdata + pool_whatprovides(pool, con);
601           for (; *dp; dp++)
602             MAPSET(conflictsmap, *dp);
603         }
604     }
605 }
606
607 int
608 solvable_identical(Pool *pool, Solvable *s1, Solvable *s2)
609 {
610   unsigned int bt1, bt2;
611   Id rq1, rq2;
612   Id *reqp;
613
614   if (s1->name != s2->name)
615     return 0;
616   if (s1->arch != s2->arch)
617     return 0;
618   if (s1->evr != s2->evr)
619     return 0;
620   if (s1->vendor != s2->vendor)
621     return 0;
622
623   /* looking good, try some fancier stuff */
624   /* might also look up the package checksum here */
625   bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0);
626   bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0);
627   if (bt1 && bt2)
628     {
629       if (bt1 != bt2)
630         return 0;
631     }
632   else
633     {
634       /* look at requires in a last attempt to find recompiled packages */
635       rq1 = rq2 = 0;
636       if (s1->requires)
637         for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
638           rq1 ^= *reqp++;
639       if (s2->requires)
640         for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
641           rq2 ^= *reqp++;
642       if (rq1 != rq2)
643          return 0;
644     }
645   return 1;
646 }