1 /*
2 * Copyright (c) 2012, Novell Inc.
3 *
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
6 */
7
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <errno.h>
15
16 #include "pool.h"
17 #include "repo.h"
18 #include "util.h"
19 #include "chksum.h"
20 #include "solver.h"
21 #include "repo_cudf.h"
22
23 static Id
parseonedep(Pool * pool,char * p)24 parseonedep(Pool *pool, char *p)
25 {
26 char *n, *ne, *e, *ee;
27 Id name, evr;
28 int flags;
29
30 while (*p == ' ' || *p == '\t' || *p == '\n')
31 p++;
32 if (!*p)
33 return 0;
34 if (!strcmp(p, "!true"))
35 return 0;
36 if (!strcmp(p, "!false"))
37 return pool_str2id(pool, p, 1);
38 n = p;
39 /* find end of name */
40 while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '|')
41 p++;
42 ne = p;
43 while (*p == ' ' || *p == '\t' || *p == '\n')
44 p++;
45 evr = 0;
46 flags = 0;
47 e = ee = 0;
48 if (*p == '>' || *p == '<' || *p == '=' || *p == '!')
49 {
50 if (*p == '>')
51 flags |= REL_GT;
52 else if (*p == '=')
53 flags |= REL_EQ;
54 else if (*p == '<')
55 flags |= REL_LT;
56 else if (*p == '!')
57 flags |= REL_LT | REL_GT | REL_EQ;
58 p++;
59 if (flags && *p == '=')
60 {
61 if (p[-1] != '=')
62 flags ^= REL_EQ;
63 p++;
64 }
65 while (*p == ' ' || *p == '\t' || *p == '\n')
66 p++;
67 e = p;
68 while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '|')
69 p++;
70 ee = p;
71 while (*p == ' ' || *p == '\t' || *p == '\n')
72 p++;
73 }
74 name = pool_strn2id(pool, n, ne - n, 1);
75 if (e)
76 {
77 evr = pool_strn2id(pool, e, ee - e, 1);
78 name = pool_rel2id(pool, name, evr, flags, 1);
79 }
80 if (*p == '|')
81 {
82 Id id = parseonedep(pool, p + 1);
83 if (id)
84 name = pool_rel2id(pool, name, id, REL_OR, 1);
85 }
86 return name;
87 }
88 static unsigned int
makedeps(Repo * repo,char * deps,unsigned int olddeps,Id marker)89 makedeps(Repo *repo, char *deps, unsigned int olddeps, Id marker)
90 {
91 Pool *pool = repo->pool;
92 char *p;
93 Id id;
94
95 while ((p = strchr(deps, ',')) != 0)
96 {
97 *p = 0;
98 olddeps = makedeps(repo, deps, olddeps, marker);
99 *p = ',';
100 deps = p + 1;
101 }
102 id = parseonedep(pool, deps);
103 if (!id)
104 return olddeps;
105 return repo_addid_dep(repo, olddeps, id, marker);
106 }
107
108 static Offset
copydeps(Pool * pool,Repo * repo,Offset fromoff,Repo * fromrepo)109 copydeps(Pool *pool, Repo *repo, Offset fromoff, Repo *fromrepo)
110 {
111 Id *ida, *from;
112 int cc;
113 Offset off;
114
115 if (!fromoff)
116 return 0;
117 from = fromrepo->idarraydata + fromoff;
118 for (ida = from, cc = 0; *ida; ida++, cc++)
119 ;
120 if (cc == 0)
121 return 0;
122 off = repo_reserve_ids(repo, 0, cc);
123 memcpy(repo->idarraydata + off, from, (cc + 1) * sizeof(Id));
124 repo->idarraysize += cc + 1;
125 return off;
126 }
127
128 static void
copysolvabledata(Pool * pool,Solvable * s,Repo * repo)129 copysolvabledata(Pool *pool, Solvable *s, Repo *repo)
130 {
131 Repo *srepo = s->repo;
132 if (srepo == repo)
133 return;
134 s->provides = copydeps(pool, repo, s->provides, srepo);
135 s->requires = copydeps(pool, repo, s->requires, srepo);
136 s->conflicts = copydeps(pool, repo, s->conflicts, srepo);
137 s->obsoletes = copydeps(pool, repo, s->obsoletes, srepo);
138 s->recommends = copydeps(pool, repo, s->recommends, srepo);
139 s->suggests = copydeps(pool, repo, s->suggests, srepo);
140 s->supplements = copydeps(pool, repo, s->supplements, srepo);
141 s->enhances = copydeps(pool, repo, s->enhances, srepo);
142 }
143
144 #define KEEP_VERSION 1
145 #define KEEP_PACKAGE 2
146 #define KEEP_FEATURE 3
147
148 static void
finishpackage(Pool * pool,Solvable * s,int keep,Queue * job)149 finishpackage(Pool *pool, Solvable *s, int keep, Queue *job)
150 {
151 Id *idp, id, sid;
152 if (!s)
153 return;
154 if (!s->arch)
155 s->arch = ARCH_ANY;
156 if (!s->evr)
157 s->evr = ID_EMPTY;
158 sid = pool_rel2id(pool, s->name, s->evr, REL_EQ, 1);
159 s->provides = repo_addid_dep(s->repo, s->provides, sid, 0);
160 if (!job || !pool->installed || s->repo != pool->installed)
161 return;
162 if (keep == KEEP_VERSION)
163 queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, sid);
164 else if (keep == KEEP_PACKAGE)
165 queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, s->name);
166 else if (keep == KEEP_FEATURE)
167 {
168 for (idp = s->repo->idarraydata + s->provides; (id = *idp) != 0; idp++)
169 {
170 if (id != sid) /* skip self-provides */
171 queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, id);
172 }
173 }
174 }
175
176 int
repo_add_cudf(Repo * repo,Repo * installedrepo,FILE * fp,Queue * job,int flags)177 repo_add_cudf(Repo *repo, Repo *installedrepo, FILE *fp, Queue *job, int flags)
178 {
179 Pool *pool;
180 char *buf, *p;
181 int bufa, bufl, c;
182 Solvable *s;
183 int instanza = 0;
184 int inrequest = 0;
185 int isinstalled = 0;
186 int keep = 0;
187 Repo *xrepo;
188
189 xrepo = repo ? repo : installedrepo;
190 if (!xrepo)
191 return -1;
192 pool = xrepo->pool;
193
194 buf = solv_malloc(4096);
195 bufa = 4096;
196 bufl = 0;
197 s = 0;
198
199 while (fgets(buf + bufl, bufa - bufl, fp) > 0)
200 {
201 bufl += strlen(buf + bufl);
202 if (bufl && buf[bufl - 1] != '\n')
203 {
204 if (bufa - bufl < 256)
205 {
206 bufa += 4096;
207 buf = solv_realloc(buf, bufa);
208 }
209 continue;
210 }
211 buf[--bufl] = 0;
212 c = getc(fp);
213 if (c == ' ' || c == '\t')
214 {
215 /* continuation line */
216 buf[bufl++] = ' ';
217 continue;
218 }
219 if (c != EOF)
220 ungetc(c, fp);
221 bufl = 0;
222 if (*buf == '#')
223 continue;
224 if (!*buf)
225 {
226 if (s && !repo && !isinstalled)
227 s = solvable_free(s, 1);
228 if (s)
229 finishpackage(pool, s, keep, job);
230 s = 0;
231 keep = 0;
232 instanza = 0;
233 inrequest = 0;
234 continue;
235 }
236 p = strchr(buf, ':');
237 if (!p)
238 continue; /* hmm */
239 *p++ = 0;
240 while (*p == ' ' || *p == '\t')
241 p++;
242 if (!instanza)
243 {
244 instanza = 1;
245 inrequest = 0;
246 if (!strcmp(buf, "request"))
247 {
248 inrequest = 1;
249 continue;
250 }
251 if (!strcmp(buf, "package"))
252 {
253 s = pool_id2solvable(pool, repo_add_solvable(xrepo));
254 isinstalled = 0;
255 keep = 0;
256 }
257 }
258 if (inrequest)
259 {
260 if (!job)
261 continue;
262 if (!strcmp(buf, "install"))
263 {
264 Id id, *idp;
265 Offset off = makedeps(xrepo, p, 0, 0);
266 for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++)
267 queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, id);
268 }
269 else if (!strcmp(buf, "remove"))
270 {
271 Id id, *idp;
272 Offset off = makedeps(xrepo, p, 0, 0);
273 for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++)
274 queue_push2(job, SOLVER_ERASE|SOLVER_SOLVABLE_PROVIDES, id);
275 }
276 else if (!strcmp(buf, "upgrade"))
277 {
278 Id id, *idp;
279 Offset off = makedeps(xrepo, p, 0, 0);
280 for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++)
281 queue_push2(job, SOLVER_INSTALL|SOLVER_ORUPDATE|SOLVER_SOLVABLE_PROVIDES, id);
282 }
283 continue;
284 }
285 if (!s)
286 continue; /* we ignore the preamble for now */
287 switch (buf[0])
288 {
289 case 'c':
290 if (!strcmp(buf, "conflicts"))
291 {
292 s->conflicts = makedeps(s->repo, p, s->conflicts, 0);
293 continue;
294 }
295 case 'd':
296 if (!strcmp(buf, "depends"))
297 {
298 s->requires = makedeps(s->repo, p, s->requires, 0);
299 continue;
300 }
301 break;
302 case 'k':
303 if (!strcmp(buf, "keep"))
304 {
305 if (!job)
306 continue;
307 if (!strcmp(p, "version"))
308 keep = KEEP_VERSION;
309 else if (!strcmp(p, "package"))
310 keep = KEEP_PACKAGE;
311 else if (!strcmp(p, "feature"))
312 keep = KEEP_FEATURE;
313 continue;
314 }
315 break;
316 case 'i':
317 if (!strcmp(buf, "installed"))
318 {
319 if (!strcmp(p, "true"))
320 {
321 isinstalled = 1;
322 if (!installedrepo)
323 s = solvable_free(s, 1);
324 else if (s->repo != installedrepo)
325 {
326 copysolvabledata(pool, s, installedrepo);
327 s->repo->nsolvables--;
328 s->repo = installedrepo;
329 if (s - pool->solvables < s->repo->start)
330 s->repo->start = s - pool->solvables;
331 if (s - pool->solvables >= s->repo->end)
332 s->repo->end = s - pool->solvables + 1;
333 s->repo->nsolvables++;
334 }
335 }
336 continue;
337 }
338 break;
339 case 'p':
340 if (!strcmp(buf, "package"))
341 {
342 s->name = pool_str2id(pool, p, 1);
343 continue;
344 }
345 if (!strcmp(buf, "provides"))
346 {
347 s->provides = makedeps(s->repo, p, s->provides, 0);
348 continue;
349 }
350 break;
351 case 'r':
352 if (!strcmp(buf, "depends"))
353 {
354 s->recommends = makedeps(s->repo, p, s->recommends, 0);
355 continue;
356 }
357 break;
358 case 'v':
359 if (!strcmp(buf, "version"))
360 {
361 s->evr = pool_str2id(pool, p, 1);
362 continue;
363 }
364 break;
365 }
366 }
367 if (s && !repo && !isinstalled)
368 s = solvable_free(s, 1);
369 if (s)
370 finishpackage(pool, s, keep, job);
371 solv_free(buf);
372 return 0;
373 }
374
375