6f6ba1de2d0bda0ae3e0ca7834b96d954ae89ff8
[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 "policy.h"
24 #include "poolvendor.h"
25 #include "chksum.h"
26 #include "linkedpkg.h"
27
28 const char *
29 pool_solvable2str(Pool *pool, Solvable *s)
30 {
31   const char *n, *e, *a;
32   int nl, el, al;
33   char *p;
34   n = pool_id2str(pool, s->name);
35   e = pool_id2str(pool, s->evr);
36   /* XXX: may want to skip the epoch here */
37   a = pool_id2str(pool, s->arch);
38   nl = strlen(n);
39   el = strlen(e);
40   al = strlen(a);
41   if (pool->havedistepoch)
42     {
43       /* strip the distepoch from the evr */
44       const char *de = strrchr(e, '-');
45       if (de && (de = strchr(de, ':')) != 0)
46         el = de - e;
47     }
48   p = pool_alloctmpspace(pool, nl + el + al + 3);
49   strcpy(p, n);
50   if (el)
51     {
52       p[nl++] = '-';
53       strncpy(p + nl, e, el);
54       p[nl + el] = 0;
55     }
56   if (al)
57     {
58       p[nl + el] = pool->disttype == DISTTYPE_HAIKU ? '-' : '.';
59       strcpy(p + nl + el + 1, a);
60     }
61   return p;
62 }
63
64 Id
65 solvable_lookup_type(Solvable *s, Id keyname)
66 {
67   if (!s->repo)
68     return 0;
69   return repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname);
70 }
71
72 Id
73 solvable_lookup_id(Solvable *s, Id keyname)
74 {
75   if (!s->repo)
76     return 0;
77   return repo_lookup_id(s->repo, s - s->repo->pool->solvables, keyname);
78 }
79
80 int
81 solvable_lookup_idarray(Solvable *s, Id keyname, Queue *q)
82 {
83   if (!s->repo)
84     {
85       queue_empty(q);
86       return 0;
87     }
88   return repo_lookup_idarray(s->repo, s - s->repo->pool->solvables, keyname, q);
89 }
90
91 int
92 solvable_lookup_deparray(Solvable *s, Id keyname, Queue *q, Id marker)
93 {
94   if (!s->repo)
95     {
96       queue_empty(q);
97       return 0;
98     }
99   return repo_lookup_deparray(s->repo, s - s->repo->pool->solvables, keyname, q, marker);
100 }
101
102 static const char *
103 solvable_lookup_str_joinarray(Solvable *s, Id keyname, const char *joinstr)
104 {
105   Queue q;
106   Id qbuf[10];
107   char *str = 0;
108
109   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
110   if (solvable_lookup_idarray(s, keyname, &q) && q.count)
111     {
112       Pool *pool = s->repo->pool;
113       int i;
114       str = pool_tmpjoin(pool, pool_id2str(pool, q.elements[0]), 0, 0);
115       for (i = 1; i < q.count; i++)
116         str = pool_tmpappend(pool, str, joinstr, pool_id2str(pool, q.elements[i]));
117     }
118   queue_free(&q);
119   return str;
120 }
121
122 const char *
123 solvable_lookup_str(Solvable *s, Id keyname)
124 {
125   const char *str;
126   if (!s->repo)
127     return 0;
128   str = repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname);
129   if (!str && (keyname == SOLVABLE_LICENSE || keyname == SOLVABLE_GROUP))
130     str = solvable_lookup_str_joinarray(s, keyname, ", ");
131   return str;
132 }
133
134 static const char *
135 solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname, int usebase)
136 {
137   Pool *pool;
138   const char *str, *basestr;
139   Id p, pp, name;
140   Solvable *s2;
141   int pass;
142
143   if (!s->repo)
144     return 0;
145   pool = s->repo->pool;
146   str = solvable_lookup_str(s, keyname);
147   if (str || keyname == basekeyname)
148     return str;
149   basestr = solvable_lookup_str(s, basekeyname);
150   if (!basestr)
151     return 0;
152   /* search for a solvable with same name and same base that has the
153    * translation */
154   if (!pool->whatprovides)
155     return usebase ? basestr : 0;
156   name = s->name;
157   /* we do this in two passes, first same vendor, then all other vendors */
158   for (pass = 0; pass < 2; pass++)
159     {
160       FOR_PROVIDES(p, pp, name)
161         {
162           s2 = pool->solvables + p;
163           if (s2->name != name)
164             continue;
165           if ((s->vendor == s2->vendor) != (pass == 0))
166             continue;
167           str = solvable_lookup_str(s2, basekeyname);
168           if (!str || strcmp(str, basestr))
169             continue;
170           str = solvable_lookup_str(s2, keyname);
171           if (str)
172             return str;
173         }
174 #ifdef ENABLE_LINKED_PKGS
175       /* autopattern/product translation magic */
176       if (pass)
177         {
178           const char *n = pool_id2str(pool, name);
179           if (*n == 'p')
180             {
181               if (!strncmp("pattern:", n, 8) && (name = find_autopattern_name(pool, s)) != 0)
182                 pass = -1;
183               if (!strncmp("product:", n, 8) && (name = find_autoproduct_name(pool, s)) != 0)
184                 pass = -1;
185             }
186         }
187 #endif
188     }
189   return usebase ? basestr : 0;
190 }
191
192 const char *
193 solvable_lookup_str_poollang(Solvable *s, Id keyname)
194 {
195   Pool *pool;
196   int i, cols;
197   const char *str;
198   Id *row;
199
200   if (!s->repo)
201     return 0;
202   pool = s->repo->pool;
203   if (!pool->nlanguages)
204     return solvable_lookup_str(s, keyname);
205   cols = pool->nlanguages + 1;
206   if (!pool->languagecache)
207     {
208       pool->languagecache = solv_calloc(cols * ID_NUM_INTERNAL, sizeof(Id));
209       pool->languagecacheother = 0;
210     }
211   if (keyname >= ID_NUM_INTERNAL)
212     {
213       row = pool->languagecache + ID_NUM_INTERNAL * cols;
214       for (i = 0; i < pool->languagecacheother; i++, row += cols)
215         if (*row == keyname)
216           break;
217       if (i >= pool->languagecacheother)
218         {
219           pool->languagecache = solv_realloc2(pool->languagecache, pool->languagecacheother + 1, cols * sizeof(Id));
220           row = pool->languagecache + cols * (ID_NUM_INTERNAL + pool->languagecacheother++);
221           *row = keyname;
222         }
223     }
224   else
225     row = pool->languagecache + keyname * cols;
226   row++;        /* skip keyname */
227   for (i = 0; i < pool->nlanguages; i++, row++)
228     {
229       if (!*row)
230         *row = pool_id2langid(pool, keyname, pool->languages[i], 1);
231       str = solvable_lookup_str_base(s, *row, keyname, 0);
232       if (str)
233         return str;
234     }
235   return solvable_lookup_str(s, keyname);
236 }
237
238 const char *
239 solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase)
240 {
241   if (s->repo)
242     {
243       Id id = pool_id2langid(s->repo->pool, keyname, lang, 0);
244       if (id)
245         return solvable_lookup_str_base(s, id, keyname, usebase);
246       if (!usebase)
247         return 0;
248     }
249   return solvable_lookup_str(s, keyname);
250 }
251
252 unsigned long long
253 solvable_lookup_num(Solvable *s, Id keyname, unsigned long long notfound)
254 {
255   if (!s->repo)
256     return notfound;
257   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound);
258 }
259
260 unsigned int
261 solvable_lookup_sizek(Solvable *s, Id keyname, unsigned int notfound)
262 {
263   unsigned long long size;
264   if (!s->repo)
265     return notfound;
266   size = solvable_lookup_num(s, keyname, (unsigned long long)notfound << 10);
267   return (unsigned int)((size + 1023) >> 10);
268 }
269
270 int
271 solvable_lookup_void(Solvable *s, Id keyname)
272 {
273   if (!s->repo)
274     return 0;
275   return repo_lookup_void(s->repo, s - s->repo->pool->solvables, keyname);
276 }
277
278 int
279 solvable_lookup_bool(Solvable *s, Id keyname)
280 {
281   if (!s->repo)
282     return 0;
283   /* historic nonsense: there are two ways of storing a bool, as num == 1 or void. test both. */
284   if (repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname) == REPOKEY_TYPE_VOID)
285     return 1;
286   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, 0) == 1;
287 }
288
289 const unsigned char *
290 solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep)
291 {
292   Repo *repo = s->repo;
293
294   if (!repo)
295     {
296       *typep = 0;
297       return 0;
298     }
299   return repo_lookup_bin_checksum(repo, s - repo->pool->solvables, keyname, typep);
300 }
301
302 const char *
303 solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep)
304 {
305   const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep);
306   return chk ? pool_bin2hex(s->repo->pool, chk, solv_chksum_len(*typep)) : 0;
307 }
308
309 static inline const char *
310 evrid2vrstr(Pool *pool, Id evrid)
311 {
312   const char *p, *evr = pool_id2str(pool, evrid);
313   if (!evr)
314     return evr;
315   for (p = evr; *p >= '0' && *p <= '9'; p++)
316     ;
317   return p != evr && *p == ':' && p[1] ? p + 1 : evr;
318 }
319
320 const char *
321 solvable_lookup_location(Solvable *s, unsigned int *medianrp)
322 {
323   Pool *pool;
324   int l = 0;
325   char *loc;
326   const char *mediadir, *mediafile;
327
328   if (medianrp)
329     *medianrp = 0;
330   if (!s->repo)
331     return 0;
332   pool = s->repo->pool;
333   if (medianrp)
334     *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 0);
335   if (solvable_lookup_void(s, SOLVABLE_MEDIADIR))
336     mediadir = pool_id2str(pool, s->arch);
337   else
338     mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR);
339   if (mediadir)
340     l = strlen(mediadir) + 1;
341   if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE))
342     {
343       const char *name, *evr, *arch;
344       name = pool_id2str(pool, s->name);
345       evr = evrid2vrstr(pool, s->evr);
346       arch = pool_id2str(pool, s->arch);
347       /* name-vr.arch.rpm */
348       loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7);
349       if (mediadir)
350         sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch);
351       else
352         sprintf(loc, "%s-%s.%s.rpm", name, evr, arch);
353     }
354   else
355     {
356       mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
357       if (!mediafile)
358         return 0;
359       loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1);
360       if (mediadir)
361         sprintf(loc, "%s/%s", mediadir, mediafile);
362       else
363         strcpy(loc, mediafile);
364     }
365   return loc;
366 }
367
368 const char *
369 solvable_get_location(Solvable *s, unsigned int *medianrp)
370 {
371   const char *loc = solvable_lookup_location(s, medianrp);
372   if (medianrp && *medianrp == 0)
373     *medianrp = 1;      /* compat, to be removed */
374   return loc;
375 }
376
377 const char *
378 solvable_lookup_sourcepkg(Solvable *s)
379 {
380   Pool *pool;
381   const char *evr, *name;
382   Id archid;
383
384   if (!s->repo)
385     return 0;
386   pool = s->repo->pool;
387   if (solvable_lookup_void(s, SOLVABLE_SOURCENAME))
388     name = pool_id2str(pool, s->name);
389   else
390     name = solvable_lookup_str(s, SOLVABLE_SOURCENAME);
391   if (!name)
392     return 0;
393   archid = solvable_lookup_id(s, SOLVABLE_SOURCEARCH);
394   if (solvable_lookup_void(s, SOLVABLE_SOURCEEVR))
395     evr = evrid2vrstr(pool, s->evr);
396   else
397     evr = solvable_lookup_str(s, SOLVABLE_SOURCEEVR);
398   if (archid == ARCH_SRC || archid == ARCH_NOSRC)
399     {
400       char *str;
401       str = pool_tmpjoin(pool, name, evr ? "-" : 0, evr);
402       str = pool_tmpappend(pool, str, ".", pool_id2str(pool, archid));
403       return pool_tmpappend(pool, str, ".rpm", 0);
404     }
405   else
406     return name;        /* FIXME */
407 }
408
409
410 /*****************************************************************************/
411
412 /*
413  * Create maps containing the state of each solvable. Input is a "installed" queue,
414  * it contains all solvable ids that are considered to be installed.
415  *
416  * The created maps can be used for * pool_calc_duchanges() and
417  * pool_calc_installsizechange().
418  *
419  */
420 void
421 pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap)
422 {
423   int i;
424   Solvable *s;
425   Id p, *dp;
426   Id *conp, con;
427
428   map_init(installedmap, pool->nsolvables);
429   if (conflictsmap)
430     map_init(conflictsmap, pool->nsolvables);
431   for (i = 0; i < installed->count; i++)
432     {
433       p = installed->elements[i];
434       if (p <= 0)       /* makes it work with decisionq */
435         continue;
436       MAPSET(installedmap, p);
437       if (!conflictsmap)
438         continue;
439       s = pool->solvables + p;
440       if (!s->conflicts)
441         continue;
442       conp = s->repo->idarraydata + s->conflicts;
443       while ((con = *conp++) != 0)
444         {
445           dp = pool_whatprovides_ptr(pool, con);
446           for (; *dp; dp++)
447             MAPSET(conflictsmap, *dp);
448         }
449     }
450 }
451
452 /* Tests if two solvables have identical content. Currently
453  * both solvables need to come from the same pool
454  */
455
456 int
457 solvable_identical(Solvable *s1, Solvable *s2)
458 {
459   unsigned int bt1, bt2;
460   Id rq1, rq2;
461   Id *reqp;
462   if (s1->name != s2->name)
463     return 0;
464   if (s1->arch != s2->arch)
465     return 0;
466   if (s1->evr != s2->evr)
467     return 0;
468
469   /* check vendor, map missing vendor to empty string */
470   if ((s1->vendor ? s1->vendor : 1) != (s2->vendor ? s2->vendor : 1))
471     {
472       /* workaround for bug 881493 */
473       if (s1->repo && !strncmp(pool_id2str(s1->repo->pool, s1->name), "product:", 8))
474         return 1;
475       return 0;
476     }
477
478   /* looking good, try some fancier stuff */
479   /* might also look up the package checksum here */
480   bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0);
481   bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0);
482   if (bt1 && bt2)
483     {
484       if (bt1 != bt2)
485         return 0;
486     }
487   else
488     {
489       if (s1->repo)
490         {
491           /* workaround for bugs 881493 and 885830*/
492           const char *n = pool_id2str(s1->repo->pool, s1->name);
493           if (!strncmp(n, "product:", 8) || !strncmp(n, "application:", 12))
494             return 1;
495         }
496       /* look at requires in a last attempt to find recompiled packages */
497       rq1 = rq2 = 0;
498       if (s1->requires)
499         for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
500           rq1 ^= *reqp;
501       if (s2->requires)
502         for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
503           rq2 ^= *reqp;
504       if (rq1 != rq2)
505          return 0;
506     }
507   return 1;
508 }
509
510 /* return the self provide dependency of a solvable */
511 Id
512 solvable_selfprovidedep(Solvable *s)
513 {
514   Pool *pool;
515   Reldep *rd;
516   Id prov, *provp;
517
518   if (!s->repo)
519     return s->name;
520   pool = s->repo->pool;
521   if (s->provides)
522     {
523       provp = s->repo->idarraydata + s->provides;
524       while ((prov = *provp++) != 0)
525         {
526           if (!ISRELDEP(prov))
527             continue;
528           rd = GETRELDEP(pool, prov);
529           if (rd->name == s->name && rd->evr == s->evr && rd->flags == REL_EQ)
530             return prov;
531         }
532     }
533   return pool_rel2id(pool, s->name, s->evr, REL_EQ, 1);
534 }
535
536 /* setter functions, simply call the repo variants */
537 void
538 solvable_set_id(Solvable *s, Id keyname, Id id)
539 {
540   repo_set_id(s->repo, s - s->repo->pool->solvables, keyname, id);
541 }
542
543 void
544 solvable_set_num(Solvable *s, Id keyname, unsigned long long num)
545 {
546   repo_set_num(s->repo, s - s->repo->pool->solvables, keyname, num);
547 }
548
549 void
550 solvable_set_str(Solvable *s, Id keyname, const char *str)
551 {
552   repo_set_str(s->repo, s - s->repo->pool->solvables, keyname, str);
553 }
554
555 void
556 solvable_set_poolstr(Solvable *s, Id keyname, const char *str)
557 {
558   repo_set_poolstr(s->repo, s - s->repo->pool->solvables, keyname, str);
559 }
560
561 void
562 solvable_add_poolstr_array(Solvable *s, Id keyname, const char *str)
563 {
564   repo_add_poolstr_array(s->repo, s - s->repo->pool->solvables, keyname, str);
565 }
566
567 void
568 solvable_add_idarray(Solvable *s, Id keyname, Id id)
569 {
570   repo_add_idarray(s->repo, s - s->repo->pool->solvables, keyname, id);
571 }
572
573 void
574 solvable_add_deparray(Solvable *s, Id keyname, Id dep, Id marker)
575 {
576   repo_add_deparray(s->repo, s - s->repo->pool->solvables, keyname, dep, marker);
577 }
578
579 void
580 solvable_set_idarray(Solvable *s, Id keyname, Queue *q)
581 {
582   repo_set_idarray(s->repo, s - s->repo->pool->solvables, keyname, q);
583 }
584
585 void
586 solvable_set_deparray(Solvable *s, Id keyname, Queue *q, Id marker)
587 {
588   repo_set_deparray(s->repo, s - s->repo->pool->solvables, keyname, q, marker);
589 }
590
591 void
592 solvable_unset(Solvable *s, Id keyname)
593 {
594   repo_unset(s->repo, s - s->repo->pool->solvables, keyname);
595 }
596
597 /* return true if a dependency intersects dep in the keyname array */
598 int
599 solvable_matchesdep(Solvable *s, Id keyname, Id dep, int marker)
600 {
601   int i;
602   Pool *pool = s->repo->pool;
603   Queue q;
604
605   if (keyname == SOLVABLE_NAME)
606     return pool_match_nevr(pool, s, dep) ? 1 : 0;       /* nevr match hack */
607   queue_init(&q);
608   solvable_lookup_deparray(s, keyname, &q, marker);
609   for (i = 0; i < q.count; i++)
610     if (pool_match_dep(pool, q.elements[i], dep))
611       break;
612   i = i == q.count ? 0 : 1;
613   queue_free(&q);
614   return i;
615 }