- add pool_freetmpspace, pool_tmpappend, pool_bin2hex, sat_dupappend, sat_hex2bin...
[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 #include "chksum.h"
24
25 const char *
26 solvable2str(Pool *pool, Solvable *s)
27 {
28   const char *n, *e, *a;
29   char *p;
30   n = id2str(pool, s->name);
31   e = id2str(pool, s->evr);
32   a = id2str(pool, s->arch);
33   p = pool_alloctmpspace(pool, strlen(n) + strlen(e) + strlen(a) + 3);
34   sprintf(p, "%s-%s.%s", n, e, a);
35   return p;
36 }
37
38 Id
39 solvable_lookup_id(Solvable *s, Id keyname)
40 {
41   if (!s->repo)
42     return 0;
43   return repo_lookup_id(s->repo, s - s->repo->pool->solvables, keyname);
44 }
45
46 int
47 solvable_lookup_idarray(Solvable *s, Id keyname, Queue *q)
48 {
49   Dataiterator di;
50   int found = 0;
51
52   queue_empty(q);
53   if (!s->repo)
54     return 0;
55   dataiterator_init(&di, s->repo->pool, s->repo, s - s->repo->pool->solvables, keyname, 0, SEARCH_ARRAYSENTINEL);
56   while (dataiterator_step(&di))
57     {
58       if (di.key->type != REPOKEY_TYPE_IDARRAY && di.key->type != REPOKEY_TYPE_REL_IDARRAY)
59         continue;
60       found = 1;
61       if (di.kv.eof)
62         break;
63       queue_push(q, di.kv.id);
64     }
65   dataiterator_free(&di);
66   return found;
67 }
68
69 const char *
70 solvable_lookup_str(Solvable *s, Id keyname)
71 {
72   if (!s->repo)
73     return 0;
74   return repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname);
75 }
76
77 static const char *
78 solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname, int usebase)
79 {
80   Pool *pool;
81   const char *str, *basestr;
82   Id p, pp;
83   Solvable *s2;
84   int pass;
85
86   if (!s->repo)
87     return 0;
88   pool = s->repo->pool;
89   str = solvable_lookup_str(s, keyname);
90   if (str || keyname == basekeyname)
91     return str;
92   basestr = solvable_lookup_str(s, basekeyname);
93   if (!basestr)
94     return 0;
95   /* search for a solvable with same name and same base that has the
96    * translation */
97   if (!pool->whatprovides)
98     return usebase ? basestr : 0;
99   /* we do this in two passes, first same vendor, then all other vendors */
100   for (pass = 0; pass < 2; pass++)
101     {
102       FOR_PROVIDES(p, pp, s->name)
103         {
104           s2 = pool->solvables + p;
105           if (s2->name != s->name)
106             continue;
107           if ((s->vendor == s2->vendor) != (pass == 0))
108             continue;
109           str = solvable_lookup_str(s2, basekeyname);
110           if (!str || strcmp(str, basestr))
111             continue;
112           str = solvable_lookup_str(s2, keyname);
113           if (str)
114             return str;
115         }
116     }
117   return usebase ? basestr : 0;
118 }
119
120 const char *
121 solvable_lookup_str_poollang(Solvable *s, Id keyname)
122 {
123   Pool *pool;
124   int i, cols;
125   const char *str;
126   Id *row;
127
128   if (!s->repo)
129     return 0;
130   pool = s->repo->pool;
131   if (!pool->nlanguages)
132     return solvable_lookup_str(s, keyname);
133   cols = pool->nlanguages + 1;
134   if (!pool->languagecache)
135     {
136       pool->languagecache = sat_calloc(cols * ID_NUM_INTERNAL, sizeof(Id));
137       pool->languagecacheother = 0;
138     }
139   if (keyname >= ID_NUM_INTERNAL)
140     {
141       row = pool->languagecache + ID_NUM_INTERNAL * cols;
142       for (i = 0; i < pool->languagecacheother; i++, row += cols)
143         if (*row == keyname)
144           break;
145       if (i >= pool->languagecacheother)
146         {
147           pool->languagecache = sat_realloc2(pool->languagecache, pool->languagecacheother + 1, cols * sizeof(Id));
148           row = pool->languagecache + cols * (ID_NUM_INTERNAL + pool->languagecacheother++);
149           *row = keyname;
150         }
151     }
152   else
153     row = pool->languagecache + keyname * cols;
154   row++;        /* skip keyname */
155   for (i = 0; i < pool->nlanguages; i++, row++)
156     {
157       if (!*row)
158         *row = pool_id2langid(pool, keyname, pool->languages[i], 1);
159       str = solvable_lookup_str_base(s, *row, keyname, 0);
160       if (str)
161         return str;
162     }
163   return solvable_lookup_str(s, keyname);
164 }
165
166 const char *
167 solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase)
168 {
169   if (s->repo)
170     {
171       Id id = pool_id2langid(s->repo->pool, keyname, lang, 0);
172       if (id)
173         return solvable_lookup_str_base(s, id, keyname, usebase);
174       if (!usebase)
175         return 0;
176     }
177   return solvable_lookup_str(s, keyname);
178 }
179
180 unsigned int
181 solvable_lookup_num(Solvable *s, Id keyname, unsigned int notfound)
182 {
183   if (!s->repo)
184     return notfound;
185   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound);
186 }
187
188 int
189 solvable_lookup_void(Solvable *s, Id keyname)
190 {
191   if (!s->repo)
192     return 0;
193   return repo_lookup_void(s->repo, s - s->repo->pool->solvables, keyname);
194 }
195
196 int
197 solvable_lookup_bool(Solvable *s, Id keyname)
198 {
199   if (!s->repo)
200     return 0;
201   /* historic nonsense: there are two ways of storing a bool, as num == 1 or void. test both. */
202   if (repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname) == REPOKEY_TYPE_VOID)
203     return 1;
204   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, 0) == 1;
205 }
206
207 const unsigned char *
208 solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep)
209 {
210   Repo *repo = s->repo;
211
212   if (!repo)
213     {
214       *typep = 0;
215       return 0;
216     }
217   return repo_lookup_bin_checksum(repo, s - repo->pool->solvables, keyname, typep);
218 }
219
220 const char *
221 solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep)
222 {
223   const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep);
224   return chk ? pool_bin2hex(s->repo->pool, chk, sat_chksum_len(*typep)) : 0;
225 }
226
227 static inline const char *
228 evrid2vrstr(Pool *pool, Id evrid)
229 {
230   const char *p, *evr = id2str(pool, evrid);
231   if (!evr)
232     return evr;
233   for (p = evr; *p >= '0' && *p <= '9'; p++)
234     ;
235   return p != evr && *p == ':' ? p + 1 : evr;
236 }
237
238 char *
239 solvable_get_location(Solvable *s, unsigned int *medianrp)
240 {
241   Pool *pool;
242   int l = 0;
243   char *loc;
244   const char *mediadir, *mediafile;
245
246   *medianrp = 0;
247   if (!s->repo)
248     return 0;
249   pool = s->repo->pool;
250   *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 1);
251   if (solvable_lookup_void(s, SOLVABLE_MEDIADIR))
252     mediadir = id2str(pool, s->arch);
253   else
254     mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR);
255   if (mediadir)
256     l = strlen(mediadir) + 1;
257   if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE))
258     {
259       const char *name, *evr, *arch;
260       name = id2str(pool, s->name);
261       evr = evrid2vrstr(pool, s->evr);
262       arch = id2str(pool, s->arch);
263       /* name-vr.arch.rpm */
264       loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7);
265       if (mediadir)
266         sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch);
267       else
268         sprintf(loc, "%s-%s.%s.rpm", name, evr, arch);
269     }
270   else
271     {
272       mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
273       if (!mediafile)
274         return 0;
275       loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1);
276       if (mediadir)
277         sprintf(loc, "%s/%s", mediadir, mediafile);
278       else
279         strcpy(loc, mediafile);
280     }
281   return loc;
282 }
283
284 /*****************************************************************************/
285
286 static inline Id dep2name(Pool *pool, Id dep)
287 {
288   while (ISRELDEP(dep))
289     {
290       Reldep *rd = rd = GETRELDEP(pool, dep);
291       dep = rd->name;
292     }
293   return dep;
294 }
295
296 static inline int providedbyinstalled(Pool *pool, Map *installed, Id dep)
297 {
298   Id p, pp;
299   FOR_PROVIDES(p, pp, dep)
300     {
301       if (p == SYSTEMSOLVABLE)
302         return -1;
303       if (MAPTST(installed, p))
304         return 1;
305     }
306   return 0;
307 }
308
309 /*
310  * solvable_trivial_installable_map - anwers is a solvable is installable
311  * without any other installs/deinstalls.
312  * The packages considered to be installed are provided via the
313  * installedmap bitmap. A additional "conflictsmap" bitmap providing
314  * information about the conflicts of the installed packages can be
315  * used for extra speed up. Provide a NULL pointer if you do not
316  * have this information.
317  * Both maps can be created with pool_create_state_maps() or
318  * solver_create_state_maps().
319  *
320  * returns:
321  * 1:  solvable is installable without any other package changes
322  * 0:  solvable is not installable
323  * -1: solvable is installable, but doesn't constrain any installed packages
324  */
325 int
326 solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap)
327 {
328   Pool *pool = s->repo->pool;
329   Solvable *s2;
330   Id p, pp, *dp;
331   Id *reqp, req;
332   Id *conp, con;
333   Id *obsp, obs;
334   int r, interesting = 0;
335
336   if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables))
337     return 0;
338   if (s->requires)
339     {
340       reqp = s->repo->idarraydata + s->requires;
341       while ((req = *reqp++) != 0)
342         {
343           if (req == SOLVABLE_PREREQMARKER)
344             continue;
345           r = providedbyinstalled(pool, installedmap, req);
346           if (!r)
347             return 0;
348           if (r > 0)
349             interesting = 1;
350         }
351     }
352   if (s->conflicts)
353     {
354       conp = s->repo->idarraydata + s->conflicts;
355       while ((con = *conp++) != 0)
356         {
357           if (providedbyinstalled(pool, installedmap, con))
358             return 0;
359           if (!interesting && ISRELDEP(con))
360             {
361               con = dep2name(pool, con);
362               if (providedbyinstalled(pool, installedmap, con))
363                 interesting = 1;
364             }
365         }
366     }
367   if (s->repo)
368     {
369       Repo *installed = 0;
370       if (s->obsoletes && s->repo != installed)
371         {
372           obsp = s->repo->idarraydata + s->obsoletes;
373           while ((obs = *obsp++) != 0)
374             {
375               if (providedbyinstalled(pool, installedmap, obs))
376                 return 0;
377             }
378         }
379       if (s->repo != installed)
380         {
381           FOR_PROVIDES(p, pp, s->name)
382             {
383               s2 = pool->solvables + p;
384               if (s2->repo == installed && s2->name == s->name)
385                 return 0;
386             }
387         }
388     }
389   if (!conflictsmap)
390     {
391       int i;
392
393       p = s - pool->solvables;
394       for (i = 1; i < pool->nsolvables; i++)
395         {
396           if (!MAPTST(installedmap, i))
397             continue;
398           s2 = pool->solvables + i;
399           if (!s2->conflicts)
400             continue;
401           conp = s2->repo->idarraydata + s2->conflicts;
402           while ((con = *conp++) != 0)
403             {
404               dp = pool_whatprovides_ptr(pool, con);
405               for (; *dp; dp++)
406                 if (*dp == p)
407                   return 0;
408             }
409         }
410      }
411   return interesting ? 1 : -1;
412 }
413
414 /*
415  * different interface for solvable_trivial_installable_map, where
416  * the information about the installed packages is provided
417  * by a queue.
418  */
419 int
420 solvable_trivial_installable_queue(Solvable *s, Queue *installed)
421 {
422   Pool *pool = s->repo->pool;
423   int i;
424   Id p;
425   Map installedmap;
426   int r;
427
428   map_init(&installedmap, pool->nsolvables);
429   for (i = 0; i < installed->count; i++)
430     {
431       p = installed->elements[i];
432       if (p > 0)                /* makes it work with decisionq */
433         MAPSET(&installedmap, p);
434     }
435   r = solvable_trivial_installable_map(s, &installedmap, 0);
436   map_free(&installedmap);
437   return r;
438 }
439
440 /*
441  * different interface for solvable_trivial_installable_map, where
442  * the information about the installed packages is provided
443  * by a repo containing the installed solvables.
444  */
445 int
446 solvable_trivial_installable_repo(Solvable *s, Repo *installed)
447 {
448   Pool *pool = s->repo->pool;
449   Id p;
450   Solvable *s2;
451   Map installedmap;
452   int r;
453
454   map_init(&installedmap, pool->nsolvables);
455   FOR_REPO_SOLVABLES(installed, p, s2)
456     MAPSET(&installedmap, p);
457   r = solvable_trivial_installable_map(s, &installedmap, 0);
458   map_free(&installedmap);
459   return r;
460 }
461
462
463 /*****************************************************************************/
464
465 /*
466  * Create maps containing the state of each solvable. Input is a "installed" queue,
467  * it contains all solvable ids that are considered to be installed.
468  * 
469  * The created maps can be used for solvable_trivial_installable_map(),
470  * pool_calc_duchanges(), pool_calc_installsizechange().
471  *
472  */
473 void
474 pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap)
475 {
476   int i;
477   Solvable *s;
478   Id p, *dp;
479   Id *conp, con;
480
481   map_init(installedmap, pool->nsolvables);
482   if (conflictsmap)
483     map_init(conflictsmap, pool->nsolvables);
484   for (i = 0; i < installed->count; i++)
485     {
486       p = installed->elements[i];
487       if (p <= 0)       /* makes it work with decisionq */
488         continue;
489       MAPSET(installedmap, p);
490       if (!conflictsmap)
491         continue;
492       s = pool->solvables + p;
493       if (!s->conflicts)
494         continue;
495       conp = s->repo->idarraydata + s->conflicts;
496       while ((con = *conp++) != 0)
497         {
498           dp = pool_whatprovides_ptr(pool, con);
499           for (; *dp; dp++)
500             MAPSET(conflictsmap, *dp);
501         }
502     }
503 }
504
505 /* Tests if two solvables have identical content. Currently
506  * both solvables need to come from the same pool */
507
508 int
509 solvable_identical(Solvable *s1, Solvable *s2)
510 {
511   unsigned int bt1, bt2;
512   Id rq1, rq2;
513   Id *reqp;
514
515   if (s1->name != s2->name)
516     return 0;
517   if (s1->arch != s2->arch)
518     return 0;
519   if (s1->evr != s2->evr)
520     return 0;
521   /* map missing vendor to empty string */
522   if ((s1->vendor ? s1->vendor : 1) != (s2->vendor ? s2->vendor : 1))
523     return 0;
524
525   /* looking good, try some fancier stuff */
526   /* might also look up the package checksum here */
527   bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0);
528   bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0);
529   if (bt1 && bt2)
530     {
531       if (bt1 != bt2)
532         return 0;
533     }
534   else
535     {
536       /* look at requires in a last attempt to find recompiled packages */
537       rq1 = rq2 = 0;
538       if (s1->requires)
539         for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
540           rq1 ^= *reqp;
541       if (s2->requires)
542         for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
543           rq2 ^= *reqp;
544       if (rq1 != rq2)
545          return 0;
546     }
547   return 1;
548 }
549
550 /* return the self provide dependency of a solvable */
551 Id
552 solvable_selfprovidedep(Solvable *s)
553 {
554   Pool *pool;
555   Reldep *rd;
556   Id prov, *provp;
557
558   if (!s->repo)
559     return s->name;
560   pool = s->repo->pool;
561   if (s->provides)
562     {
563       provp = s->repo->idarraydata + s->provides;
564       while ((prov = *provp++) != 0)
565         {
566           if (!ISRELDEP(prov))
567             continue;
568           rd = GETRELDEP(pool, prov);
569           if (rd->name == s->name && rd->evr == s->evr && rd->flags == REL_EQ)
570             return prov;
571         }
572     }
573   return rel2id(pool, s->name, s->evr, REL_EQ, 1);
574 }