parse /etc/products.d/*.prod for installed products
[platform/upstream/libsolv.git] / tools / repo_products.c
1 /*
2  * repo_products.c
3  * 
4  * Parses all files below 'proddir'
5  * See http://en.opensuse.org/Product_Management/Code11
6  * 
7  * 
8  * Copyright (c) 2007, Novell Inc.
9  *
10  * This program is licensed under the BSD license, read LICENSE.BSD
11  * for further information
12  */
13
14 #include <sys/types.h>
15 #include <limits.h>
16 #include <fcntl.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <assert.h>
21 #include <dirent.h>
22
23 #include "pool.h"
24 #include "repo.h"
25 #include "util.h"
26 #include "repo_content.h"
27
28 struct parsedata {
29   Repo *repo;
30   char *tmp;
31   int tmpl;
32 };
33
34
35 /*
36  * join up to three strings into one
37  */
38
39 static char *
40 join(struct parsedata *pd, const char *s1, const char *s2, const char *s3)
41 {
42   int l = 1;
43   char *p;
44
45   if (s1)
46     l += strlen(s1);
47   if (s2)
48     l += strlen(s2);
49   if (s3)
50     l += strlen(s3);
51   if (l > pd->tmpl)
52     {
53       pd->tmpl = l + 256;
54       pd->tmp = sat_realloc(pd->tmp, pd->tmpl);
55     }
56   p = pd->tmp;
57   if (s1)
58     {
59       strcpy(p, s1);
60       p += strlen(s1);
61     }
62   if (s2)
63     {
64       strcpy(p, s2);
65       p += strlen(s2);
66     }
67   if (s3)
68     {
69       strcpy(p, s3);
70       p += strlen(s3);
71     }
72   return pd->tmp;
73 }
74
75
76 static Id
77 makeevr(Pool *pool, char *s)
78 {
79   if (!strncmp(s, "0:", 2) && s[2])
80     s += 2;
81   return str2id(pool, s, 1);
82 }
83
84
85 enum sections 
86 {
87   SECTION_UNKNOWN,
88   SECTION_PRODUCT
89 };
90
91
92 /*
93  * add single product to repo
94  *
95  */
96
97 static void
98 repo_add_product(struct parsedata *pd, FILE *fp)
99 {
100   Repo *repo = pd->repo;
101   Pool *pool = repo->pool;
102   char *line, *linep;
103   int aline;
104   Solvable *s = 0;
105   Id handle = 0;
106   Repodata *data;
107
108   enum sections current_section = SECTION_UNKNOWN;
109   
110   if (repo->nrepodata)
111     /* use last repodata */
112     data = repo->repodata + repo->nrepodata - 1;
113   else
114     data = repo_add_repodata(repo, 0);
115
116   line = sat_malloc(1024);
117   aline = 1024;
118
119   linep = line;
120   s = 0;
121
122   for (;;)
123     {      
124       /* read line into big-enough buffer */
125       if (linep - line + 16 > aline)
126         {
127           aline = linep - line;
128           line = sat_realloc(line, aline + 512);
129           linep = line + aline;
130           aline += 512;
131         }
132       if (!fgets(linep, aline - (linep - line), fp))
133         break;
134       linep += strlen(linep);
135       if (linep == line || linep[-1] != '\n')
136         continue;
137       *--linep = 0;
138       linep = line;
139
140       /*
141        * Very trivial .ini parser
142        */
143       
144       /* skip empty and comment lines */
145       if (*linep == '#'
146           || *linep == 0)
147         {
148           continue;
149         }
150       
151       /* sections must start at column 0 */
152       if (*linep == '[')
153         {
154           char *secp = linep+1;
155           char *endp = linep;
156           endp = strchr(secp, ']');
157           if (!endp)
158             {
159               fprintf(stderr, "Skipping unclosed section '%s'\n", line);
160               continue;
161             }
162           *endp = 0;
163           if (!strcmp(secp, "product"))
164             current_section = SECTION_PRODUCT;
165           else
166             {
167               fprintf(stderr, "Skipping unknown section '%s'\n", secp);
168               current_section = SECTION_UNKNOWN;
169             }
170           continue;
171         }
172       else if (current_section != SECTION_UNKNOWN)
173         {
174           char *ptr = linep;
175           char *key, *value;
176
177           /* split line into '<key> = <value>' */
178           while (*ptr && (*ptr == ' ' || *ptr == '\t'))
179             ++ptr;
180           key = ptr;
181           while (*ptr && !(*ptr == ' ' || *ptr == '\t' || *ptr == '='))
182             ++ptr;
183           if (*ptr != '=')
184             *ptr++ = 0;
185           while (*ptr && !(*ptr == '='))
186             ++ptr;
187           if (*ptr == '=')
188             *ptr++ = 0;
189           while (*ptr && (*ptr == ' ' || *ptr == '\t'))
190             ++ptr;
191           value = ptr;
192           while (*ptr && !(*ptr == ' ' || *ptr == '\t'))
193             ++ptr;
194           *ptr++ = 0;
195
196           if (current_section == SECTION_PRODUCT)
197             {
198               if (!s)
199                 {
200                   s = pool_id2solvable(pool, repo_add_solvable(repo));
201                   repodata_extend(data, s - pool->solvables);
202                   handle = repodata_get_handle(data, s - pool->solvables - repo->start);
203                 }
204               if (!strcmp(key, "name"))
205                   s->name = str2id(pool, join(pd, "product", ":", value), 1);
206               else if (!strcmp(key, "version"))
207                 s->evr = makeevr(pool, value);
208               else if (!strcmp (key, "flavor"))
209                 repo_set_str(repo, s - pool->solvables, PRODUCT_FLAVOR, value);     
210             }
211         }
212       else
213         fprintf (stderr, "malformed line: %s\n", line);
214     }
215
216   if (!s)
217     {
218       fprintf(stderr, "No product solvable created !\n");
219       exit(1);
220     }
221
222   if (!s->arch)
223     s->arch = ARCH_NOARCH;
224   if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
225     {
226       s->provides = repo_addid_dep(pd->repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
227     }
228   
229   sat_free(line);
230 }
231
232
233 /*
234  * read all .prod files from directory
235  * parse each one as a product
236  */
237
238 void
239 repo_add_products(Repo *repo, const char *proddir)
240 {
241   DIR *dir = opendir(proddir);
242   struct dirent *entry;
243   struct parsedata pd;
244   
245   memset(&pd, 0, sizeof(pd));
246   pd.repo = repo;
247
248   if (!dir)
249     {
250       perror(proddir);
251       return;
252     }
253   
254   while ((entry = readdir(dir)))
255     {
256       const char *dot;
257       dot = strrchr( entry->d_name, '.' );
258       if (dot && strcmp(dot, ".prod") == 0)
259         {
260           char *fullpath = join(&pd, proddir, "/", entry->d_name);
261           FILE *fp = fopen(fullpath, "r");
262           if (!fp)
263             {
264               perror(fullpath);
265               break;
266             }
267           repo_add_product(&pd, fp);
268           fclose(fp);
269         }
270     }
271   if (pd.tmp)
272     sat_free(pd.tmp);
273   closedir(dir);
274 }