- add pool_id2langid function
[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_bool(Solvable *s, Id keyname)
230 {
231   return solvable_lookup_num(s, keyname, 0) ? 1 : 0;
232 }
233
234 int
235 solvable_lookup_void(Solvable *s, Id keyname)
236 {
237   Repo *repo = s->repo;
238   Pool *pool;
239   Repodata *data;
240   int i, j, n;
241
242   if (!repo)
243     return 0;
244   pool = repo->pool;
245   n = s - pool->solvables;
246   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
247     {
248       if (n < data->start || n >= data->end)
249         continue;
250       for (j = 1; j < data->nkeys; j++)
251         {
252           if (data->keys[j].name == keyname
253               && (data->keys[j].type == REPOKEY_TYPE_VOID))
254             {
255               if (repodata_lookup_void(data, n - data->start, j))
256                 return 1;
257             }
258         }
259     }
260   return 0;
261 }
262
263 const unsigned char *
264 solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep)
265 {
266   Repo *repo = s->repo;
267   Pool *pool;
268   Repodata *data;
269   int i, j, n;
270
271   *typep = 0;
272   if (!repo)
273     return 0;
274   pool = repo->pool;
275   n = s - pool->solvables;
276   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
277     {
278       if (n < data->start || n >= data->end)
279         continue;
280       for (j = 1; j < data->nkeys; j++)
281         {
282           if (data->keys[j].name == keyname
283               && (data->keys[j].type == REPOKEY_TYPE_MD5
284                   || data->keys[j].type == REPOKEY_TYPE_SHA1
285                   || data->keys[j].type == REPOKEY_TYPE_SHA256))
286             {
287               const unsigned char *chk = repodata_lookup_bin_checksum(data, n - data->start, j, typep);
288               if (chk)
289                 return chk;
290             }
291         }
292     }
293   return 0;
294 }
295
296 const char *
297 solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep)
298 {
299   const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep);
300   /* we need the repodata just as a reference for a pool */
301   return chk ? repodata_chk2str(s->repo->repodata, *typep, chk) : 0;
302 }
303
304 char *
305 solvable_get_location(Solvable *s, unsigned int *medianrp)
306 {
307   Pool *pool;
308   int l = 0;
309   char *loc;
310   const char *mediadir, *mediafile;
311
312   *medianrp = 0;
313   if (!s->repo)
314     return 0;
315   pool = s->repo->pool;
316   *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 1);
317   if (solvable_lookup_void(s, SOLVABLE_MEDIADIR))
318     mediadir = id2str(pool, s->arch);
319   else
320     mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR);
321   if (mediadir)
322     l = strlen(mediadir) + 1;
323   if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE))
324     {
325       const char *name, *evr, *arch;
326       name = id2str(pool, s->name);
327       evr = id2str(pool, s->evr);
328       arch = id2str(pool, s->arch);
329       /* name-evr.arch.rpm */
330       loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7);
331       if (mediadir)
332         sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch);
333       else
334         sprintf(loc, "%s-%s.%s.rpm", name, evr, arch);
335     }
336   else
337     {
338       mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
339       if (!mediafile)
340         return 0;
341       loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1);
342       if (mediadir)
343         sprintf(loc, "%s/%s", mediadir, mediafile);
344       else
345         strcpy(loc, mediafile);
346     }
347   return loc;
348 }
349
350 /*****************************************************************************/
351
352 static inline Id dep2name(Pool *pool, Id dep)
353 {
354   while (ISRELDEP(dep))
355     {
356       Reldep *rd = rd = GETRELDEP(pool, dep);
357       dep = rd->name;
358     }
359   return dep;
360 }
361
362 static inline int providedbyinstalled(Pool *pool, Map *installed, Id dep)
363 {
364   Id p, *pp;
365   FOR_PROVIDES(p, pp, dep)
366     {
367       if (p == SYSTEMSOLVABLE)
368         return -1;
369       if (MAPTST(installed, p))
370         return 1;
371     }
372   return 0;
373 }
374
375 /*
376  * solvable_trivial_installable_map - anwers is a solvable is installable
377  * without any other installs/deinstalls.
378  * The packages considered to be installed are provided via the
379  * installedmap bitmap. A additional "conflictsmap" bitmap providing
380  * information about the conflicts of the installed packages can be
381  * used for extra speed up. Provide a NULL pointer if you do not
382  * have this information.
383  * Both maps can be created with pool_create_state_maps() or
384  * solver_create_state_maps().
385  *
386  * returns:
387  * 1:  solvable is installable without any other package changes
388  * 0:  solvable is not installable
389  * -1: solvable is installable, but doesn't constrain any installed packages
390  */
391 int
392 solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap)
393 {
394   Pool *pool = s->repo->pool;
395   Solvable *s2;
396   Id p, *pp, *dp;
397   Id *reqp, req;
398   Id *conp, con;
399   Id *obsp, obs;
400   int r, interesting = 0;
401
402   if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables))
403     return 0;
404   if (s->requires)
405     {
406       reqp = s->repo->idarraydata + s->requires;
407       while ((req = *reqp++) != 0)
408         {
409           if (req == SOLVABLE_PREREQMARKER)
410             continue;
411           r = providedbyinstalled(pool, installedmap, req);
412           if (!r)
413             return 0;
414           if (r > 0)
415             interesting = 1;
416         }
417     }
418   if (s->conflicts)
419     {
420       conp = s->repo->idarraydata + s->conflicts;
421       while ((con = *conp++) != 0)
422         {
423           if (providedbyinstalled(pool, installedmap, con))
424             return 0;
425           if (!interesting && ISRELDEP(con))
426             {
427               con = dep2name(pool, con);
428               if (providedbyinstalled(pool, installedmap, con))
429                 interesting = 1;
430             }
431         }
432     }
433   if (s->repo)
434     {
435       Repo *installed = 0;
436       if (s->obsoletes && s->repo != installed)
437         {
438           obsp = s->repo->idarraydata + s->obsoletes;
439           while ((obs = *obsp++) != 0)
440             {
441               if (providedbyinstalled(pool, installedmap, obs))
442                 return 0;
443             }
444         }
445       if (s->repo != installed)
446         {
447           FOR_PROVIDES(p, pp, s->name)
448             {
449               s2 = pool->solvables + p;
450               if (s2->repo == installed && s2->name == s->name)
451                 return 0;
452             }
453         }
454     }
455   if (!conflictsmap)
456     {
457       int i;
458
459       p = s - pool->solvables;
460       for (i = 1; i < pool->nsolvables; i++)
461         {
462           if (!MAPTST(installedmap, i))
463             continue;
464           s2 = pool->solvables + i;
465           if (!s2->conflicts)
466             continue;
467           conp = s2->repo->idarraydata + s2->conflicts;
468           while ((con = *conp++) != 0)
469             {
470               dp = pool_whatprovides(pool, con);
471               for (; *dp; dp++)
472                 if (*dp == p)
473                   return 0;
474             }
475         }
476      }
477   return interesting ? 1 : -1;
478 }
479
480 /*
481  * different interface for solvable_trivial_installable_map, where
482  * the information about the installed packages is provided
483  * by a queue.
484  */
485 int
486 solvable_trivial_installable_queue(Solvable *s, Queue *installed)
487 {
488   Pool *pool = s->repo->pool;
489   int i;
490   Id p;
491   Map installedmap;
492   int r;
493
494   map_init(&installedmap, pool->nsolvables);
495   for (i = 0; i < installed->count; i++)
496     {
497       p = installed->elements[i];
498       if (p > 0)                /* makes it work with decisionq */
499         MAPSET(&installedmap, p);
500     }
501   r = solvable_trivial_installable_map(s, &installedmap, 0);
502   map_free(&installedmap);
503   return r;
504 }
505
506 /*
507  * different interface for solvable_trivial_installable_map, where
508  * the information about the installed packages is provided
509  * by a repo containing the installed solvables.
510  */
511 int
512 solvable_trivial_installable_repo(Solvable *s, Repo *installed)
513 {
514   Pool *pool = s->repo->pool;
515   Id p;
516   Solvable *s2;
517   Map installedmap;
518   int r;
519
520   map_init(&installedmap, pool->nsolvables);
521   FOR_REPO_SOLVABLES(installed, p, s2)
522     MAPSET(&installedmap, p);
523   r = solvable_trivial_installable_map(s, &installedmap, 0);
524   map_free(&installedmap);
525   return r;
526 }
527
528
529 /*****************************************************************************/
530
531 /*
532  * Create maps containing the state of each solvable. Input is a "installed" queue,
533  * it contains all solvable ids that are considered to be installed.
534  * 
535  * The created maps can be used for solvable_trivial_installable_map(),
536  * pool_calc_duchanges(), pool_calc_installsizechange().
537  *
538  */
539 void
540 pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap)
541 {
542   int i;
543   Solvable *s;
544   Id p, *dp;
545   Id *conp, con;
546
547   map_init(installedmap, pool->nsolvables);
548   if (conflictsmap)
549     map_init(conflictsmap, pool->nsolvables);
550   for (i = 0; i < installed->count; i++)
551     {
552       p = installed->elements[i];
553       if (p <= 0)       /* makes it work with decisionq */
554         continue;
555       MAPSET(installedmap, p);
556       if (!conflictsmap)
557         continue;
558       s = pool->solvables + p;
559       if (!s->conflicts)
560         continue;
561       conp = s->repo->idarraydata + s->conflicts;
562       while ((con = *conp++) != 0)
563         {
564           dp = pool_whatprovides(pool, con);
565           for (; *dp; dp++)
566             MAPSET(conflictsmap, *dp);
567         }
568     }
569 }
570