1 /** \ingroup rpmdep
2 * \file lib/rpmds.c
3 */
4 #include "system.h"
5
6 #include <rpm/rpmtypes.h>
7 #include <rpm/rpmlib.h> /* rpmvercmp */
8 #include <rpm/rpmstring.h>
9 #include <rpm/rpmlog.h>
10 #include <rpm/rpmstrpool.h>
11
12 #include "lib/rpmds_internal.h"
13
14 #include "debug.h"
15
16 int _rpmds_debug = 0;
17
18 int _rpmds_nopromote = 1;
19
20 /**
21 * A package dependency set.
22 */
23 struct rpmds_s {
24 rpmstrPool pool; /*!< String pool. */
25 const char * Type; /*!< Tag name. */
26 char * DNEVR; /*!< Formatted dependency string. */
27 rpmsid * N; /*!< Dependency name id's (pool) */
28 rpmsid * EVR; /*!< Dependency EVR id's (pool) */
29 rpmsenseFlags * Flags; /*!< Bit(s) identifying context/comparison. */
30 rpm_color_t * Color; /*!< Bit(s) calculated from file color(s). */
31 rpmTagVal tagN; /*!< Header tag. */
32 int32_t Count; /*!< No. of elements */
33 unsigned int instance; /*!< From rpmdb instance? */
34 int i; /*!< Element index. */
35 int nrefs; /*!< Reference count. */
36 int *ti; /*!< Trigger index. */
37 };
38
39 struct depinfo_s {
40 rpmTagVal typeTag;
41 rpmTagVal evrTag;
42 rpmTagVal flagTag;
43 rpmTagVal ixTag;
44 char *name;
45 char abrev;
46 };
47
48 static const struct depinfo_s depTypes[] = {
49 { RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION,
50 RPMTAG_PROVIDEFLAGS, 0,
51 "Provides", 'P',
52 },
53 { RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION,
54 RPMTAG_REQUIREFLAGS, 0,
55 "Requires", 'R',
56 },
57 { RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION,
58 RPMTAG_CONFLICTFLAGS, 0,
59 "Conflicts", 'C',
60 },
61 { RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION,
62 RPMTAG_OBSOLETEFLAGS, 0,
63 "Obsoletes", 'O',
64 },
65 { RPMTAG_SUPPLEMENTNAME, RPMTAG_SUPPLEMENTVERSION,
66 RPMTAG_SUPPLEMENTFLAGS, 0,
67 "Supplements", 'S',
68 },
69 { RPMTAG_ENHANCENAME, RPMTAG_ENHANCEVERSION,
70 RPMTAG_ENHANCEFLAGS, 0,
71 "Enhances", 'e',
72 },
73 { RPMTAG_RECOMMENDNAME, RPMTAG_RECOMMENDVERSION,
74 RPMTAG_RECOMMENDFLAGS, 0,
75 "Recommends", 'r',
76 },
77 { RPMTAG_SUGGESTNAME, RPMTAG_SUGGESTVERSION,
78 RPMTAG_SUGGESTFLAGS, 0,
79 "Suggests", 's',
80 },
81 { RPMTAG_ORDERNAME, RPMTAG_ORDERVERSION,
82 RPMTAG_ORDERFLAGS, 0,
83 "Order", 'o',
84 },
85 { RPMTAG_TRIGGERNAME, RPMTAG_TRIGGERVERSION,
86 RPMTAG_TRIGGERFLAGS, RPMTAG_TRIGGERINDEX,
87 "Trigger", 't',
88 },
89 { RPMTAG_FILETRIGGERNAME, RPMTAG_FILETRIGGERVERSION,
90 RPMTAG_FILETRIGGERFLAGS, RPMTAG_FILETRIGGERINDEX,
91 "FileTrigger", 'f',
92 },
93 { RPMTAG_TRANSFILETRIGGERNAME, RPMTAG_TRANSFILETRIGGERVERSION,
94 RPMTAG_TRANSFILETRIGGERFLAGS, RPMTAG_TRANSFILETRIGGERINDEX,
95 "TransFileTrigger", 'F',
96 },
97 { RPMTAG_OLDSUGGESTSNAME, RPMTAG_OLDSUGGESTSVERSION,
98 RPMTAG_OLDSUGGESTSFLAGS, 0,
99 "Oldsuggests", '?',
100 },
101 { RPMTAG_OLDENHANCESNAME, RPMTAG_OLDENHANCESVERSION,
102 RPMTAG_OLDENHANCESFLAGS, 0,
103 "Oldenhances", '?',
104 },
105 { 0, 0,
106 0, 0,
107 NULL, 0,
108 }
109 };
110
depinfoByTag(rpmTagVal tag)111 static const struct depinfo_s *depinfoByTag(rpmTagVal tag)
112 {
113 for (const struct depinfo_s *dse = depTypes; dse->name; dse++) {
114 if (tag == dse->typeTag)
115 return dse;
116 }
117 return NULL;
118 }
119
depinfoByAbrev(char abrev)120 static const struct depinfo_s *depinfoByAbrev(char abrev)
121 {
122 for (const struct depinfo_s *dse = depTypes; dse->name; dse++) {
123 if (abrev == dse->abrev)
124 return dse;
125 }
126 return NULL;
127 }
dsType(rpmTagVal tag,const char ** Type,rpmTagVal * tagEVR,rpmTagVal * tagF,rpmTagVal * tagTi)128 static int dsType(rpmTagVal tag,
129 const char ** Type, rpmTagVal * tagEVR, rpmTagVal * tagF,
130 rpmTagVal * tagTi)
131 {
132 const struct depinfo_s *di = depinfoByTag(tag);
133 if (di) {
134 if (Type) *Type = di->name;
135 if (tagEVR) *tagEVR = di->evrTag;
136 if (tagF) *tagF = di->flagTag;
137 if (tagTi) *tagTi = di->ixTag;
138 }
139 return (di == NULL);
140 }
141
tagNToChar(rpmTagVal tagN)142 static char tagNToChar(rpmTagVal tagN)
143 {
144 const struct depinfo_s *di = depinfoByTag(tagN);
145 return (di != NULL) ? di->abrev : '\0';
146 }
147
rpmdsDToTagN(char deptype)148 rpmTagVal rpmdsDToTagN(char deptype)
149 {
150 const struct depinfo_s *di = depinfoByAbrev(deptype);
151 return (di != NULL) ? di->typeTag : RPMTAG_NOT_FOUND;
152 }
153
rpmdsNIdIndex(rpmds ds,int i)154 rpmsid rpmdsNIdIndex(rpmds ds, int i)
155 {
156 rpmsid id = 0;
157 if (ds != NULL && i >= 0 && i < ds->Count && ds->N != NULL)
158 id = ds->N[i];
159 return id;
160 }
161
rpmdsEVRIdIndex(rpmds ds,int i)162 rpmsid rpmdsEVRIdIndex(rpmds ds, int i)
163 {
164 rpmsid id = 0;
165 if (ds != NULL && i >= 0 && i < ds->Count && ds->EVR != NULL)
166 id = ds->EVR[i];
167 return id;
168 }
rpmdsNIndex(rpmds ds,int i)169 const char * rpmdsNIndex(rpmds ds, int i)
170 {
171 const char * N = NULL;
172 if (ds != NULL && i >= 0 && i < ds->Count && ds->N != NULL)
173 N = rpmstrPoolStr(ds->pool, ds->N[i]);
174 return N;
175 }
176
rpmdsEVRIndex(rpmds ds,int i)177 const char * rpmdsEVRIndex(rpmds ds, int i)
178 {
179 const char * EVR = NULL;
180 if (ds != NULL && i >= 0 && i < ds->Count && ds->EVR != NULL)
181 EVR = rpmstrPoolStr(ds->pool, ds->EVR[i]);
182 return EVR;
183 }
184
rpmdsFlagsIndex(rpmds ds,int i)185 rpmsenseFlags rpmdsFlagsIndex(rpmds ds, int i)
186 {
187 rpmsenseFlags Flags = 0;
188 if (ds != NULL && i >= 0 && i < ds->Count && ds->Flags != NULL)
189 Flags = ds->Flags[i];
190 return Flags;
191 }
192
rpmdsTiIndex(rpmds ds,int i)193 int rpmdsTiIndex(rpmds ds, int i)
194 {
195 int ti = -1;
196 if (ds != NULL && i >= 0 && i < ds->Count && ds->ti != NULL)
197 ti = ds->ti[i];
198 return ti;
199 }
200
rpmdsColorIndex(rpmds ds,int i)201 rpm_color_t rpmdsColorIndex(rpmds ds, int i)
202 {
203 rpm_color_t Color = 0;
204 if (ds != NULL && i >= 0 && i < ds->Count && ds->Color != NULL)
205 Color = ds->Color[i];
206 return Color;
207 }
rpmdsUnlink(rpmds ds)208 static rpmds rpmdsUnlink(rpmds ds)
209 {
210 if (ds)
211 ds->nrefs--;
212 return NULL;
213 }
214
rpmdsLink(rpmds ds)215 rpmds rpmdsLink(rpmds ds)
216 {
217 if (ds)
218 ds->nrefs++;
219 return ds;
220 }
221
rpmdsFree(rpmds ds)222 rpmds rpmdsFree(rpmds ds)
223 {
224 rpmTagVal tagEVR, tagF, tagTi;
225
226 if (ds == NULL)
227 return NULL;
228
229 if (ds->nrefs > 1)
230 return rpmdsUnlink(ds);
231
232 if (dsType(ds->tagN, NULL, &tagEVR, &tagF, &tagTi))
233 return NULL;
234
235 if (ds->Count > 0) {
236 ds->N = _free(ds->N);
237 ds->EVR = _free(ds->EVR);
238 ds->Flags = _free(ds->Flags);
239 ds->ti = _free(ds->ti);
240 }
241
242 ds->pool = rpmstrPoolFree(ds->pool);
243 ds->DNEVR = _free(ds->DNEVR);
244 ds->Color = _free(ds->Color);
245
246 (void) rpmdsUnlink(ds);
247 memset(ds, 0, sizeof(*ds)); /* XXX trash and burn */
248 ds = _free(ds);
249 return NULL;
250 }
251
rpmdsCreate(rpmstrPool pool,rpmTagVal tagN,const char * Type,int Count,unsigned int instance)252 static rpmds rpmdsCreate(rpmstrPool pool,
253 rpmTagVal tagN, const char * Type, int Count,
254 unsigned int instance)
255 {
256 rpmds ds = xcalloc(1, sizeof(*ds));
257
258 ds->pool = (pool != NULL) ? rpmstrPoolLink(pool) : rpmstrPoolCreate();
259 ds->tagN = tagN;
260 ds->Type = Type;
261 ds->Count = Count;
262 ds->instance = instance;
263 ds->i = -1;
264
265 return rpmdsLink(ds);
266 }
267
rpmdsNewPool(rpmstrPool pool,Header h,rpmTagVal tagN,int flags)268 rpmds rpmdsNewPool(rpmstrPool pool, Header h, rpmTagVal tagN, int flags)
269 {
270 rpmTagVal tagEVR, tagF, tagTi;
271 rpmds ds = NULL;
272 const char * Type;
273 struct rpmtd_s names;
274 if (dsType(tagN, &Type, &tagEVR, &tagF, &tagTi))
275 goto exit;
276
277 if (headerGet(h, tagN, &names, HEADERGET_MINMEM)) {
278 struct rpmtd_s evr, dflags, tindices;
279 rpm_count_t count = rpmtdCount(&names);
280
281 headerGet(h, tagEVR, &evr, HEADERGET_MINMEM);
282 if (evr.count && evr.count != count) {
283 rpmtdFreeData(&evr);
284 return NULL;
285 }
286
287 headerGet(h, tagF, &dflags, HEADERGET_ALLOC);
288 if (dflags.count && dflags.count != count) {
289 rpmtdFreeData(&dflags);
290 return NULL;
291 }
292
293 if (tagTi != RPMTAG_NOT_FOUND) {
294 headerGet(h, tagTi, &tindices, HEADERGET_ALLOC);
295 if (tindices.count && tindices.count != count) {
296 rpmtdFreeData(&tindices);
297 return NULL;
298 }
299 }
300
301 ds = rpmdsCreate(pool, tagN, Type, count, headerGetInstance(h));
302
303 ds->N = names.count ? rpmtdToPool(&names, ds->pool) : NULL;
304 ds->EVR = evr.count ? rpmtdToPool(&evr, ds->pool): NULL;
305 ds->Flags = dflags.data;
306 if (tagTi != RPMTAG_NOT_FOUND) {
307 ds->ti = tindices.data;
308 }
309
310 /* ensure rpmlib() requires always have RPMSENSE_RPMLIB flag set */
311 if (tagN == RPMTAG_REQUIRENAME && ds->Flags) {
312 for (int i = 0; i < ds->Count; i++) {
313 if (!(rpmdsFlagsIndex(ds, i) & RPMSENSE_RPMLIB)) {
314 const char *N = rpmdsNIndex(ds, i);
315 if (rstreqn(N, "rpmlib(", sizeof("rpmlib(")-1))
316 ds->Flags[i] |= RPMSENSE_RPMLIB;
317 }
318 }
319 }
320 rpmtdFreeData(&names);
321 rpmtdFreeData(&evr);
322
323 /* freeze the pool to save memory, but only if private pool */
324 if (ds->pool != pool)
325 rpmstrPoolFreeze(ds->pool, 0);
326 }
327
328 exit:
329 return ds;
330 }
331
rpmdsNew(Header h,rpmTagVal tagN,int flags)332 rpmds rpmdsNew(Header h, rpmTagVal tagN, int flags)
333 {
334 return rpmdsNewPool(NULL, h, tagN, flags);
335 }
336
rpmdsNewDNEVR(const char * dspfx,const rpmds ds)337 char * rpmdsNewDNEVR(const char * dspfx, const rpmds ds)
338 {
339 const char * N = rpmdsN(ds);
340 const char * EVR = rpmdsEVR(ds);
341 rpmsenseFlags Flags = rpmdsFlags(ds);
342 char * tbuf, * t;
343 size_t nb;
344
345 nb = 0;
346 if (dspfx) nb += strlen(dspfx) + 1;
347 if (N) nb += strlen(N);
348 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
349 if (Flags & RPMSENSE_SENSEMASK) {
350 if (nb) nb++;
351 if (Flags & RPMSENSE_LESS) nb++;
352 if (Flags & RPMSENSE_GREATER) nb++;
353 if (Flags & RPMSENSE_EQUAL) nb++;
354 }
355 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
356 if (EVR && *EVR) {
357 if (nb) nb++;
358 nb += strlen(EVR);
359 }
360
361 t = tbuf = xmalloc(nb + 1);
362 if (dspfx) {
363 t = stpcpy(t, dspfx);
364 *t++ = ' ';
365 }
366 if (N)
367 t = stpcpy(t, N);
368 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
369 if (Flags & RPMSENSE_SENSEMASK) {
370 if (t != tbuf) *t++ = ' ';
371 if (Flags & RPMSENSE_LESS) *t++ = '<';
372 if (Flags & RPMSENSE_GREATER) *t++ = '>';
373 if (Flags & RPMSENSE_EQUAL) *t++ = '=';
374 }
375 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
376 if (EVR && *EVR) {
377 if (t != tbuf) *t++ = ' ';
378 t = stpcpy(t, EVR);
379 }
380 *t = '\0';
381 return tbuf;
382 }
383
singleDSPool(rpmstrPool pool,rpmTagVal tagN,rpmsid N,rpmsid EVR,rpmsenseFlags Flags,unsigned int instance,rpm_color_t Color,int triggerIndex)384 static rpmds singleDSPool(rpmstrPool pool, rpmTagVal tagN,
385 rpmsid N, rpmsid EVR, rpmsenseFlags Flags,
386 unsigned int instance, rpm_color_t Color,
387 int triggerIndex)
388 {
389 rpmds ds = NULL;
390 const char * Type;
391 rpmTagVal tagTi;
392
393 if (dsType(tagN, &Type, NULL, NULL, &tagTi))
394 goto exit;
395
396 ds = rpmdsCreate(pool, tagN, Type, 1, instance);
397
398 ds->N = xmalloc(1 * sizeof(*ds->N));
399 ds->N[0] = N;
400 ds->EVR = xmalloc(1 * sizeof(*ds->EVR));
401 ds->EVR[0] = EVR;
402 ds->Flags = xmalloc(sizeof(*ds->Flags));
403 ds->Flags[0] = Flags;
404 if (tagTi != RPMTAG_NOT_FOUND) {
405 ds->ti = xmalloc(sizeof(*ds->ti));
406 ds->ti[0] = triggerIndex;
407 }
408 ds->i = 0;
409 if (Color)
410 rpmdsSetColor(ds, Color);
411
412 exit:
413 return ds;
414 }
415
singleDS(rpmstrPool pool,rpmTagVal tagN,const char * N,const char * EVR,rpmsenseFlags Flags,unsigned int instance,rpm_color_t Color,int triggerIndex)416 static rpmds singleDS(rpmstrPool pool, rpmTagVal tagN,
417 const char * N, const char * EVR,
418 rpmsenseFlags Flags, unsigned int instance,
419 rpm_color_t Color, int triggerIndex)
420 {
421 rpmds ds = singleDSPool(pool, tagN, 0, 0, Flags, instance, Color,
422 triggerIndex);
423 if (ds) {
424 /* now that we have a pool, we can insert our N & EVR strings */
425 ds->N[0] = rpmstrPoolId(ds->pool, N ? N : "", 1);
426 ds->EVR[0] = rpmstrPoolId(ds->pool, EVR ? EVR : "", 1);
427 /* freeze the pool to save memory, but only if private pool */
428 if (ds->pool != pool)
429 rpmstrPoolFreeze(ds->pool, 0);
430 }
431 return ds;
432 }
433
rpmdsThisPool(rpmstrPool pool,Header h,rpmTagVal tagN,rpmsenseFlags Flags)434 rpmds rpmdsThisPool(rpmstrPool pool,
435 Header h, rpmTagVal tagN, rpmsenseFlags Flags)
436 {
437 char *evr = headerGetAsString(h, RPMTAG_EVR);
438 rpmds ds = singleDS(pool, tagN, headerGetString(h, RPMTAG_NAME),
439 evr, Flags, headerGetInstance(h), 0, 0);
440 free(evr);
441 return ds;
442 }
443
rpmdsThis(Header h,rpmTagVal tagN,rpmsenseFlags Flags)444 rpmds rpmdsThis(Header h, rpmTagVal tagN, rpmsenseFlags Flags)
445 {
446 return rpmdsThisPool(NULL, h, tagN, Flags);
447 }
448
rpmdsSinglePool(rpmstrPool pool,rpmTagVal tagN,const char * N,const char * EVR,rpmsenseFlags Flags)449 rpmds rpmdsSinglePool(rpmstrPool pool,rpmTagVal tagN,
450 const char * N, const char * EVR, rpmsenseFlags Flags)
451 {
452 return singleDS(pool, tagN, N, EVR, Flags, 0, 0, 0);
453 }
454
rpmdsSinglePoolTix(rpmstrPool pool,rpmTagVal tagN,const char * N,const char * EVR,rpmsenseFlags Flags,int triggerIndex)455 rpmds rpmdsSinglePoolTix(rpmstrPool pool,rpmTagVal tagN,
456 const char * N, const char * EVR,
457 rpmsenseFlags Flags, int triggerIndex)
458 {
459 return singleDS(pool, tagN, N, EVR, Flags, 0, 0, triggerIndex);
460 }
461
rpmdsSingle(rpmTagVal tagN,const char * N,const char * EVR,rpmsenseFlags Flags)462 rpmds rpmdsSingle(rpmTagVal tagN, const char * N, const char * EVR, rpmsenseFlags Flags)
463 {
464 return rpmdsSinglePool(NULL, tagN, N, EVR, Flags);
465 }
466
rpmdsCurrent(rpmds ds)467 rpmds rpmdsCurrent(rpmds ds)
468 {
469 rpmds cds = NULL;
470 int ti = -1;
471 if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
472 if (ds->ti)
473 ti = ds->ti[ds->i];
474 /* Using parent's pool so we can just use the same id's */
475 cds = singleDSPool(ds->pool, ds->tagN, ds->N[ds->i], ds->EVR[ds->i],
476 rpmdsFlags(ds), ds->instance, rpmdsColor(ds), ti);
477 }
478 return cds;
479 }
480
rpmdsFilterTi(rpmds ds,int ti)481 rpmds rpmdsFilterTi(rpmds ds, int ti)
482 {
483 int i, i2, tiCount = 0;
484 rpmds fds;
485
486 if (ds == NULL || !ds->ti || !ds->Count)
487 return NULL;
488
489 for (i = 0; i < ds->Count; i++) {
490 if (ds->ti[i] == ti)
491 tiCount++;
492 }
493
494 if (!tiCount)
495 return NULL;
496
497 fds = rpmdsCreate(ds->pool, ds->tagN, ds->Type, tiCount, ds->instance);
498
499 fds->N = xmalloc(tiCount * sizeof(*fds->N));
500 fds->EVR = xmalloc(tiCount * sizeof(*fds->EVR));
501 fds->Flags = xmalloc(tiCount * sizeof(*fds->Flags));
502 fds->ti = xmalloc(tiCount * sizeof(*fds->ti));
503 fds->i = -1;
504
505 i2 = 0;
506 for (i = 0; i < ds->Count; i++) {
507 if (ds->ti[i] == ti) {
508 fds->N[i2] = ds->N[i];
509 fds->EVR[i2] = ds->EVR[i];
510 fds->Flags[i2] = ds->Flags[i];
511 fds->ti[i2] = ds->ti[i];
512 i2++;
513 }
514 }
515
516 return fds;
517 }
518
rpmdsPutToHeader(rpmds ds,Header h)519 int rpmdsPutToHeader(rpmds ds, Header h)
520 {
521 rpmTagVal tagN = rpmdsTagN(ds);
522 rpmTagVal tagEVR = rpmdsTagEVR(ds);
523 rpmTagVal tagF = rpmdsTagF(ds);
524 rpmTagVal tagTi = rpmdsTagTi(ds);
525 if (!tagN)
526 return -1;
527
528 rpmds pi = rpmdsInit(ds);
529 while (rpmdsNext(pi) >= 0) {
530 rpmsenseFlags flags = rpmdsFlags(pi);
531 uint32_t index = rpmdsTi(pi);
532 headerPutString(h, tagN, rpmdsN(pi));
533 headerPutString(h, tagEVR, rpmdsEVR(pi));
534 headerPutUint32(h, tagF, &flags, 1);
535 if (tagTi != RPMTAG_NOT_FOUND) {
536 headerPutUint32(h, tagTi, &index, 1);
537 }
538 }
539 return 0;
540 }
541
rpmdsCount(const rpmds ds)542 int rpmdsCount(const rpmds ds)
543 {
544 return (ds != NULL ? ds->Count : 0);
545 }
546
rpmdsIx(const rpmds ds)547 int rpmdsIx(const rpmds ds)
548 {
549 return (ds != NULL ? ds->i : -1);
550 }
551
rpmdsSetIx(rpmds ds,int ix)552 int rpmdsSetIx(rpmds ds, int ix)
553 {
554 int i = -1;
555
556 if (ds != NULL) {
557 i = ds->i;
558 ds->i = ix;
559 ds->DNEVR = _free(ds->DNEVR);
560 }
561 return i;
562 }
563
rpmdsD(const rpmds ds)564 char rpmdsD(const rpmds ds)
565 {
566 if (ds != NULL) {
567 return tagNToChar(ds->tagN);
568 } else {
569 return '\0';
570 }
571 }
572
rpmdsDNEVR(const rpmds ds)573 const char * rpmdsDNEVR(const rpmds ds)
574 {
575 const char * DNEVR = NULL;
576
577 if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
578 if (ds->DNEVR == NULL) {
579 char t[2] = { tagNToChar(ds->tagN), '\0' };
580 ds->DNEVR = rpmdsNewDNEVR(t, ds);
581 }
582 DNEVR = ds->DNEVR;
583 }
584 return DNEVR;
585 }
586
rpmdsNId(rpmds ds)587 rpmsid rpmdsNId(rpmds ds)
588 {
589 return (ds != NULL) ? rpmdsNIdIndex(ds, ds->i) : 0;
590 }
591
rpmdsEVRId(rpmds ds)592 rpmsid rpmdsEVRId(rpmds ds)
593 {
594 return (ds != NULL) ? rpmdsEVRIdIndex(ds, ds->i) : 0;
595 }
596
rpmdsN(const rpmds ds)597 const char * rpmdsN(const rpmds ds)
598 {
599 return (ds != NULL) ? rpmdsNIndex(ds, ds->i) : NULL;
600 }
601
rpmdsEVR(const rpmds ds)602 const char * rpmdsEVR(const rpmds ds)
603 {
604 return (ds != NULL) ? rpmdsEVRIndex(ds, ds->i) : NULL;
605 }
606
rpmdsFlags(const rpmds ds)607 rpmsenseFlags rpmdsFlags(const rpmds ds)
608 {
609 return (ds != NULL) ? rpmdsFlagsIndex(ds, ds->i) : 0;
610 }
611
rpmdsTi(const rpmds ds)612 int rpmdsTi(const rpmds ds)
613 {
614 return (ds != NULL) ? rpmdsTiIndex(ds, ds->i) : 0;
615 }
616
rpmdsTagN(const rpmds ds)617 rpmTagVal rpmdsTagN(const rpmds ds)
618 {
619 rpmTagVal tagN = RPMTAG_NOT_FOUND;
620
621 if (ds != NULL)
622 tagN = ds->tagN;
623 return tagN;
624 }
625
rpmdsTagEVR(const rpmds ds)626 rpmTagVal rpmdsTagEVR(const rpmds ds)
627 {
628 rpmTagVal tagEVR = RPMTAG_NOT_FOUND;
629
630 if (ds != NULL)
631 dsType(ds->tagN, NULL, &tagEVR, NULL, NULL);
632 return tagEVR;
633 }
634
rpmdsTagF(const rpmds ds)635 rpmTagVal rpmdsTagF(const rpmds ds)
636 {
637 rpmTagVal tagF = RPMTAG_NOT_FOUND;
638
639 if (ds != NULL)
640 dsType(ds->tagN, NULL, NULL, &tagF, NULL);
641 return tagF;
642 }
643
rpmdsTagTi(const rpmds ds)644 rpmTagVal rpmdsTagTi(const rpmds ds)
645 {
646 rpmTagVal tagTi = RPMTAG_NOT_FOUND;
647
648 if (ds != NULL)
649 dsType(ds->tagN, NULL, NULL, NULL, &tagTi);
650 return tagTi;
651 }
652
rpmdsInstance(rpmds ds)653 unsigned int rpmdsInstance(rpmds ds)
654 {
655 return (ds != NULL) ? ds->instance : 0;
656 }
657
rpmdsNoPromote(const rpmds ds)658 int rpmdsNoPromote(const rpmds ds)
659 {
660 return 1;
661 }
662
rpmdsSetNoPromote(rpmds ds,int nopromote)663 int rpmdsSetNoPromote(rpmds ds, int nopromote)
664 {
665 return 1;
666 }
667
rpmdsColor(const rpmds ds)668 rpm_color_t rpmdsColor(const rpmds ds)
669 {
670 return (ds != NULL) ? rpmdsColorIndex(ds, ds->i) : 0;
671 }
672
rpmdsSetColor(const rpmds ds,rpm_color_t color)673 rpm_color_t rpmdsSetColor(const rpmds ds, rpm_color_t color)
674 {
675 rpm_color_t ocolor = 0;
676
677 if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
678 if (ds->Color == NULL) {
679 ds->Color = xcalloc(ds->Count, sizeof(*ds->Color));
680 }
681 ocolor = ds->Color[ds->i];
682 ds->Color[ds->i] = color;
683 }
684 return ocolor;
685 }
686
rpmdsNotify(rpmds ds,const char * where,int rc)687 void rpmdsNotify(rpmds ds, const char * where, int rc)
688 {
689 const char *DNEVR;
690
691 if (!rpmIsDebug())
692 return;
693 if (!(ds != NULL && ds->i >= 0 && ds->i < ds->Count))
694 return;
695 if (!(ds->Type != NULL && (DNEVR = rpmdsDNEVR(ds)) != NULL))
696 return;
697
698 rpmlog(RPMLOG_DEBUG, "%9s: %-45s %-s %s\n", ds->Type,
699 (rstreq(DNEVR, "cached") ? DNEVR : DNEVR+2),
700 (rc ? _("NO ") : _("YES")),
701 (where != NULL ? where : ""));
702 }
703
rpmdsNext(rpmds ds)704 int rpmdsNext(rpmds ds)
705 {
706 int i = -1;
707
708 if (ds != NULL && ++ds->i >= 0) {
709 if (ds->i < ds->Count) {
710 i = ds->i;
711 ds->DNEVR = _free(ds->DNEVR);
712 } else
713 ds->i = -1;
714
715 if (_rpmds_debug < 0 && i != -1)
716 fprintf(stderr, "*** ds %p\t%s[%d]: %s\n", ds, (ds->Type ? ds->Type : "?Type?"), i, (ds->DNEVR ? ds->DNEVR : "?DNEVR?"));
717
718 }
719
720 return i;
721 }
722
rpmdsInit(rpmds ds)723 rpmds rpmdsInit(rpmds ds)
724 {
725 if (ds != NULL) {
726 ds->i = -1;
727 ds->DNEVR = _free(ds->DNEVR);
728 }
729 return ds;
730 }
731
rpmdsDup(const rpmds ods)732 static rpmds rpmdsDup(const rpmds ods)
733 {
734 rpmds ds = rpmdsCreate(ods->pool, ods->tagN, ods->Type,
735 ods->Count, ods->instance);
736 size_t nb;
737
738 ds->i = ods->i;
739
740 nb = ds->Count * sizeof(*ds->N);
741 ds->N = memcpy(xmalloc(nb), ods->N, nb);
742
743 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
744 if (ods->EVR) {
745 nb = ds->Count * sizeof(*ds->EVR);
746 ds->EVR = memcpy(xmalloc(nb), ods->EVR, nb);
747 }
748
749 if (ods->Flags) {
750 nb = ds->Count * sizeof(*ds->Flags);
751 ds->Flags = memcpy(xmalloc(nb), ods->Flags, nb);
752 }
753
754 if (ods->ti) {
755 nb = ds->Count * sizeof(*ds->ti);
756 ds->ti = memcpy(xmalloc(nb), ods->ti, nb);
757 }
758
759 return ds;
760
761 }
762
doFind(rpmds ds,const rpmds ods,unsigned int * he)763 static int doFind(rpmds ds, const rpmds ods, unsigned int *he)
764 {
765 int comparison;
766 const char *N, *ON = rpmdsN(ods);
767 const char *EVR, *OEVR = rpmdsEVR(ods);
768 rpmsenseFlags Flags, OFlags = rpmdsFlags(ods);
769 int index, Oindex = rpmdsTi(ods);
770 int rc = -1; /* assume not found */
771
772 if (ds == NULL || ods == NULL)
773 return -1;
774
775 unsigned int l = 0;
776 unsigned int u = ds->Count;
777 while (l < u) {
778 ds->i = (l + u) / 2;
779
780 N = rpmdsN(ds);
781 EVR = rpmdsEVR(ds);
782 Flags = rpmdsFlags(ds);
783 index = rpmdsTi(ds);
784
785 comparison = strcmp(ON, N);
786
787 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
788 if (comparison == 0 && OEVR && EVR)
789 comparison = strcmp(OEVR, EVR);
790 if (comparison == 0)
791 comparison = OFlags - Flags;
792 if (comparison == 0)
793 comparison = Oindex - index;
794
795 if (comparison < 0)
796 u = ds->i;
797 else if (comparison > 0)
798 l = ds->i + 1;
799 else {
800 rc = ds->i;
801 break;
802 }
803 }
804 if (he)
805 *he = u;
806 return rc;
807 }
808
rpmdsFind(rpmds ds,const rpmds ods)809 int rpmdsFind(rpmds ds, const rpmds ods)
810 {
811 return doFind(ds, ods, NULL);
812 }
813
rpmdsMerge(rpmds * dsp,rpmds ods)814 int rpmdsMerge(rpmds * dsp, rpmds ods)
815 {
816 rpmds ds;
817 int save;
818 int ocount;
819
820 if (dsp == NULL || ods == NULL)
821 return -1;
822
823 ocount = rpmdsCount(*dsp);
824
825 /* If not initialized yet, dup the 1st entry. */
826 if (*dsp == NULL) {
827 save = ods->Count;
828 ods->Count = 1;
829 *dsp = rpmdsDup(ods);
830 ods->Count = save;
831 }
832 ds = *dsp;
833 if (ds == NULL)
834 return -1;
835
836 /* Ensure EVR and Flags exist */
837 if (ds->EVR == NULL)
838 ds->EVR = xcalloc(ds->Count, sizeof(*ds->EVR));
839 if (ds->Flags == NULL)
840 ds->Flags = xcalloc(ds->Count, sizeof(*ds->Flags));
841 if (ds->ti == NULL && ods->ti) {
842 int i;
843 ds->ti = xcalloc(ds->Count, sizeof(*ds->ti));
844 for (i = 0; i < ds->Count; i++)
845 ds->ti[i] = -1;
846 }
847
848 /*
849 * Add new entries.
850 */
851 save = ods->i;
852 ods = rpmdsInit(ods);
853 while (rpmdsNext(ods) >= 0) {
854 const char *OEVR;
855 unsigned int u;
856 /*
857 * If this entry is already present, don't bother.
858 */
859 if (doFind(ds, ods, &u) >= 0)
860 continue;
861
862 /*
863 * Insert new entry. Ensure pool is unfrozen to allow additions.
864 */
865 rpmstrPoolUnfreeze(ds->pool);
866 ds->N = xrealloc(ds->N, (ds->Count+1) * sizeof(*ds->N));
867 if (u < ds->Count) {
868 memmove(ds->N + u + 1, ds->N + u,
869 (ds->Count - u) * sizeof(*ds->N));
870 }
871 ds->N[u] = rpmstrPoolId(ds->pool, rpmdsN(ods), 1);
872
873 ds->EVR = xrealloc(ds->EVR, (ds->Count+1) * sizeof(*ds->EVR));
874 if (u < ds->Count) {
875 memmove(ds->EVR + u + 1, ds->EVR + u,
876 (ds->Count - u) * sizeof(*ds->EVR));
877 }
878 OEVR = rpmdsEVR(ods);
879 ds->EVR[u] = rpmstrPoolId(ds->pool, OEVR ? OEVR : "", 1);
880
881 ds->Flags = xrealloc(ds->Flags, (ds->Count+1) * sizeof(*ds->Flags));
882 if (u < ds->Count) {
883 memmove(ds->Flags + u + 1, ds->Flags + u,
884 (ds->Count - u) * sizeof(*ds->Flags));
885 }
886 ds->Flags[u] = rpmdsFlags(ods);
887
888 if (ds->ti || ods->ti) {
889 ds->ti = xrealloc(ds->ti, (ds->Count+1) * sizeof(*ds->ti));
890 if (u < ds->Count) {
891 memmove(ds->ti + u + 1, ds->ti + u,
892 (ds->Count - u) * sizeof(*ds->ti));
893 }
894 ds->ti[u] = rpmdsTi(ods);
895 }
896
897 ds->i = ds->Count;
898 ds->Count++;
899
900 }
901 ods->i = save;
902 return (ds->Count - ocount);
903 }
904
905
rpmdsSearch(rpmds ds,rpmds ods)906 int rpmdsSearch(rpmds ds, rpmds ods)
907 {
908 int comparison;
909 int i, l, u;
910 const char *ON = rpmdsN(ods);
911
912 if (ds == NULL || ods == NULL)
913 return -1;
914
915 /* Binary search to find the [l,u) subset that contains N */
916 i = -1;
917 l = 0;
918 u = ds->Count;
919 while (l < u) {
920 i = (l + u) / 2;
921
922 comparison = strcmp(ON, rpmdsNIndex(ds, i));
923
924 if (comparison < 0)
925 u = i;
926 else if (comparison > 0)
927 l = i + 1;
928 else {
929 /* Set l to 1st member of set that contains N. */
930 if (!rstreq(ON, rpmdsNIndex(ds, l)))
931 l = i;
932 while (l > 0 && rstreq(ON, rpmdsNIndex(ds, l-1)))
933 l--;
934 /* Set u to 1st member of set that does not contain N. */
935 if (u >= ds->Count || !rstreq(ON, rpmdsNIndex(ds, u)))
936 u = i;
937 while (++u < ds->Count) {
938 if (!rstreq(ON, rpmdsNIndex(ds, u)))
939 break;
940 }
941 break;
942 }
943 }
944
945 /* Check each member of [l,u) subset for ranges overlap. */
946 i = -1;
947 if (l < u) {
948 int save = rpmdsSetIx(ds, l-1);
949 while ((l = rpmdsNext(ds)) >= 0 && (l < u)) {
950 if ((i = rpmdsCompare(ods, ds)) != 0)
951 break;
952 }
953 /* Return element index that overlaps, or -1. */
954 if (i)
955 i = rpmdsIx(ds);
956 else {
957 (void) rpmdsSetIx(ds, save);
958 i = -1;
959 }
960 }
961 return i;
962 }
963
rpmdsCompareIndex(rpmds A,int aix,rpmds B,int bix)964 int rpmdsCompareIndex(rpmds A, int aix, rpmds B, int bix)
965 {
966 const char *AEVR, *BEVR;
967 rpmsenseFlags AFlags, BFlags;
968 int result;
969
970 /* Different names don't overlap. */
971 if (!rpmstrPoolStreq(A->pool, rpmdsNIdIndex(A, aix),
972 B->pool, rpmdsNIdIndex(B, bix))) {
973 result = 0;
974 goto exit;
975 }
976
977 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
978 if (!(A->EVR && A->Flags && B->EVR && B->Flags)) {
979 result = 1;
980 goto exit;
981 }
982
983 /* Same name. If either A or B is an existence test, always overlap. */
984 AFlags = rpmdsFlagsIndex(A, aix);
985 BFlags = rpmdsFlagsIndex(B, bix);
986 if (!((AFlags & RPMSENSE_SENSEMASK) && (BFlags & RPMSENSE_SENSEMASK))) {
987 result = 1;
988 goto exit;
989 }
990
991 AEVR = rpmdsEVRIndex(A, aix);
992 BEVR = rpmdsEVRIndex(B, bix);
993 if (!(AEVR && *AEVR && BEVR && *BEVR)) {
994 /* If either EVR is non-existent or empty, always overlap. */
995 result = 1;
996 } else {
997 /* Both AEVR and BEVR exist, compare [epoch:]version[-release]. */
998 rpmver av = rpmverParse(AEVR);
999 rpmver bv = rpmverParse(BEVR);
1000
1001 result = rpmverOverlap(av, AFlags, bv, BFlags);
1002
1003 rpmverFree(av);
1004 rpmverFree(bv);
1005 }
1006
1007 exit:
1008 return result;
1009 }
1010
rpmdsCompare(const rpmds A,const rpmds B)1011 int rpmdsCompare(const rpmds A, const rpmds B)
1012 {
1013 return rpmdsCompareIndex(A, A->i, B, B->i);
1014 }
1015
rpmdsMatches(rpmstrPool pool,Header h,int prix,rpmds req,int selfevr)1016 int rpmdsMatches(rpmstrPool pool, Header h, int prix,
1017 rpmds req, int selfevr)
1018 {
1019 rpmds provides;
1020 rpmTagVal tag = RPMTAG_PROVIDENAME;
1021 int result = 0;
1022
1023 /* Get provides information from header */
1024 if (selfevr)
1025 provides = rpmdsThisPool(pool, h, tag, RPMSENSE_EQUAL);
1026 else
1027 provides = rpmdsNewPool(pool, h, tag, 0);
1028
1029 /*
1030 * For a self-provide and indexed provide, we only need one comparison.
1031 * Otherwise loop through the provides until match or end.
1032 */
1033 if (prix >= 0 || selfevr) {
1034 if (prix >= 0)
1035 rpmdsSetIx(provides, prix);
1036 result = rpmdsCompare(provides, req);
1037 } else {
1038 provides = rpmdsInit(provides);
1039 while (rpmdsNext(provides) >= 0) {
1040 result = rpmdsCompare(provides, req);
1041 /* If this provide matches the require, we're done. */
1042 if (result)
1043 break;
1044 }
1045 }
1046
1047 rpmdsFree(provides);
1048 return result;
1049 }
1050
rpmdsMatchesDep(const Header h,int ix,const rpmds req,int nopromote)1051 int rpmdsMatchesDep (const Header h, int ix, const rpmds req, int nopromote)
1052 {
1053 return rpmdsMatches(NULL, h, ix, req, 0);
1054 }
1055
rpmdsAnyMatchesDep(const Header h,const rpmds req,int nopromote)1056 int rpmdsAnyMatchesDep (const Header h, const rpmds req, int nopromote)
1057 {
1058 return rpmdsMatches(NULL, h, -1, req, 0);
1059 }
1060
rpmdsNVRMatchesDep(const Header h,const rpmds req,int nopromote)1061 int rpmdsNVRMatchesDep(const Header h, const rpmds req, int nopromote)
1062 {
1063 return rpmdsMatches(NULL, h, -1, req, 1);
1064 }
1065
1066 /**
1067 */
1068 struct rpmlibProvides_s {
1069 const char * featureName;
1070 const char * featureEVR;
1071 rpmsenseFlags featureFlags;
1072 const char * featureDescription;
1073 };
1074
1075 static const struct rpmlibProvides_s rpmlibProvides[] = {
1076 { "rpmlib(VersionedDependencies)", "3.0.3-1",
1077 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1078 N_("PreReq:, Provides:, and Obsoletes: dependencies support versions.") },
1079 { "rpmlib(CompressedFileNames)", "3.0.4-1",
1080 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1081 N_("file name(s) stored as (dirName,baseName,dirIndex) tuple, not as path.")},
1082 #if HAVE_BZLIB_H
1083 { "rpmlib(PayloadIsBzip2)", "3.0.5-1",
1084 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1085 N_("package payload can be compressed using bzip2.") },
1086 #endif
1087 #if HAVE_LZMA_H
1088 { "rpmlib(PayloadIsXz)", "5.2-1",
1089 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1090 N_("package payload can be compressed using xz.") },
1091 { "rpmlib(PayloadIsLzma)", "4.4.2-1",
1092 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1093 N_("package payload can be compressed using lzma.") },
1094 #endif
1095 { "rpmlib(PayloadFilesHavePrefix)", "4.0-1",
1096 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1097 N_("package payload file(s) have \"./\" prefix.") },
1098 { "rpmlib(ExplicitPackageProvide)", "4.0-1",
1099 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1100 N_("package name-version-release is not implicitly provided.") },
1101 { "rpmlib(HeaderLoadSortsTags)", "4.0.1-1",
1102 ( RPMSENSE_EQUAL),
1103 N_("header tags are always sorted after being loaded.") },
1104 { "rpmlib(ScriptletInterpreterArgs)", "4.0.3-1",
1105 ( RPMSENSE_EQUAL),
1106 N_("the scriptlet interpreter can use arguments from header.") },
1107 { "rpmlib(PartialHardlinkSets)", "4.0.4-1",
1108 ( RPMSENSE_EQUAL),
1109 N_("a hardlink file set may be installed without being complete.") },
1110 { "rpmlib(ConcurrentAccess)", "4.1-1",
1111 ( RPMSENSE_EQUAL),
1112 N_("package scriptlets may access the rpm database while installing.") },
1113 #ifdef WITH_LUA
1114 { "rpmlib(BuiltinLuaScripts)", "4.2.2-1",
1115 ( RPMSENSE_EQUAL),
1116 N_("internal support for lua scripts.") },
1117 #endif
1118 { "rpmlib(FileDigests)", "4.6.0-1",
1119 ( RPMSENSE_EQUAL),
1120 N_("file digest algorithm is per package configurable") },
1121 #ifdef WITH_CAP
1122 { "rpmlib(FileCaps)", "4.6.1-1",
1123 ( RPMSENSE_EQUAL),
1124 N_("support for POSIX.1e file capabilities") },
1125 #endif
1126 { "rpmlib(ScriptletExpansion)", "4.9.0-1",
1127 ( RPMSENSE_EQUAL),
1128 N_("package scriptlets can be expanded at install time.") },
1129 { "rpmlib(TildeInVersions)", "4.10.0-1",
1130 ( RPMSENSE_EQUAL),
1131 N_("dependency comparison supports versions with tilde.") },
1132 { "rpmlib(CaretInVersions)", "4.15.0-1",
1133 ( RPMSENSE_EQUAL),
1134 N_("dependency comparison supports versions with caret.") },
1135 { "rpmlib(LargeFiles)", "4.12.0-1",
1136 ( RPMSENSE_EQUAL),
1137 N_("support files larger than 4GB") },
1138 { "rpmlib(RichDependencies)", "4.12.0-1",
1139 ( RPMSENSE_EQUAL),
1140 N_("support for rich dependencies.") },
1141 { "rpmlib(DynamicBuildRequires)", "4.15.0-1",
1142 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1143 N_("support for dynamic buildrequires.") },
1144 #ifdef HAVE_ZSTD
1145 { "rpmlib(PayloadIsZstd)", "5.4.18-1",
1146 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1147 N_("package payload can be compressed using zstd.") },
1148 #endif
1149 { NULL, NULL, 0, NULL }
1150 };
1151
1152
rpmdsRpmlibPool(rpmstrPool pool,rpmds * dsp,const void * tblp)1153 int rpmdsRpmlibPool(rpmstrPool pool, rpmds * dsp, const void * tblp)
1154 {
1155 const struct rpmlibProvides_s * rltblp = tblp;
1156 const struct rpmlibProvides_s * rlp;
1157 int rc = 0;
1158
1159 if (rltblp == NULL)
1160 rltblp = rpmlibProvides;
1161
1162 for (rlp = rltblp; rlp->featureName != NULL && rc >= 0; rlp++) {
1163 rpmds ds = rpmdsSinglePool(pool, RPMTAG_PROVIDENAME, rlp->featureName,
1164 rlp->featureEVR, rlp->featureFlags);
1165 rc = rpmdsMerge(dsp, ds);
1166 rpmdsFree(ds);
1167 }
1168 /* freeze the pool to save memory, but only if private pool */
1169 if (*dsp && (*dsp)->pool != pool)
1170 rpmstrPoolFreeze((*dsp)->pool, 0);
1171 return (rc < 0) ? -1 : 0;
1172 }
1173
rpmdsRpmlib(rpmds * dsp,const void * tblp)1174 int rpmdsRpmlib(rpmds * dsp, const void * tblp)
1175 {
1176 return rpmdsRpmlibPool(NULL, dsp, tblp);
1177 }
1178
rpmdsPool(rpmds ds)1179 rpmstrPool rpmdsPool(rpmds ds)
1180 {
1181 return (ds != NULL) ? ds->pool : NULL;
1182 }
1183
rpmdsIsWeak(rpmds ds)1184 int rpmdsIsWeak(rpmds ds)
1185 {
1186 int weak = 1;
1187 switch (rpmdsTagN(ds)) {
1188 case RPMTAG_REQUIRENAME:
1189 case RPMTAG_PROVIDENAME:
1190 case RPMTAG_OBSOLETENAME:
1191 case RPMTAG_CONFLICTNAME:
1192 if (!(rpmdsFlags(ds) & RPMSENSE_MISSINGOK))
1193 weak = 0;
1194 break;
1195 }
1196 return weak;
1197 }
1198
rpmdsIsReverse(rpmds ds)1199 int rpmdsIsReverse(rpmds ds)
1200 {
1201 int reverse = 0;
1202 switch (rpmdsTagN(ds)) {
1203 case RPMTAG_SUPPLEMENTNAME:
1204 case RPMTAG_ENHANCENAME:
1205 reverse = 1;
1206 break;
1207 }
1208 return reverse;
1209 }
1210
rpmSanitizeDSFlags(rpmTagVal tagN,rpmsenseFlags Flags)1211 rpmsenseFlags rpmSanitizeDSFlags(rpmTagVal tagN, rpmsenseFlags Flags)
1212 {
1213 rpmsenseFlags extra = RPMSENSE_ANY;
1214 switch (tagN) {
1215 case RPMTAG_PROVIDENAME:
1216 extra = Flags & RPMSENSE_FIND_PROVIDES;
1217 break;
1218 case RPMTAG_TRIGGERNAME:
1219 case RPMTAG_FILETRIGGERNAME:
1220 case RPMTAG_TRANSFILETRIGGERNAME:
1221 extra = Flags & RPMSENSE_TRIGGER;
1222 break;
1223 case RPMTAG_RECOMMENDNAME:
1224 case RPMTAG_SUGGESTNAME:
1225 case RPMTAG_SUPPLEMENTNAME:
1226 case RPMTAG_ENHANCENAME:
1227 case RPMTAG_REQUIRENAME:
1228 extra = Flags & (_ALL_REQUIRES_MASK);
1229 break;
1230 case RPMTAG_CONFLICTNAME:
1231 extra = Flags;
1232 break;
1233 default:
1234 break;
1235 }
1236 return (Flags & RPMSENSE_SENSEMASK) | extra;
1237 }
1238
1239 static struct ReqComp {
1240 const char * token;
1241 rpmsenseFlags sense;
1242 } const ReqComparisons[] = {
1243 { "<=", RPMSENSE_LESS | RPMSENSE_EQUAL},
1244 { "=<", RPMSENSE_LESS | RPMSENSE_EQUAL},
1245 { "<", RPMSENSE_LESS},
1246
1247 { "==", RPMSENSE_EQUAL},
1248 { "=", RPMSENSE_EQUAL},
1249
1250 { ">=", RPMSENSE_GREATER | RPMSENSE_EQUAL},
1251 { "=>", RPMSENSE_GREATER | RPMSENSE_EQUAL},
1252 { ">", RPMSENSE_GREATER},
1253
1254 { NULL, 0 },
1255 };
1256
rpmParseDSFlags(const char * str,size_t len)1257 rpmsenseFlags rpmParseDSFlags(const char *str, size_t len)
1258 {
1259 const struct ReqComp *rc;
1260 for (rc = ReqComparisons; rc->token != NULL; rc++)
1261 if (len == strlen(rc->token) && rstreqn(str, rc->token, len))
1262 return rc->sense;
1263 return 0;
1264 }
1265
1266 static struct RichOpComp {
1267 const char * token;
1268 rpmrichOp op;
1269 } const RichOps[] = {
1270 { "and", RPMRICHOP_AND},
1271 { "or", RPMRICHOP_OR},
1272 { "if", RPMRICHOP_IF},
1273 { "unless", RPMRICHOP_UNLESS},
1274 { "else", RPMRICHOP_ELSE},
1275 { "with", RPMRICHOP_WITH},
1276 { "without", RPMRICHOP_WITHOUT},
1277 { NULL, 0 },
1278 };
1279
rpmdsIsRich(rpmds dep)1280 int rpmdsIsRich(rpmds dep)
1281 {
1282 const char * n = rpmdsN(dep);
1283 return (n && n[0] == '(');
1284 }
1285
parseRichDepOp(const char ** dstrp,rpmrichOp * opp,char ** emsg)1286 static rpmRC parseRichDepOp(const char **dstrp, rpmrichOp *opp, char **emsg)
1287 {
1288 const char *p = *dstrp, *pe = p;
1289 const struct RichOpComp *ro;
1290
1291 while (*pe && !risspace(*pe) && *pe != ')')
1292 pe++;
1293 for (ro = RichOps; ro->token != NULL; ro++)
1294 if (pe - p == strlen(ro->token) && rstreqn(p, ro->token, pe - p)) {
1295 *opp = ro->op;
1296 *dstrp = pe;
1297 return RPMRC_OK;
1298 }
1299 if (emsg)
1300 rasprintf(emsg, _("Unknown rich dependency op '%.*s'"), (int)(pe - p), p);
1301 return RPMRC_FAIL;
1302 }
1303
rpmrichOpStr(rpmrichOp op)1304 const char *rpmrichOpStr(rpmrichOp op)
1305 {
1306 if (op == RPMRICHOP_SINGLE)
1307 return "SINGLE";
1308 if (op == RPMRICHOP_AND)
1309 return "and";
1310 if (op == RPMRICHOP_OR)
1311 return "or";
1312 if (op == RPMRICHOP_IF)
1313 return "if";
1314 if (op == RPMRICHOP_UNLESS)
1315 return "unless";
1316 if (op == RPMRICHOP_ELSE)
1317 return "else";
1318 if (op == RPMRICHOP_WITH)
1319 return "with";
1320 if (op == RPMRICHOP_WITHOUT)
1321 return "without";
1322 return NULL;
1323 }
1324
1325
1326 #define SKIPWHITE(_x) {while (*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
1327 #define SKIPNONWHITEX(_x){int bl = 0; while (*(_x) &&!(risspace(*_x) || *(_x) == ',' || (*(_x) == ')' && bl-- <= 0))) if (*(_x)++ == '(') bl++;}
1328
parseSimpleDep(const char ** dstrp,char ** emsg,rpmrichParseFunction cb,void * cbdata)1329 static rpmRC parseSimpleDep(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata)
1330 {
1331 const char *p = *dstrp;
1332 const char *n, *e = 0;
1333 int nl, el = 0;
1334 rpmsenseFlags sense = 0;
1335
1336 n = p;
1337 SKIPNONWHITEX(p);
1338 nl = p - n;
1339 if (nl == 0) {
1340 if (emsg)
1341 rasprintf(emsg, _("Name required"));
1342 return RPMRC_FAIL;
1343 }
1344 SKIPWHITE(p);
1345 if (*p) {
1346 const char *pe = p;
1347
1348 SKIPNONWHITEX(pe);
1349 sense = rpmParseDSFlags(p, pe - p);
1350 if (sense) {
1351 p = pe;
1352 SKIPWHITE(p);
1353 e = p;
1354 SKIPNONWHITEX(p);
1355 el = p - e;
1356 }
1357 }
1358 if (e && el == 0) {
1359 if (emsg)
1360 rasprintf(emsg, _("Version required"));
1361 return RPMRC_FAIL;
1362 }
1363 if (cb && cb(cbdata, RPMRICH_PARSE_SIMPLE, n, nl, e, el, sense, RPMRICHOP_SINGLE, emsg) != RPMRC_OK)
1364 return RPMRC_FAIL;
1365 *dstrp = p;
1366 return RPMRC_OK;
1367 }
1368
1369 #define RICHPARSE_CHECK (1 << 0)
1370 #define RICHPARSE_NO_WITH (1 << 1)
1371 #define RICHPARSE_NO_AND (1 << 2)
1372 #define RICHPARSE_NO_OR (1 << 3)
1373
rpmrichParseCheck(rpmrichOp op,int check,char ** emsg)1374 static rpmRC rpmrichParseCheck(rpmrichOp op, int check, char **emsg)
1375 {
1376 if ((op == RPMRICHOP_WITH || op == RPMRICHOP_WITHOUT) && (check & RICHPARSE_NO_WITH) != 0) {
1377 if (emsg)
1378 rasprintf(emsg, _("Illegal ops in with/without"));
1379 return RPMRC_FAIL;
1380 }
1381 if ((check & RICHPARSE_CHECK) == 0)
1382 return RPMRC_OK;
1383 if ((op == RPMRICHOP_AND || op == RPMRICHOP_IF) && (check & RICHPARSE_NO_AND) != 0) {
1384 if (emsg)
1385 rasprintf(emsg, _("Illegal context for 'unless', please use 'or' instead"));
1386 return RPMRC_FAIL;
1387 }
1388 if ((op == RPMRICHOP_OR || op == RPMRICHOP_UNLESS) && (check & RICHPARSE_NO_OR) != 0) {
1389 if (emsg)
1390 rasprintf(emsg, _("Illegal context for 'if', please use 'and' instead"));
1391 return RPMRC_FAIL;
1392 }
1393 return RPMRC_OK;
1394 }
1395
rpmrichParseInternal(const char ** dstrp,char ** emsg,rpmrichParseFunction cb,void * cbdata,int * checkp)1396 static rpmRC rpmrichParseInternal(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata, int *checkp)
1397 {
1398 const char *p = *dstrp, *pe;
1399 rpmrichOp op = RPMRICHOP_SINGLE, firstop = RPMRICHOP_SINGLE, chainop = 0;
1400 int check = checkp ? *checkp : 0;
1401
1402 if (cb && cb(cbdata, RPMRICH_PARSE_ENTER, p, 0, 0, 0, 0, op, emsg) != RPMRC_OK)
1403 return RPMRC_FAIL;
1404 if (*p++ != '(') {
1405 if (emsg)
1406 rasprintf(emsg, _("Rich dependency does not start with '('"));
1407 return RPMRC_FAIL;
1408 }
1409 for (;;) {
1410 SKIPWHITE(p);
1411 if (*p == ')') {
1412 if (emsg) {
1413 if (chainop)
1414 rasprintf(emsg, _("Missing argument to rich dependency op"));
1415 else
1416 rasprintf(emsg, _("Empty rich dependency"));
1417 }
1418 return RPMRC_FAIL;
1419 }
1420 if (*p == '(') {
1421 int subcheck = check & RICHPARSE_CHECK;
1422 if (rpmrichParseInternal(&p, emsg, cb, cbdata, &subcheck) != RPMRC_OK)
1423 return RPMRC_FAIL;
1424 if (op == RPMRICHOP_IF || op == RPMRICHOP_UNLESS)
1425 subcheck &= ~(RICHPARSE_NO_AND | RICHPARSE_NO_OR);
1426 check |= subcheck;
1427 } else {
1428 if (parseSimpleDep(&p, emsg, cb, cbdata) != RPMRC_OK)
1429 return RPMRC_FAIL;
1430 }
1431 SKIPWHITE(p);
1432 if (!*p) {
1433 if (emsg)
1434 rasprintf(emsg, _("Unterminated rich dependency: %s"), *dstrp);
1435 return RPMRC_FAIL;
1436 }
1437 if (*p == ')')
1438 break;
1439 pe = p;
1440 if (parseRichDepOp(&pe, &op, emsg) != RPMRC_OK)
1441 return RPMRC_FAIL;
1442 if (firstop == RPMRICHOP_SINGLE)
1443 firstop = op;
1444
1445 if (op == RPMRICHOP_ELSE && (chainop == RPMRICHOP_IF || chainop == RPMRICHOP_UNLESS))
1446 chainop = 0;
1447 if (chainop && op != chainop) {
1448 if (emsg)
1449 rasprintf(emsg, _("Cannot chain different ops"));
1450 return RPMRC_FAIL;
1451 }
1452 if (chainop && op != RPMRICHOP_AND && op != RPMRICHOP_OR && op != RPMRICHOP_WITH) {
1453 if (emsg)
1454 rasprintf(emsg, _("Can only chain and/or/with ops"));
1455 return RPMRC_FAIL;
1456 }
1457 if (cb && cb(cbdata, RPMRICH_PARSE_OP, p, pe - p, 0, 0, 0, op, emsg) != RPMRC_OK)
1458 return RPMRC_FAIL;
1459 chainop = op;
1460 p = pe;
1461 }
1462
1463 /* check for illegal combinations */
1464 if (rpmrichParseCheck(firstop, check, emsg) != RPMRC_OK)
1465 return RPMRC_FAIL;
1466
1467 /* update check data */
1468 if (firstop == RPMRICHOP_IF)
1469 check |= RICHPARSE_NO_OR;
1470 if (firstop == RPMRICHOP_UNLESS)
1471 check |= RICHPARSE_NO_AND;
1472 if (op == RPMRICHOP_AND || op == RPMRICHOP_OR)
1473 check &= ~(RICHPARSE_NO_AND | RICHPARSE_NO_OR);
1474 if (op != RPMRICHOP_SINGLE && op != RPMRICHOP_WITH && op != RPMRICHOP_WITHOUT && op != RPMRICHOP_OR)
1475 check |= RICHPARSE_NO_WITH;
1476
1477 p++;
1478 if (cb && cb(cbdata, RPMRICH_PARSE_LEAVE, *dstrp, p - *dstrp , 0, 0, 0, op, emsg) != RPMRC_OK)
1479 return RPMRC_FAIL;
1480 *dstrp = p;
1481 if (checkp)
1482 *checkp |= check;
1483 return RPMRC_OK;
1484 }
1485
rpmrichParse(const char ** dstrp,char ** emsg,rpmrichParseFunction cb,void * cbdata)1486 rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata)
1487 {
1488 return rpmrichParseInternal(dstrp, emsg, cb, cbdata, NULL);
1489 }
1490
rpmrichParseForTag(const char ** dstrp,char ** emsg,rpmrichParseFunction cb,void * cbdata,rpmTagVal tagN)1491 rpmRC rpmrichParseForTag(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata, rpmTagVal tagN)
1492 {
1493 int check = RICHPARSE_CHECK;
1494 if (rpmrichParseInternal(dstrp, emsg, cb, cbdata, &check) != RPMRC_OK)
1495 return RPMRC_FAIL;
1496 switch (tagN) {
1497 case RPMTAG_CONFLICTNAME:
1498 case RPMTAG_SUPPLEMENTNAME:
1499 case RPMTAG_ENHANCENAME:
1500 if (rpmrichParseCheck(RPMRICHOP_OR, check, emsg) != RPMRC_OK)
1501 return RPMRC_FAIL;
1502 break;
1503 default:
1504 if (rpmrichParseCheck(RPMRICHOP_AND, check, emsg) != RPMRC_OK)
1505 return RPMRC_FAIL;
1506 break;
1507 }
1508 return RPMRC_OK;
1509 }
1510
1511 struct rpmdsParseRichDepData {
1512 rpmds dep;
1513 rpmsenseFlags depflags;
1514
1515 rpmds leftds;
1516 rpmds rightds;
1517 rpmrichOp op;
1518
1519 int depth;
1520 const char *rightstart;
1521 int dochain;
1522 };
1523
rpmdsParseRichDepCB(void * cbdata,rpmrichParseType type,const char * n,int nl,const char * e,int el,rpmsenseFlags sense,rpmrichOp op,char ** emsg)1524 static rpmRC rpmdsParseRichDepCB(void *cbdata, rpmrichParseType type,
1525 const char *n, int nl, const char *e, int el, rpmsenseFlags sense,
1526 rpmrichOp op, char **emsg) {
1527 struct rpmdsParseRichDepData *data = cbdata;
1528 rpmds ds = 0;
1529
1530 if (type == RPMRICH_PARSE_ENTER)
1531 data->depth++;
1532 else if (type == RPMRICH_PARSE_LEAVE) {
1533 if (--data->depth == 0 && data->dochain && data->rightstart) {
1534 /* chain op hack, construct a sub-ds from the right side of the chain */
1535 char *right = xmalloc(n + nl - data->rightstart + 2);
1536 right[0] = '(';
1537 strncpy(right + 1, data->rightstart, n + nl - data->rightstart);
1538 right[n + nl - data->rightstart + 1] = 0;
1539 data->rightds = rpmdsFree(data->rightds);
1540 ds = singleDS(data->dep->pool, data->dep->tagN, 0, 0, data->depflags, 0, 0, 0);
1541 ds->N[0] = rpmstrPoolId(ds->pool, right, 1);
1542 ds->EVR[0] = rpmstrPoolId(ds->pool, "", 1);
1543 data->rightds = ds;
1544 free(right);
1545 }
1546 }
1547 if (data->depth != 1)
1548 return RPMRC_OK; /* we're only interested in top-level parsing */
1549 if ((type == RPMRICH_PARSE_SIMPLE || type == RPMRICH_PARSE_LEAVE) && !data->dochain) {
1550 if (type == RPMRICH_PARSE_SIMPLE && data->dep->tagN == RPMTAG_REQUIRENAME && nl > 7 &&
1551 rstreqn(n, "rpmlib(", sizeof("rpmlib(")-1))
1552 sense |= RPMSENSE_RPMLIB;
1553 ds = singleDS(data->dep->pool, data->dep->tagN, 0, 0, sense | data->depflags, 0, 0, 0);
1554 ds->N[0] = rpmstrPoolIdn(ds->pool, n, nl, 1);
1555 ds->EVR[0] = rpmstrPoolIdn(ds->pool, e ? e : "", el, 1);
1556 if (!data->leftds)
1557 data->leftds = ds;
1558 else {
1559 data->rightds = ds;
1560 data->rightstart = n;
1561 }
1562 }
1563 if (type == RPMRICH_PARSE_OP) {
1564 if (data->op != RPMRICHOP_SINGLE)
1565 data->dochain = 1; /* this is a chained op */
1566 else
1567 data->op = op;
1568 }
1569 return RPMRC_OK;
1570 }
1571
1572
rpmdsParseRichDep(rpmds dep,rpmds * leftds,rpmds * rightds,rpmrichOp * op,char ** emsg)1573 rpmRC rpmdsParseRichDep(rpmds dep, rpmds *leftds, rpmds *rightds, rpmrichOp *op, char **emsg)
1574 {
1575 rpmRC rc;
1576 struct rpmdsParseRichDepData data;
1577 const char *depstr = rpmdsN(dep);
1578 memset(&data, 0, sizeof(data));
1579 data.dep = dep;
1580 data.op = RPMRICHOP_SINGLE;
1581 data.depflags = rpmdsFlags(dep) & ~(RPMSENSE_SENSEMASK | RPMSENSE_MISSINGOK);
1582 rc = rpmrichParse(&depstr, emsg, rpmdsParseRichDepCB, &data);
1583 if (rc == RPMRC_OK && *depstr) {
1584 if (emsg)
1585 rasprintf(emsg, _("Junk after rich dependency"));
1586 rc = RPMRC_FAIL;
1587 }
1588 if (rc != RPMRC_OK) {
1589 rpmdsFree(data.leftds);
1590 rpmdsFree(data.rightds);
1591 } else {
1592 *leftds = data.leftds;
1593 *rightds = data.rightds;
1594 *op = data.op;
1595 }
1596 return rc;
1597 }
1598
1599