e946a89a7538fd2f1455c592670dfc0f694b3275
[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, Repo *installed, Id dep)
374 {
375   Id p, *pp;
376   Solvable *s;
377   FOR_PROVIDES(p, pp, dep)
378     {
379       if (p == SYSTEMSOLVABLE)
380         return -1;
381       s = pool->solvables + p;
382       if (s->repo && s->repo == installed)
383         return 1;
384     }
385   return 0;
386 }
387
388 /*
389  * returns:
390  * 1:  solvable is installable without any other package changes
391  * 0:  solvable is not installable
392  * -1: solvable is installable, but doesn't constrain any installed packages
393  */
394 int
395 solvable_trivial_installable(Solvable *s, Repo *installed)
396 {
397   Pool *pool = s->repo->pool;
398   Solvable *s2;
399   Id p, *pp, *dp;
400   Id *reqp, req;
401   Id *conp, con;
402   Id *obsp, obs;
403   int r, interesting = 0;
404
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, installed, req);
413           if (!r)
414             return 0;
415           if (r > 0)
416             interesting = 1;
417         }
418     }
419   if (!installed)
420     return 1;
421   if (s->conflicts)
422     {
423       conp = s->repo->idarraydata + s->conflicts;
424       while ((con = *conp++) != 0)
425         {
426           if (providedbyinstalled(pool, installed, con))
427             return 0;
428           if (!interesting && ISRELDEP(con))
429             {
430               con = dep2name(pool, con);
431               if (providedbyinstalled(pool, installed, con))
432                 interesting = 1;
433             }
434         }
435     }
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, installed, 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   FOR_REPO_SOLVABLES(installed, p, s2)
455     {
456       if (!s2->conflicts)
457         continue;
458       conp = s->repo->idarraydata + s->conflicts;
459       while ((con = *conp++) != 0)
460         {
461           dp = pool_whatprovides(pool, con);
462           for (; *dp; dp++)
463             if (*dp == s - pool->solvables)
464               return 0;
465         }
466     }
467   return interesting ? 1 : -1;
468 }