don't access r->p after solver_addrule is called, as it may realloc the rules
[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 pool_solvable2str(Pool *pool, Solvable *s)
27 {
28   const char *n, *e, *a;
29   int nl, el, al;
30   char *p;
31   n = pool_id2str(pool, s->name);
32   e = pool_id2str(pool, s->evr);
33   /* XXX: may want to skip the epoch here */
34   a = pool_id2str(pool, s->arch);
35   nl = strlen(n);
36   el = strlen(e);
37   al = strlen(a);
38   if (pool->havedistepoch)
39     {
40       /* strip the distepoch from the evr */
41       const char *de = strrchr(e, '-');
42       if (de && (de = strchr(de, ':')) != 0)
43         el = de - e;
44     }
45   p = pool_alloctmpspace(pool, nl + el + al + 3);
46   strcpy(p, n);
47   p[nl] = '-';
48   strncpy(p + nl + 1, e, el);
49   p[nl + 1 + el] = '.';
50   strcpy(p + nl + 1 + el + 1, a);
51   return p;
52 }
53
54 Id
55 solvable_lookup_type(Solvable *s, Id keyname)
56 {
57   if (!s->repo)
58     return 0;
59   return repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname);
60 }
61
62 Id
63 solvable_lookup_id(Solvable *s, Id keyname)
64 {
65   if (!s->repo)
66     return 0;
67   return repo_lookup_id(s->repo, s - s->repo->pool->solvables, keyname);
68 }
69
70 int
71 solvable_lookup_idarray(Solvable *s, Id keyname, Queue *q)
72 {
73   if (!s->repo)
74     {
75       queue_empty(q);
76       return 0;
77     }
78   return repo_lookup_idarray(s->repo, s - s->repo->pool->solvables, keyname, q);
79 }
80
81 int
82 solvable_lookup_deparray(Solvable *s, Id keyname, Queue *q, Id marker)
83 {
84   if (!s->repo)
85     {
86       queue_empty(q);
87       return 0;
88     }
89   return repo_lookup_deparray(s->repo, s - s->repo->pool->solvables, keyname, q, marker);
90 }
91
92 const char *
93 solvable_lookup_str(Solvable *s, Id keyname)
94 {
95   if (!s->repo)
96     return 0;
97   return repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname);
98 }
99
100 static const char *
101 solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname, int usebase)
102 {
103   Pool *pool;
104   const char *str, *basestr;
105   Id p, pp;
106   Solvable *s2;
107   int pass;
108
109   if (!s->repo)
110     return 0;
111   pool = s->repo->pool;
112   str = solvable_lookup_str(s, keyname);
113   if (str || keyname == basekeyname)
114     return str;
115   basestr = solvable_lookup_str(s, basekeyname);
116   if (!basestr)
117     return 0;
118   /* search for a solvable with same name and same base that has the
119    * translation */
120   if (!pool->whatprovides)
121     return usebase ? basestr : 0;
122   /* we do this in two passes, first same vendor, then all other vendors */
123   for (pass = 0; pass < 2; pass++)
124     {
125       FOR_PROVIDES(p, pp, s->name)
126         {
127           s2 = pool->solvables + p;
128           if (s2->name != s->name)
129             continue;
130           if ((s->vendor == s2->vendor) != (pass == 0))
131             continue;
132           str = solvable_lookup_str(s2, basekeyname);
133           if (!str || strcmp(str, basestr))
134             continue;
135           str = solvable_lookup_str(s2, keyname);
136           if (str)
137             return str;
138         }
139     }
140   return usebase ? basestr : 0;
141 }
142
143 const char *
144 solvable_lookup_str_poollang(Solvable *s, Id keyname)
145 {
146   Pool *pool;
147   int i, cols;
148   const char *str;
149   Id *row;
150
151   if (!s->repo)
152     return 0;
153   pool = s->repo->pool;
154   if (!pool->nlanguages)
155     return solvable_lookup_str(s, keyname);
156   cols = pool->nlanguages + 1;
157   if (!pool->languagecache)
158     {
159       pool->languagecache = solv_calloc(cols * ID_NUM_INTERNAL, sizeof(Id));
160       pool->languagecacheother = 0;
161     }
162   if (keyname >= ID_NUM_INTERNAL)
163     {
164       row = pool->languagecache + ID_NUM_INTERNAL * cols;
165       for (i = 0; i < pool->languagecacheother; i++, row += cols)
166         if (*row == keyname)
167           break;
168       if (i >= pool->languagecacheother)
169         {
170           pool->languagecache = solv_realloc2(pool->languagecache, pool->languagecacheother + 1, cols * sizeof(Id));
171           row = pool->languagecache + cols * (ID_NUM_INTERNAL + pool->languagecacheother++);
172           *row = keyname;
173         }
174     }
175   else
176     row = pool->languagecache + keyname * cols;
177   row++;        /* skip keyname */
178   for (i = 0; i < pool->nlanguages; i++, row++)
179     {
180       if (!*row)
181         *row = pool_id2langid(pool, keyname, pool->languages[i], 1);
182       str = solvable_lookup_str_base(s, *row, keyname, 0);
183       if (str)
184         return str;
185     }
186   return solvable_lookup_str(s, keyname);
187 }
188
189 const char *
190 solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase)
191 {
192   if (s->repo)
193     {
194       Id id = pool_id2langid(s->repo->pool, keyname, lang, 0);
195       if (id)
196         return solvable_lookup_str_base(s, id, keyname, usebase);
197       if (!usebase)
198         return 0;
199     }
200   return solvable_lookup_str(s, keyname);
201 }
202
203 unsigned long long
204 solvable_lookup_num(Solvable *s, Id keyname, unsigned long long notfound)
205 {
206   if (!s->repo)
207     return notfound;
208   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound);
209 }
210
211 unsigned int
212 solvable_lookup_sizek(Solvable *s, Id keyname, unsigned int notfound)
213 {
214   unsigned long long size;
215   if (!s->repo)
216     return notfound;
217   size = solvable_lookup_num(s, keyname, (unsigned long long)notfound << 10);
218   return (unsigned int)((size + 1023) >> 10);
219 }
220
221 int
222 solvable_lookup_void(Solvable *s, Id keyname)
223 {
224   if (!s->repo)
225     return 0;
226   return repo_lookup_void(s->repo, s - s->repo->pool->solvables, keyname);
227 }
228
229 int
230 solvable_lookup_bool(Solvable *s, Id keyname)
231 {
232   if (!s->repo)
233     return 0;
234   /* historic nonsense: there are two ways of storing a bool, as num == 1 or void. test both. */
235   if (repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname) == REPOKEY_TYPE_VOID)
236     return 1;
237   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, 0) == 1;
238 }
239
240 const unsigned char *
241 solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep)
242 {
243   Repo *repo = s->repo;
244
245   if (!repo)
246     {
247       *typep = 0;
248       return 0;
249     }
250   return repo_lookup_bin_checksum(repo, s - repo->pool->solvables, keyname, typep);
251 }
252
253 const char *
254 solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep)
255 {
256   const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep);
257   return chk ? pool_bin2hex(s->repo->pool, chk, solv_chksum_len(*typep)) : 0;
258 }
259
260 static inline const char *
261 evrid2vrstr(Pool *pool, Id evrid)
262 {
263   const char *p, *evr = pool_id2str(pool, evrid);
264   if (!evr)
265     return evr;
266   for (p = evr; *p >= '0' && *p <= '9'; p++)
267     ;
268   return p != evr && *p == ':' && p[1] ? p + 1 : evr;
269 }
270
271 const char *
272 solvable_lookup_location(Solvable *s, unsigned int *medianrp)
273 {
274   Pool *pool;
275   int l = 0;
276   char *loc;
277   const char *mediadir, *mediafile;
278
279   if (medianrp)
280     *medianrp = 0;
281   if (!s->repo)
282     return 0;
283   pool = s->repo->pool;
284   if (medianrp)
285     *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 0);
286   if (solvable_lookup_void(s, SOLVABLE_MEDIADIR))
287     mediadir = pool_id2str(pool, s->arch);
288   else
289     mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR);
290   if (mediadir)
291     l = strlen(mediadir) + 1;
292   if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE))
293     {
294       const char *name, *evr, *arch;
295       name = pool_id2str(pool, s->name);
296       evr = evrid2vrstr(pool, s->evr);
297       arch = pool_id2str(pool, s->arch);
298       /* name-vr.arch.rpm */
299       loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7);
300       if (mediadir)
301         sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch);
302       else
303         sprintf(loc, "%s-%s.%s.rpm", name, evr, arch);
304     }
305   else
306     {
307       mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
308       if (!mediafile)
309         return 0;
310       loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1);
311       if (mediadir)
312         sprintf(loc, "%s/%s", mediadir, mediafile);
313       else
314         strcpy(loc, mediafile);
315     }
316   return loc;
317 }
318
319 const char *
320 solvable_get_location(Solvable *s, unsigned int *medianrp)
321 {
322   const char *loc = solvable_lookup_location(s, medianrp);
323   if (medianrp && *medianrp == 0)
324     *medianrp = 1;      /* compat, to be removed */
325   return loc;
326 }
327
328 const char *
329 solvable_lookup_sourcepkg(Solvable *s)
330 {
331   Pool *pool;
332   const char *evr, *name;
333   Id archid;
334
335   if (!s->repo)
336     return 0;
337   pool = s->repo->pool;
338   if (solvable_lookup_void(s, SOLVABLE_SOURCENAME))
339     name = pool_id2str(pool, s->name);
340   else
341     name = solvable_lookup_str(s, SOLVABLE_SOURCENAME);
342   if (!name)
343     return 0;
344   archid = solvable_lookup_id(s, SOLVABLE_SOURCEARCH);
345   if (solvable_lookup_void(s, SOLVABLE_SOURCEEVR))
346     evr = evrid2vrstr(pool, s->evr);
347   else
348     evr = solvable_lookup_str(s, SOLVABLE_SOURCEEVR);
349   if (archid == ARCH_SRC || archid == ARCH_NOSRC)
350     {
351       char *str;
352       str = pool_tmpjoin(pool, name, evr ? "-" : 0, evr);
353       str = pool_tmpappend(pool, str, ".", pool_id2str(pool, archid));
354       return pool_tmpappend(pool, str, ".rpm", 0);
355     }
356   else 
357     return name;        /* FIXME */
358 }
359
360
361 /*****************************************************************************/
362
363 static inline Id dep2name(Pool *pool, Id dep)
364 {
365   while (ISRELDEP(dep))
366     {
367       Reldep *rd = rd = GETRELDEP(pool, dep);
368       dep = rd->name;
369     }
370   return dep;
371 }
372
373 static int providedbyinstalled_multiversion(Pool *pool, Map *installed, Id n, Id con) 
374 {
375   Id p, pp;
376   Solvable *sn = pool->solvables + n; 
377
378   FOR_PROVIDES(p, pp, sn->name)
379     {    
380       Solvable *s = pool->solvables + p; 
381       if (s->name != sn->name || s->arch != sn->arch)
382         continue;
383       if (!MAPTST(installed, p))
384         continue;
385       if (pool_match_nevr(pool, pool->solvables + p, con))
386         continue;
387       return 1;         /* found installed package that doesn't conflict */
388     }    
389   return 0;
390 }
391
392 static inline int providedbyinstalled(Pool *pool, Map *installed, Id dep, int ispatch, Map *noobsoletesmap)
393 {
394   Id p, pp;
395   FOR_PROVIDES(p, pp, dep)
396     {
397       if (p == SYSTEMSOLVABLE)
398         return -1;
399       if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep))
400         continue;
401       if (ispatch && noobsoletesmap && noobsoletesmap->size && MAPTST(noobsoletesmap, p) && ISRELDEP(dep))
402         if (providedbyinstalled_multiversion(pool, installed, p, dep))
403           continue;
404       if (MAPTST(installed, p))
405         return 1;
406     }
407   return 0;
408 }
409
410 /*
411  * solvable_trivial_installable_map - anwers is a solvable is installable
412  * without any other installs/deinstalls.
413  * The packages considered to be installed are provided via the
414  * installedmap bitmap. A additional "conflictsmap" bitmap providing
415  * information about the conflicts of the installed packages can be
416  * used for extra speed up. Provide a NULL pointer if you do not
417  * have this information.
418  * Both maps can be created with pool_create_state_maps() or
419  * solver_create_state_maps().
420  *
421  * returns:
422  * 1:  solvable is installable without any other package changes
423  * 0:  solvable is not installable
424  * -1: solvable is installable, but doesn't constrain any installed packages
425  */
426 int
427 solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap, Map *noobsoletesmap)
428 {
429   Pool *pool = s->repo->pool;
430   Solvable *s2;
431   Id p, *dp;
432   Id *reqp, req;
433   Id *conp, con;
434   int r, interesting = 0;
435
436   if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables))
437     return 0;
438   if (s->requires)
439     {
440       reqp = s->repo->idarraydata + s->requires;
441       while ((req = *reqp++) != 0)
442         {
443           if (req == SOLVABLE_PREREQMARKER)
444             continue;
445           r = providedbyinstalled(pool, installedmap, req, 0, 0);
446           if (!r)
447             return 0;
448           if (r > 0)
449             interesting = 1;
450         }
451     }
452   if (s->conflicts)
453     {
454       int ispatch = 0;
455
456       if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
457         ispatch = 1;
458       conp = s->repo->idarraydata + s->conflicts;
459       while ((con = *conp++) != 0)
460         {
461           if (providedbyinstalled(pool, installedmap, con, ispatch, noobsoletesmap))
462             return 0;
463           if (!interesting && ISRELDEP(con))
464             {
465               con = dep2name(pool, con);
466               if (providedbyinstalled(pool, installedmap, con, ispatch, noobsoletesmap))
467                 interesting = 1;
468             }
469         }
470     }
471 #if 0
472   if (s->repo)
473     {
474       Id *obsp, obs;
475       Repo *installed = 0;
476       if (s->obsoletes && s->repo != installed)
477         {
478           obsp = s->repo->idarraydata + s->obsoletes;
479           while ((obs = *obsp++) != 0)
480             {
481               if (providedbyinstalled(pool, installedmap, obs, 0, 0))
482                 return 0;
483             }
484         }
485       if (s->repo != installed)
486         {
487           Id pp;
488           FOR_PROVIDES(p, pp, s->name)
489             {
490               s2 = pool->solvables + p;
491               if (s2->repo == installed && s2->name == s->name)
492                 return 0;
493             }
494         }
495     }
496 #endif
497   if (!conflictsmap)
498     {
499       int i;
500
501       p = s - pool->solvables;
502       for (i = 1; i < pool->nsolvables; i++)
503         {
504           if (!MAPTST(installedmap, i))
505             continue;
506           s2 = pool->solvables + i;
507           if (!s2->conflicts)
508             continue;
509           conp = s2->repo->idarraydata + s2->conflicts;
510           while ((con = *conp++) != 0)
511             {
512               dp = pool_whatprovides_ptr(pool, con);
513               for (; *dp; dp++)
514                 if (*dp == p)
515                   return 0;
516             }
517         }
518      }
519   return interesting ? 1 : -1;
520 }
521
522 /*
523  * different interface for solvable_trivial_installable_map, where
524  * the information about the installed packages is provided
525  * by a queue.
526  */
527 int
528 solvable_trivial_installable_queue(Solvable *s, Queue *installed, Map *noobsoletesmap)
529 {
530   Pool *pool = s->repo->pool;
531   int i;
532   Id p;
533   Map installedmap;
534   int r;
535
536   map_init(&installedmap, pool->nsolvables);
537   for (i = 0; i < installed->count; i++)
538     {
539       p = installed->elements[i];
540       if (p > 0)                /* makes it work with decisionq */
541         MAPSET(&installedmap, p);
542     }
543   r = solvable_trivial_installable_map(s, &installedmap, 0, noobsoletesmap);
544   map_free(&installedmap);
545   return r;
546 }
547
548 /*
549  * different interface for solvable_trivial_installable_map, where
550  * the information about the installed packages is provided
551  * by a repo containing the installed solvables.
552  */
553 int
554 solvable_trivial_installable_repo(Solvable *s, Repo *installed, Map *noobsoletesmap)
555 {
556   Pool *pool = s->repo->pool;
557   Id p;
558   Solvable *s2;
559   Map installedmap;
560   int r;
561
562   map_init(&installedmap, pool->nsolvables);
563   FOR_REPO_SOLVABLES(installed, p, s2)
564     MAPSET(&installedmap, p);
565   r = solvable_trivial_installable_map(s, &installedmap, 0, noobsoletesmap);
566   map_free(&installedmap);
567   return r;
568 }
569
570
571 /*****************************************************************************/
572
573 /*
574  * Create maps containing the state of each solvable. Input is a "installed" queue,
575  * it contains all solvable ids that are considered to be installed.
576  * 
577  * The created maps can be used for solvable_trivial_installable_map(),
578  * pool_calc_duchanges(), pool_calc_installsizechange().
579  *
580  */
581 void
582 pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap)
583 {
584   int i;
585   Solvable *s;
586   Id p, *dp;
587   Id *conp, con;
588
589   map_init(installedmap, pool->nsolvables);
590   if (conflictsmap)
591     map_init(conflictsmap, pool->nsolvables);
592   for (i = 0; i < installed->count; i++)
593     {
594       p = installed->elements[i];
595       if (p <= 0)       /* makes it work with decisionq */
596         continue;
597       MAPSET(installedmap, p);
598       if (!conflictsmap)
599         continue;
600       s = pool->solvables + p;
601       if (!s->conflicts)
602         continue;
603       conp = s->repo->idarraydata + s->conflicts;
604       while ((con = *conp++) != 0)
605         {
606           dp = pool_whatprovides_ptr(pool, con);
607           for (; *dp; dp++)
608             MAPSET(conflictsmap, *dp);
609         }
610     }
611 }
612
613 /* Tests if two solvables have identical content. Currently
614  * both solvables need to come from the same pool
615  */
616 int
617 solvable_identical(Solvable *s1, Solvable *s2)
618 {
619   unsigned int bt1, bt2;
620   Id rq1, rq2;
621   Id *reqp;
622
623   if (s1->name != s2->name)
624     return 0;
625   if (s1->arch != s2->arch)
626     return 0;
627   if (s1->evr != s2->evr)
628     return 0;
629   /* map missing vendor to empty string */
630   if ((s1->vendor ? s1->vendor : 1) != (s2->vendor ? s2->vendor : 1))
631     return 0;
632
633   /* looking good, try some fancier stuff */
634   /* might also look up the package checksum here */
635   bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0);
636   bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0);
637   if (bt1 && bt2)
638     {
639       if (bt1 != bt2)
640         return 0;
641     }
642   else
643     {
644       /* look at requires in a last attempt to find recompiled packages */
645       rq1 = rq2 = 0;
646       if (s1->requires)
647         for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
648           rq1 ^= *reqp;
649       if (s2->requires)
650         for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
651           rq2 ^= *reqp;
652       if (rq1 != rq2)
653          return 0;
654     }
655   return 1;
656 }
657
658 /* return the self provide dependency of a solvable */
659 Id
660 solvable_selfprovidedep(Solvable *s)
661 {
662   Pool *pool;
663   Reldep *rd;
664   Id prov, *provp;
665
666   if (!s->repo)
667     return s->name;
668   pool = s->repo->pool;
669   if (s->provides)
670     {
671       provp = s->repo->idarraydata + s->provides;
672       while ((prov = *provp++) != 0)
673         {
674           if (!ISRELDEP(prov))
675             continue;
676           rd = GETRELDEP(pool, prov);
677           if (rd->name == s->name && rd->evr == s->evr && rd->flags == REL_EQ)
678             return prov;
679         }
680     }
681   return pool_rel2id(pool, s->name, s->evr, REL_EQ, 1);
682 }
683
684 /* setter functions, simply call the repo variants */
685 void
686 solvable_set_id(Solvable *s, Id keyname, Id id)
687 {
688   repo_set_id(s->repo, s - s->repo->pool->solvables, keyname, id);
689 }
690
691 void
692 solvable_set_num(Solvable *s, Id keyname, unsigned long long num)
693 {
694   repo_set_num(s->repo, s - s->repo->pool->solvables, keyname, num);
695 }
696
697 void
698 solvable_set_str(Solvable *s, Id keyname, const char *str)
699 {
700   repo_set_str(s->repo, s - s->repo->pool->solvables, keyname, str);
701 }
702
703 void
704 solvable_set_poolstr(Solvable *s, Id keyname, const char *str)
705 {
706   repo_set_poolstr(s->repo, s - s->repo->pool->solvables, keyname, str);
707 }
708
709 void
710 solvable_add_poolstr_array(Solvable *s, Id keyname, const char *str)
711 {
712   repo_add_poolstr_array(s->repo, s - s->repo->pool->solvables, keyname, str);
713 }
714
715 void
716 solvable_add_idarray(Solvable *s, Id keyname, Id id)
717 {
718   repo_add_idarray(s->repo, s - s->repo->pool->solvables, keyname, id);
719 }
720
721 void
722 solvable_add_deparray(Solvable *s, Id keyname, Id dep, Id marker)
723 {
724   repo_add_deparray(s->repo, s - s->repo->pool->solvables, keyname, dep, marker);
725 }
726
727 void
728 solvable_set_idarray(Solvable *s, Id keyname, Queue *q)
729 {
730   repo_set_idarray(s->repo, s - s->repo->pool->solvables, keyname, q);
731 }
732
733 void
734 solvable_set_deparray(Solvable *s, Id keyname, Queue *q, Id marker)
735 {
736   repo_set_deparray(s->repo, s - s->repo->pool->solvables, keyname, q, marker);
737 }
738
739 void
740 solvable_unset(Solvable *s, Id keyname)
741 {
742   repo_unset(s->repo, s - s->repo->pool->solvables, keyname);
743 }