satsolver  0.17.2
solvable.c
Go to the documentation of this file.
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 *
27 {
28  const char *n, *e, *a;
29  char *p;
30  n = id2str(pool, s->name);
31  e = id2str(pool, s->evr);
32  a = id2str(pool, s->arch);
33  p = pool_alloctmpspace(pool, strlen(n) + strlen(e) + strlen(a) + 3);
34  sprintf(p, "%s-%s.%s", n, e, a);
35  return p;
36 }
37 
38 Id
40 {
41  if (!s->repo)
42  return 0;
43  return repo_lookup_id(s->repo, s - s->repo->pool->solvables, keyname);
44 }
45 
46 int
48 {
49  if (!s->repo)
50  {
51  queue_empty(q);
52  return 0;
53  }
54  return repo_lookup_idarray(s->repo, s - s->repo->pool->solvables, keyname, q);
55 }
56 
57 const char *
59 {
60  if (!s->repo)
61  return 0;
62  return repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname);
63 }
64 
65 static const char *
66 solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname, int usebase)
67 {
68  Pool *pool;
69  const char *str, *basestr;
70  Id p, pp;
71  Solvable *s2;
72  int pass;
73 
74  if (!s->repo)
75  return 0;
76  pool = s->repo->pool;
77  str = solvable_lookup_str(s, keyname);
78  if (str || keyname == basekeyname)
79  return str;
80  basestr = solvable_lookup_str(s, basekeyname);
81  if (!basestr)
82  return 0;
83  /* search for a solvable with same name and same base that has the
84  * translation */
85  if (!pool->whatprovides)
86  return usebase ? basestr : 0;
87  /* we do this in two passes, first same vendor, then all other vendors */
88  for (pass = 0; pass < 2; pass++)
89  {
90  FOR_PROVIDES(p, pp, s->name)
91  {
92  s2 = pool->solvables + p;
93  if (s2->name != s->name)
94  continue;
95  if ((s->vendor == s2->vendor) != (pass == 0))
96  continue;
97  str = solvable_lookup_str(s2, basekeyname);
98  if (!str || strcmp(str, basestr))
99  continue;
100  str = solvable_lookup_str(s2, keyname);
101  if (str)
102  return str;
103  }
104  }
105  return usebase ? basestr : 0;
106 }
107 
108 const char *
110 {
111  Pool *pool;
112  int i, cols;
113  const char *str;
114  Id *row;
115 
116  if (!s->repo)
117  return 0;
118  pool = s->repo->pool;
119  if (!pool->nlanguages)
120  return solvable_lookup_str(s, keyname);
121  cols = pool->nlanguages + 1;
122  if (!pool->languagecache)
123  {
124  pool->languagecache = sat_calloc(cols * ID_NUM_INTERNAL, sizeof(Id));
125  pool->languagecacheother = 0;
126  }
127  if (keyname >= ID_NUM_INTERNAL)
128  {
129  row = pool->languagecache + ID_NUM_INTERNAL * cols;
130  for (i = 0; i < pool->languagecacheother; i++, row += cols)
131  if (*row == keyname)
132  break;
133  if (i >= pool->languagecacheother)
134  {
135  pool->languagecache = sat_realloc2(pool->languagecache, pool->languagecacheother + 1, cols * sizeof(Id));
136  row = pool->languagecache + cols * (ID_NUM_INTERNAL + pool->languagecacheother++);
137  *row = keyname;
138  }
139  }
140  else
141  row = pool->languagecache + keyname * cols;
142  row++; /* skip keyname */
143  for (i = 0; i < pool->nlanguages; i++, row++)
144  {
145  if (!*row)
146  *row = pool_id2langid(pool, keyname, pool->languages[i], 1);
147  str = solvable_lookup_str_base(s, *row, keyname, 0);
148  if (str)
149  return str;
150  }
151  return solvable_lookup_str(s, keyname);
152 }
153 
154 const char *
155 solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase)
156 {
157  if (s->repo)
158  {
159  Id id = pool_id2langid(s->repo->pool, keyname, lang, 0);
160  if (id)
161  return solvable_lookup_str_base(s, id, keyname, usebase);
162  if (!usebase)
163  return 0;
164  }
165  return solvable_lookup_str(s, keyname);
166 }
167 
168 unsigned int
169 solvable_lookup_num(Solvable *s, Id keyname, unsigned int notfound)
170 {
171  if (!s->repo)
172  return notfound;
173  return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound);
174 }
175 
176 int
178 {
179  if (!s->repo)
180  return 0;
181  return repo_lookup_void(s->repo, s - s->repo->pool->solvables, keyname);
182 }
183 
184 int
186 {
187  if (!s->repo)
188  return 0;
189  /* historic nonsense: there are two ways of storing a bool, as num == 1 or void. test both. */
190  if (repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname) == REPOKEY_TYPE_VOID)
191  return 1;
192  return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, 0) == 1;
193 }
194 
195 const unsigned char *
197 {
198  Repo *repo = s->repo;
199 
200  if (!repo)
201  {
202  *typep = 0;
203  return 0;
204  }
205  return repo_lookup_bin_checksum(repo, s - repo->pool->solvables, keyname, typep);
206 }
207 
208 const char *
210 {
211  const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep);
212  return chk ? pool_bin2hex(s->repo->pool, chk, sat_chksum_len(*typep)) : 0;
213 }
214 
215 static inline const char *
216 evrid2vrstr(Pool *pool, Id evrid)
217 {
218  const char *p, *evr = id2str(pool, evrid);
219  if (!evr)
220  return evr;
221  for (p = evr; *p >= '0' && *p <= '9'; p++)
222  ;
223  return p != evr && *p == ':' ? p + 1 : evr;
224 }
225 
226 char *
227 solvable_get_location(Solvable *s, unsigned int *medianrp)
228 {
229  Pool *pool;
230  int l = 0;
231  char *loc;
232  const char *mediadir, *mediafile;
233 
234  if (medianrp)
235  *medianrp = 0;
236  if (!s->repo)
237  return 0;
238  pool = s->repo->pool;
239  if (medianrp)
240  *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 1);
241  if (solvable_lookup_void(s, SOLVABLE_MEDIADIR))
242  mediadir = id2str(pool, s->arch);
243  else
244  mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR);
245  if (mediadir)
246  l = strlen(mediadir) + 1;
247  if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE))
248  {
249  const char *name, *evr, *arch;
250  name = id2str(pool, s->name);
251  evr = evrid2vrstr(pool, s->evr);
252  arch = id2str(pool, s->arch);
253  /* name-vr.arch.rpm */
254  loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7);
255  if (mediadir)
256  sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch);
257  else
258  sprintf(loc, "%s-%s.%s.rpm", name, evr, arch);
259  }
260  else
261  {
262  mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
263  if (!mediafile)
264  return 0;
265  loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1);
266  if (mediadir)
267  sprintf(loc, "%s/%s", mediadir, mediafile);
268  else
269  strcpy(loc, mediafile);
270  }
271  return loc;
272 }
273 
274 /*****************************************************************************/
275 
276 static inline Id dep2name(Pool *pool, Id dep)
277 {
278  while (ISRELDEP(dep))
279  {
280  Reldep *rd = rd = GETRELDEP(pool, dep);
281  dep = rd->name;
282  }
283  return dep;
284 }
285 
286 static inline int providedbyinstalled(Pool *pool, Map *installed, Id dep)
287 {
288  Id p, pp;
289  FOR_PROVIDES(p, pp, dep)
290  {
291  if (p == SYSTEMSOLVABLE)
292  return -1;
293  if (MAPTST(installed, p))
294  return 1;
295  }
296  return 0;
297 }
298 
299 /*
300  * solvable_trivial_installable_map - anwers is a solvable is installable
301  * without any other installs/deinstalls.
302  * The packages considered to be installed are provided via the
303  * installedmap bitmap. A additional "conflictsmap" bitmap providing
304  * information about the conflicts of the installed packages can be
305  * used for extra speed up. Provide a NULL pointer if you do not
306  * have this information.
307  * Both maps can be created with pool_create_state_maps() or
308  * solver_create_state_maps().
309  *
310  * returns:
311  * 1: solvable is installable without any other package changes
312  * 0: solvable is not installable
313  * -1: solvable is installable, but doesn't constrain any installed packages
314  */
315 int
316 solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap)
317 {
318  Pool *pool = s->repo->pool;
319  Solvable *s2;
320  Id p, pp, *dp;
321  Id *reqp, req;
322  Id *conp, con;
323  Id *obsp, obs;
324  int r, interesting = 0;
325 
326  if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables))
327  return 0;
328  if (s->requires)
329  {
330  reqp = s->repo->idarraydata + s->requires;
331  while ((req = *reqp++) != 0)
332  {
333  if (req == SOLVABLE_PREREQMARKER)
334  continue;
335  r = providedbyinstalled(pool, installedmap, req);
336  if (!r)
337  return 0;
338  if (r > 0)
339  interesting = 1;
340  }
341  }
342  if (s->conflicts)
343  {
344  conp = s->repo->idarraydata + s->conflicts;
345  while ((con = *conp++) != 0)
346  {
347  if (providedbyinstalled(pool, installedmap, con))
348  return 0;
349  if (!interesting && ISRELDEP(con))
350  {
351  con = dep2name(pool, con);
352  if (providedbyinstalled(pool, installedmap, con))
353  interesting = 1;
354  }
355  }
356  }
357  if (s->repo)
358  {
359  Repo *installed = 0;
360  if (s->obsoletes && s->repo != installed)
361  {
362  obsp = s->repo->idarraydata + s->obsoletes;
363  while ((obs = *obsp++) != 0)
364  {
365  if (providedbyinstalled(pool, installedmap, obs))
366  return 0;
367  }
368  }
369  if (s->repo != installed)
370  {
371  FOR_PROVIDES(p, pp, s->name)
372  {
373  s2 = pool->solvables + p;
374  if (s2->repo == installed && s2->name == s->name)
375  return 0;
376  }
377  }
378  }
379  if (!conflictsmap)
380  {
381  int i;
382 
383  p = s - pool->solvables;
384  for (i = 1; i < pool->nsolvables; i++)
385  {
386  if (!MAPTST(installedmap, i))
387  continue;
388  s2 = pool->solvables + i;
389  if (!s2->conflicts)
390  continue;
391  conp = s2->repo->idarraydata + s2->conflicts;
392  while ((con = *conp++) != 0)
393  {
394  dp = pool_whatprovides_ptr(pool, con);
395  for (; *dp; dp++)
396  if (*dp == p)
397  return 0;
398  }
399  }
400  }
401  return interesting ? 1 : -1;
402 }
403 
404 /*
405  * different interface for solvable_trivial_installable_map, where
406  * the information about the installed packages is provided
407  * by a queue.
408  */
409 int
411 {
412  Pool *pool = s->repo->pool;
413  int i;
414  Id p;
415  Map installedmap;
416  int r;
417 
418  map_init(&installedmap, pool->nsolvables);
419  for (i = 0; i < installed->count; i++)
420  {
421  p = installed->elements[i];
422  if (p > 0) /* makes it work with decisionq */
423  MAPSET(&installedmap, p);
424  }
425  r = solvable_trivial_installable_map(s, &installedmap, 0);
426  map_free(&installedmap);
427  return r;
428 }
429 
430 /*
431  * different interface for solvable_trivial_installable_map, where
432  * the information about the installed packages is provided
433  * by a repo containing the installed solvables.
434  */
435 int
437 {
438  Pool *pool = s->repo->pool;
439  Id p;
440  Solvable *s2;
441  Map installedmap;
442  int r;
443 
444  map_init(&installedmap, pool->nsolvables);
445  FOR_REPO_SOLVABLES(installed, p, s2)
446  MAPSET(&installedmap, p);
447  r = solvable_trivial_installable_map(s, &installedmap, 0);
448  map_free(&installedmap);
449  return r;
450 }
451 
452 
453 /*****************************************************************************/
454 
455 /*
456  * Create maps containing the state of each solvable. Input is a "installed" queue,
457  * it contains all solvable ids that are considered to be installed.
458  *
459  * The created maps can be used for solvable_trivial_installable_map(),
460  * pool_calc_duchanges(), pool_calc_installsizechange().
461  *
462  */
463 void
464 pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap)
465 {
466  int i;
467  Solvable *s;
468  Id p, *dp;
469  Id *conp, con;
470 
471  map_init(installedmap, pool->nsolvables);
472  if (conflictsmap)
473  map_init(conflictsmap, pool->nsolvables);
474  for (i = 0; i < installed->count; i++)
475  {
476  p = installed->elements[i];
477  if (p <= 0) /* makes it work with decisionq */
478  continue;
479  MAPSET(installedmap, p);
480  if (!conflictsmap)
481  continue;
482  s = pool->solvables + p;
483  if (!s->conflicts)
484  continue;
485  conp = s->repo->idarraydata + s->conflicts;
486  while ((con = *conp++) != 0)
487  {
488  dp = pool_whatprovides_ptr(pool, con);
489  for (; *dp; dp++)
490  MAPSET(conflictsmap, *dp);
491  }
492  }
493 }
494 
495 /* Tests if two solvables have identical content. Currently
496  * both solvables need to come from the same pool
497  */
498 int
500 {
501  unsigned int bt1, bt2;
502  Id rq1, rq2;
503  Id *reqp;
504 
505  if (s1->name != s2->name)
506  return 0;
507  if (s1->arch != s2->arch)
508  return 0;
509  if (s1->evr != s2->evr)
510  return 0;
511  /* map missing vendor to empty string */
512  if ((s1->vendor ? s1->vendor : 1) != (s2->vendor ? s2->vendor : 1))
513  return 0;
514 
515  /* looking good, try some fancier stuff */
516  /* might also look up the package checksum here */
517  bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0);
518  bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0);
519  if (bt1 && bt2)
520  {
521  if (bt1 != bt2)
522  return 0;
523  }
524  else
525  {
526  /* look at requires in a last attempt to find recompiled packages */
527  rq1 = rq2 = 0;
528  if (s1->requires)
529  for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
530  rq1 ^= *reqp;
531  if (s2->requires)
532  for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
533  rq2 ^= *reqp;
534  if (rq1 != rq2)
535  return 0;
536  }
537  return 1;
538 }
539 
540 /* return the self provide dependency of a solvable */
541 Id
543 {
544  Pool *pool;
545  Reldep *rd;
546  Id prov, *provp;
547 
548  if (!s->repo)
549  return s->name;
550  pool = s->repo->pool;
551  if (s->provides)
552  {
553  provp = s->repo->idarraydata + s->provides;
554  while ((prov = *provp++) != 0)
555  {
556  if (!ISRELDEP(prov))
557  continue;
558  rd = GETRELDEP(pool, prov);
559  if (rd->name == s->name && rd->evr == s->evr && rd->flags == REL_EQ)
560  return prov;
561  }
562  }
563  return rel2id(pool, s->name, s->evr, REL_EQ, 1);
564 }