- change interface for solvable_trivial_installable. We now have
[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   Pool *pool;
181   Id id;
182   char *p;
183   const char *kn, *str;
184
185   if (!s->repo)
186     return repo_lookup_str(s, keyname);
187   pool = s->repo->pool;
188   kn = id2str(pool, keyname);
189   p = sat_malloc(strlen(kn) + strlen(lang) + 2);
190   sprintf(p, "%s:%s", kn, lang);
191   id = str2id(pool, p, 0);
192   free(p);
193   if (id)
194     {
195       str = repo_lookup_str(s, id);
196       if (str)
197         return str;
198     }
199   return repo_lookup_str(s, keyname);
200 }
201
202 unsigned int
203 solvable_lookup_num(Solvable *s, Id keyname, unsigned int notfound)
204 {
205   Repo *repo = s->repo;
206   Pool *pool;
207   Repodata *data;
208   int i, j, n;
209
210   if (!repo)
211     return 0;
212   pool = repo->pool;
213   if (keyname == RPM_RPMDBID)
214     {
215       if (repo->rpmdbid)
216         return repo->rpmdbid[(s - pool->solvables) - repo->start];
217       return notfound;
218     }
219   n = s - pool->solvables;
220   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
221     {
222       if (n < data->start || n >= data->end)
223         continue;
224       for (j = 1; j < data->nkeys; j++)
225         {
226           if (data->keys[j].name == keyname
227               && (data->keys[j].type == REPOKEY_TYPE_U32
228                   || data->keys[j].type == REPOKEY_TYPE_NUM
229                   || data->keys[j].type == REPOKEY_TYPE_CONSTANT))
230             {
231               unsigned int value;
232               if (repodata_lookup_num(data, n - data->start, j, &value))
233                 return value;
234             }
235         }
236     }
237   return notfound;
238 }
239
240 int
241 solvable_lookup_bool(Solvable *s, Id keyname)
242 {
243   return solvable_lookup_num(s, keyname, 0) ? 1 : 0;
244 }
245
246 int
247 solvable_lookup_void(Solvable *s, Id keyname)
248 {
249   Repo *repo = s->repo;
250   Pool *pool;
251   Repodata *data;
252   int i, j, n;
253
254   if (!repo)
255     return 0;
256   pool = repo->pool;
257   n = s - pool->solvables;
258   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
259     {
260       if (n < data->start || n >= data->end)
261         continue;
262       for (j = 1; j < data->nkeys; j++)
263         {
264           if (data->keys[j].name == keyname
265               && (data->keys[j].type == REPOKEY_TYPE_VOID))
266             {
267               if (repodata_lookup_void(data, n - data->start, j))
268                 return 1;
269             }
270         }
271     }
272   return 0;
273 }
274
275 const unsigned char *
276 solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep)
277 {
278   Repo *repo = s->repo;
279   Pool *pool;
280   Repodata *data;
281   int i, j, n;
282
283   *typep = 0;
284   if (!repo)
285     return 0;
286   pool = repo->pool;
287   n = s - pool->solvables;
288   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
289     {
290       if (n < data->start || n >= data->end)
291         continue;
292       for (j = 1; j < data->nkeys; j++)
293         {
294           if (data->keys[j].name == keyname
295               && (data->keys[j].type == REPOKEY_TYPE_MD5
296                   || data->keys[j].type == REPOKEY_TYPE_SHA1
297                   || data->keys[j].type == REPOKEY_TYPE_SHA256))
298             {
299               const unsigned char *chk = repodata_lookup_bin_checksum(data, n - data->start, j, typep);
300               if (chk)
301                 return chk;
302             }
303         }
304     }
305   return 0;
306 }
307
308 const char *
309 solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep)
310 {
311   const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep);
312   /* we need the repodata just as a reference for a pool */
313   return chk ? repodata_chk2str(s->repo->repodata, *typep, chk) : 0;
314 }
315
316 char *
317 solvable_get_location(Solvable *s, unsigned int *medianrp)
318 {
319   Pool *pool;
320   int l = 0;
321   char *loc;
322   const char *mediadir, *mediafile;
323
324   *medianrp = 0;
325   if (!s->repo)
326     return 0;
327   pool = s->repo->pool;
328   *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 1);
329   if (solvable_lookup_void(s, SOLVABLE_MEDIADIR))
330     mediadir = id2str(pool, s->arch);
331   else
332     mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR);
333   if (mediadir)
334     l = strlen(mediadir) + 1;
335   if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE))
336     {
337       const char *name, *evr, *arch;
338       name = id2str(pool, s->name);
339       evr = id2str(pool, s->evr);
340       arch = id2str(pool, s->arch);
341       /* name-evr.arch.rpm */
342       loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7);
343       if (mediadir)
344         sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch);
345       else
346         sprintf(loc, "%s-%s.%s.rpm", name, evr, arch);
347     }
348   else
349     {
350       mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
351       if (!mediafile)
352         return 0;
353       loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1);
354       if (mediadir)
355         sprintf(loc, "%s/%s", mediadir, mediafile);
356       else
357         strcpy(loc, mediafile);
358     }
359   return loc;
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 inline int providedbyinstalled(Pool *pool, Map *installed, Id dep)
374 {
375   Id p, *pp;
376   FOR_PROVIDES(p, pp, dep)
377     {
378       if (p == SYSTEMSOLVABLE)
379         return -1;
380       if (MAPTST(installed, p))
381         return 1;
382     }
383   return 0;
384 }
385
386 /*
387  * returns:
388  * 1:  solvable is installable without any other package changes
389  * 0:  solvable is not installable
390  * -1: solvable is installable, but doesn't constrain any installed packages
391  */
392 int
393 solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap)
394 {
395   Pool *pool = s->repo->pool;
396   Solvable *s2;
397   Id p, *pp, *dp;
398   Id *reqp, req;
399   Id *conp, con;
400   Id *obsp, obs;
401   int r, interesting = 0;
402
403   if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables))
404     return 0;
405   if (s->requires)
406     {
407       reqp = s->repo->idarraydata + s->requires;
408       while ((req = *reqp++) != 0)
409         {
410           if (req == SOLVABLE_PREREQMARKER)
411             continue;
412           r = providedbyinstalled(pool, installedmap, req);
413           if (!r)
414             return 0;
415           if (r > 0)
416             interesting = 1;
417         }
418     }
419   if (s->conflicts)
420     {
421       conp = s->repo->idarraydata + s->conflicts;
422       while ((con = *conp++) != 0)
423         {
424           if (providedbyinstalled(pool, installedmap, con))
425             return 0;
426           if (!interesting && ISRELDEP(con))
427             {
428               con = dep2name(pool, con);
429               if (providedbyinstalled(pool, installedmap, con))
430                 interesting = 1;
431             }
432         }
433     }
434   if (0)
435     {
436       Repo *installed = 0;
437       if (s->obsoletes && s->repo != installed)
438         {
439           obsp = s->repo->idarraydata + s->obsoletes;
440           while ((obs = *obsp++) != 0)
441             {
442               if (providedbyinstalled(pool, installedmap, obs))
443                 return 0;
444             }
445         }
446       if (s->repo != installed)
447         {
448           FOR_PROVIDES(p, pp, s->name)
449             {
450               s2 = pool->solvables + p;
451               if (s2->repo == installed && s2->name == s->name)
452                 return 0;
453             }
454         }
455     }
456   if (!conflictsmap)
457     {
458       int i;
459
460       p = s - pool->solvables;
461       for (i = 1; i < pool->nsolvables; i++)
462         {
463           if (!MAPTST(installedmap, i))
464             continue;
465           s2 = pool->solvables + i;
466           if (!s2->conflicts)
467             continue;
468           conp = s2->repo->idarraydata + s2->conflicts;
469           while ((con = *conp++) != 0)
470             {
471               dp = pool_whatprovides(pool, con);
472               for (; *dp; dp++)
473                 if (*dp == p)
474                   return 0;
475             }
476         }
477      }
478   return interesting ? 1 : -1;
479 }
480
481 int
482 solvable_trivial_installable_queue(Solvable *s, Queue *installed)
483 {
484   Pool *pool = s->repo->pool;
485   int i;
486   Id p;
487   Map installedmap;
488   int r;
489
490   map_init(&installedmap, pool->nsolvables);
491   for (i = 0; i < installed->count; i++)
492     {
493       p = installed->elements[i];
494       if (p > 0)                /* makes it work with decisionq */
495         MAPSET(&installedmap, p);
496     }
497   r = solvable_trivial_installable_map(s, &installedmap, 0);
498   map_free(&installedmap);
499   return r;
500 }
501
502 int
503 solvable_trivial_installable_repo(Solvable *s, Repo *installed)
504 {
505   Pool *pool = s->repo->pool;
506   Id p;
507   Solvable *s2;
508   Map installedmap;
509   int r;
510
511   map_init(&installedmap, pool->nsolvables);
512   FOR_REPO_SOLVABLES(installed, p, s2)
513     MAPSET(&installedmap, p);
514   r = solvable_trivial_installable_map(s, &installedmap, 0);
515   map_free(&installedmap);
516   return r;
517 }
518
519 void
520 create_trivial_installable_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap)
521 {
522   int i;
523   Solvable *s;
524   Id p, *dp;
525   Id *conp, con;
526
527   map_init(installedmap, pool->nsolvables);
528   map_init(conflictsmap, pool->nsolvables);
529   for (i = 0; i < installed->count; i++)
530     {
531       p = installed->elements[i];
532       if (p <= 0)       /* makes it work with decisionq */
533         continue;
534       MAPSET(installedmap, p);
535       s = pool->solvables + p;
536       if (!s->conflicts)
537         continue;
538       conp = s->repo->idarraydata + s->conflicts;
539       while ((con = *conp++) != 0)
540         {
541           dp = pool_whatprovides(pool, con);
542           for (; *dp; dp++)
543             MAPSET(conflictsmap, *dp);
544         }
545     }
546 }
547