4 * Parses all files below 'proddir'
5 * See http://en.opensuse.org/Product_Management/Code11
8 * Copyright (c) 2007, Novell Inc.
10 * This program is licensed under the BSD license, read LICENSE.BSD
11 * for further information
14 #include <sys/types.h>
28 #include "tools_util.h"
29 #include "repo_content.h"
32 static ino_t baseproduct = 0;
38 Id langcache[ID_NUM_INTERNAL];
43 * create localized tag
47 langtag(struct parsedata *pd, Id tag, const char *language)
49 if (language && !language[0])
51 if (!language || tag >= ID_NUM_INTERNAL)
52 return pool_id2langid(pd->repo->pool, tag, language, 1);
53 return pool_id2langid(pd->repo->pool, tag, language, 1);
54 if (!pd->langcache[tag])
55 pd->langcache[tag] = pool_id2langid(pd->repo->pool, tag, language, 1);
56 return pd->langcache[tag];
72 * add single product to repo
77 repo_add_product(struct parsedata *pd, Repodata *data, FILE *fp, int code11)
79 Repo *repo = pd->repo;
80 Pool *pool = repo->pool;
86 enum sections current_section = SECTION_UNKNOWN;
88 line = sat_malloc(1024);
96 /* read line into big-enough buffer */
97 if (linep - line + 16 > aline)
100 line = sat_realloc(line, aline + 512);
101 linep = line + aline;
104 if (!fgets(linep, aline - (linep - line), fp))
106 linep += strlen(linep);
107 if (linep == line || linep[-1] != '\n')
114 /* non-code11, assume /etc/xyz-release
115 * just parse first line
116 * as "<name> <version> (<arch>)"
120 if (split(linep, sp, 3) == 3)
126 s = pool_id2solvable(pool, repo_add_solvable(repo));
127 repodata_extend(data, s - pool->solvables);
128 handle = repodata_get_handle(data, s - pool->solvables - repo->start);
129 if (!fstat(fileno(fp), &st))
131 repodata_set_num(data, handle, SOLVABLE_INSTALLTIME, st.st_ctime);
135 perror("Can't stat()");
138 s->name = str2id(pool, join2("product", ":", sp[0]), 1);
139 s->evr = makeevr(pool, sp[1]);
143 fprintf(stderr, "Can't recognize -release line '%s'\n", linep);
145 break; /* just parse single line */
149 * Very trivial .ini parser
152 /* skip empty and comment lines */
159 /* sections must start at column 0 */
162 char *secp = linep+1;
164 endp = strchr(secp, ']');
167 fprintf(stderr, "Skipping unclosed section '%s'\n", line);
171 if (!strcmp(secp, "product"))
172 current_section = SECTION_PRODUCT;
173 else if (!strcmp(secp, "translated"))
174 current_section = SECTION_TRANSLATED;
175 else if (!strcmp(secp, "update"))
176 current_section = SECTION_UPDATE;
179 fprintf(stderr, "Skipping unknown section '%s'\n", secp);
180 current_section = SECTION_UNKNOWN;
184 else if (current_section != SECTION_UNKNOWN)
187 char *key, *value, *lang;
191 /* split line into '<key>[<lang>] = <value>' */
192 while (*ptr && (*ptr == ' ' || *ptr == '\t'))
195 while (*ptr && !(*ptr == ' ' || *ptr == '\t' || *ptr == '=' || *ptr == '['))
201 while (*ptr && !(*ptr == ']'))
207 while (*ptr && !(*ptr == '='))
211 while (*ptr && (*ptr == ' ' || *ptr == '\t'))
219 if (current_section == SECTION_PRODUCT)
225 s = pool_id2solvable(pool, repo_add_solvable(repo));
226 repodata_extend(data, s - pool->solvables);
227 handle = repodata_get_handle(data, s - pool->solvables - repo->start);
228 if (!fstat(fileno(fp), &st))
230 repodata_set_num(data, handle, SOLVABLE_INSTALLTIME, st.st_ctime);
231 /* this is where <productsdir>/baseproduct points to */
232 if (st.st_ino == baseproduct)
233 repodata_set_str(data, handle, PRODUCT_TYPE, "base");
237 perror("Can't stat()");
240 if (!strcmp(key, "name"))
241 s->name = str2id(pool, join2("product", ":", value), 1);
242 else if (!strcmp(key, "version"))
243 s->evr = makeevr(pool, value);
244 else if (!strcmp(key, "vendor"))
245 s->vendor = str2id(pool, value, 1);
246 else if (!strcmp(key, "distribution"))
247 repo_set_str(repo, s - pool->solvables, SOLVABLE_DISTRIBUTION, value);
248 else if (!strcmp (key, "flavor"))
249 repo_set_str(repo, s - pool->solvables, PRODUCT_FLAVOR, value);
254 else if (current_section == SECTION_TRANSLATED)
256 if (!strcmp(key, "summary"))
258 repodata_set_str(data, handle, langtag(pd, SOLVABLE_SUMMARY, lang), value );
260 else if (!strcmp(key, "description"))
261 repodata_set_str(data, handle, langtag(pd, SOLVABLE_DESCRIPTION, lang), value );
266 else if (current_section == SECTION_UPDATE)
271 fprintf (stderr, "malformed line: %s\n", line);
276 fprintf(stderr, "No product solvable created !\n");
281 s->arch = ARCH_NOARCH;
282 if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
284 s->provides = repo_addid_dep(pd->repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
292 * parse dir looking for files ending in suffix
296 parse_dir(DIR *dir, const char *path, struct parsedata *pd, Repodata *repodata, int code11)
298 struct dirent *entry;
299 char *suffix = code11 ? ".prod" : "-release";
300 int slen = code11 ? 5 : 8; /* strlen(".prod") : strlen("-release") */
303 /* check for <productsdir>/baseproduct on code11 and remember its target inode */
305 && stat(join2(path, "/", "baseproduct"), &st) == 0) /* follow symlink */
307 baseproduct = st.st_ino;
310 while ((entry = readdir(dir)))
313 len = strlen(entry->d_name);
315 /* skip /etc/lsb-release, thats not a product per-se */
317 && strcmp(entry->d_name, "lsb-release") == 0)
323 && strcmp(entry->d_name+len-slen, suffix) == 0)
325 char *fullpath = join2(path, "/", entry->d_name);
326 FILE *fp = fopen(fullpath, "r");
332 repo_add_product(pd, repodata, fp, code11);
340 * read all installed products
342 * try proddir (reading all .prod files from this directory) first
343 * if not available, assume non-code11 layout and parse /etc/xyz-release
345 * parse each one as a product
349 repo_add_products(Repo *repo, Repodata *repodata, const char *proddir, const char *root)
351 const char *fullpath = proddir;
353 DIR *dir = opendir(fullpath);
356 memset(&pd, 0, sizeof(pd));
361 fullpath = root ? join2(root, "", "/etc") : "/etc";
362 dir = opendir(fullpath);
371 parse_dir(dir, fullpath, &pd, repodata, code11);