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