2 * Copyright (c) 2018, SUSE LLC.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
22 #include "repo_rpmdb.h"
26 #include "repo_repomdxml.h"
27 #include "repo_rpmmd.h"
28 #include "repo_updateinfoxml.h"
29 #include "repo_deltainfoxml.h"
32 #ifdef ENABLE_SUSEREPO
33 #include "repo_content.h"
34 #include "repo_susetags.h"
38 #include "repo_autopattern.h"
41 #include "repo_appdata.h"
43 #include "common_write.h"
44 #include "solv_xfopen.h"
55 int add_changelog = 0;
56 int filtered_filelist = 0;
59 #define REPO_PLAINDIR 1
61 #define REPO_RPMMD_REPODATA 3
62 #define REPO_SUSETAGS 4
65 autodetect_repotype(Pool *pool, const char *dir)
71 tmp = pool_tmpjoin(pool, dir, "/repomd.xml", 0);
72 if (stat(tmp, &stb) == 0)
74 tmp = pool_tmpjoin(pool, dir, "/repodata/repomd.xml", 0);
75 if (stat(tmp, &stb) == 0)
76 return REPO_RPMMD_REPODATA;
77 tmp = pool_tmpjoin(pool, dir, "/content", 0);
78 if ((fp = fopen(tmp, "r")) != 0)
80 char buf[512], *descrdir = 0;
81 while (fgets(buf, sizeof(buf), fp))
85 if (buf[l - 1] != '\n')
88 while ((c = getc(fp)) != EOF && c != '\n')
92 while (l && (buf[l - 1] == '\n' || buf[l - 1] == ' ' || buf[l - 1] == '\t'))
95 while (*bp == ' ' || *bp == '\t')
97 if (strncmp(bp, "DESCRDIR", 8) != 0 || (bp[8] != ' ' && bp[8] != '\t'))
100 while (*bp == ' ' || *bp == '\t')
108 tmp = pool_tmpjoin(pool, dir, "/", descrdir);
109 if (stat(tmp, &stb) == 0 && S_ISDIR(stb.st_mode))
110 return REPO_SUSETAGS;
113 tmp = pool_tmpjoin(pool, dir, "/suse/setup/descr", 0);
114 if (stat(tmp, &stb) == 0 && S_ISDIR(stb.st_mode))
115 return REPO_SUSETAGS;
116 return REPO_PLAINDIR;
123 read_plaindir_repo(Repo *repo, const char *dir)
125 Pool *pool = repo->pool;
139 /* run find command */
145 while ((pid = fork()) == (pid_t)-1)
164 if (dup2(fds[1], 1) == -1)
172 execl("/usr/bin/find", ".", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0);
174 execl("/usr/bin/find", ".", "-maxdepth", "1", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0);
175 perror("/usr/bin/find");
179 if ((fp = fdopen(fds[0], "r")) == 0)
184 data = repo_add_repodata(repo, 0);
186 while ((c = getc(fp)) != EOF)
190 size_t len = bp - buf;
191 buf = solv_realloc(buf, len + 4096);
199 rpm = solv_dupjoin(dir, "/", bp[0] == '.' && bp[1] == '/' ? bp + 2 : bp);
200 if ((p = repo_add_rpm(repo, rpm, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|(filtered_filelist ? RPM_ADD_FILTERED_FILELIST : 0))) == 0)
202 fprintf(stderr, "%s: %s\n", rpm, pool_errstr(pool));
208 repodata_set_location(data, p, 0, 0, bp[0] == '.' && bp[1] == '/' ? bp + 2 : bp);
212 while (waitpid(pid, &wstatus, 0) == -1)
221 fprintf(stderr, "find: exit status %d\n", (wstatus >> 8) | (wstatus & 255) << 8);
226 repo_internalize(repo);
233 read_plaindir_repo(Repo *repo, const char *dir)
235 fprintf(stderr, "plaindir repo type is not supported\n");
241 #ifdef ENABLE_SUSEREPO
244 susetags_find(char **files, int nfiles, const char *what)
247 size_t l = strlen(what);
248 for (i = 0; i < nfiles; i++)
251 if (strncmp(fn, what, l) != 0)
257 if (strchr(fn + l + 1, '.') != 0)
259 if (solv_xfopen_iscompressed(fn) <= 0)
267 susetags_open(const char *dir, const char *filename, char **tmpp, int missingok)
275 *tmpp = solv_dupjoin(dir, "/", filename);
276 if ((fp = solv_xfopen(*tmpp, "r")) == 0)
283 *tmpp = solv_free(*tmpp);
290 susetags_extend(Repo *repo, const char *dir, char **files, int nfiles, char *what, Id defvendor, char *language, int missingok)
292 const char *filename;
296 filename = susetags_find(files, nfiles, what);
299 if ((fp = susetags_open(dir, filename, &tmp, missingok)) != 0)
301 if (repo_add_susetags(repo, fp, defvendor, language, REPO_EXTEND_SOLVABLES))
303 fprintf(stderr, "%s: %s\n", tmp, pool_errstr(repo->pool));
312 susetags_extend_languages(Repo *repo, const char *dir, char **files, int nfiles, Id defvendor, int missingok)
315 for (i = 0; i < nfiles; i++)
319 if (strncmp(fn, "packages.", 9) != 0)
321 if (strlen(fn + 9) + 1 >= sizeof(lang))
323 strncpy(lang, fn + 9, sizeof(lang) - 1);
324 lang[sizeof(lang) - 1] = 0;
325 p = strrchr(lang, '.');
328 if (solv_xfopen_iscompressed(lang) <= 0)
332 if (strchr(lang, '.'))
334 if (!strcmp(lang, "en"))
335 continue; /* already did that one */
336 if (!strcmp(lang, "DU"))
337 continue; /* disk usage */
338 if (!strcmp(lang, "FL"))
339 continue; /* file list */
340 if (!strcmp(lang, "DL"))
341 continue; /* deltas */
342 susetags_extend(repo, dir, files, nfiles, fn, defvendor, lang, missingok);
347 susetags_dircmp(const void *ap, const void *bp, void *dp)
349 return strcmp(*(const char **)ap, *(const char **)bp);
353 read_susetags_repo(Repo *repo, const char *dir)
355 Pool *pool = repo->pool;
356 const char *filename;
361 const char *descrdir = 0;
367 /* read content file */
368 repo_add_repodata(repo, 0);
369 tmp = solv_dupjoin(dir, "/content", 0);
370 if ((fp = fopen(tmp, "r")) != 0)
372 if (repo_add_content(repo, fp, REPO_REUSE_REPODATA))
374 fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
378 descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR);
379 defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
382 descrdir = "suse/setup/descr";
383 tmp = solv_free(tmp);
385 /* get content of descrdir directory */
386 ddir = solv_dupjoin(dir, "/", descrdir);
387 if ((dp = opendir(ddir)) == 0)
392 while ((de = readdir(dp)) != 0)
394 if (de->d_name[0] == 0 || de->d_name[0] == '.')
396 files = solv_extend(files, nfiles, 1, sizeof(char *), 63);
397 files[nfiles++] = solv_strdup(de->d_name);
401 solv_sort(files, nfiles, sizeof(char *), susetags_dircmp, 0);
404 filename = susetags_find(files, nfiles, "packages");
405 if (filename && (fp = susetags_open(ddir, filename, &tmp, 1)) != 0)
407 if (repo_add_susetags(repo, fp, defvendor, 0, REPO_NO_INTERNALIZE|SUSETAGS_RECORD_SHARES))
409 fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
413 tmp = solv_free(tmp);
415 /* now extend the packages */
416 susetags_extend(repo, ddir, files, nfiles, "packages.DU", defvendor, 0, 1);
417 susetags_extend(repo, ddir, files, nfiles, "packages.en", defvendor, 0, 1);
418 susetags_extend_languages(repo, ddir, files, nfiles, defvendor, 1);
420 susetags_extend(repo, ddir, files, nfiles, "packages.FL", defvendor, 0, 1);
424 filename = susetags_find(files, nfiles, "packages.DL");
425 if (filename && (fp = susetags_open(ddir, filename, &tmp, 1)) != 0)
427 if (repo_add_susetags(repo, fp, defvendor, 0, 0))
429 fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
433 tmp = solv_free(tmp);
436 /* add legacy patterns */
437 tmp = solv_dupjoin(ddir, "/patterns", 0);
438 if ((fp = fopen(tmp, "r")) != 0)
442 repo_add_repodata(repo, 0);
443 while (fgets(pbuf, sizeof(pbuf), fp))
447 if (strchr(pbuf, '/') != 0)
449 if ((p = strchr(pbuf, '\n')) != 0)
454 tmp = solv_dupjoin(ddir, "/", pbuf);
455 if ((pfp = solv_xfopen(tmp, "r")) != 0)
457 if (repo_add_susetags(repo, pfp, defvendor, 0, REPO_NO_INTERNALIZE|REPO_REUSE_REPODATA))
459 fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
467 tmp = solv_free(tmp);
469 #ifdef ENABLE_APPDATA
471 filename = add_appdata ? susetags_find(files, nfiles, "appdata.xml") : 0;
472 if (filename && (fp = susetags_open(ddir, filename, &tmp, 1)) != 0)
474 if (repo_add_appdata(repo, fp, 0))
476 fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
480 tmp = solv_free(tmp);
485 solv_free(files[--nfiles]);
488 repo_internalize(repo);
495 read_susetags_repo(Repo *repo, const char *dir)
497 fprintf(stderr, "susetags repo type is not supported\n");
507 repomd_find(Repo *repo, const char *what)
509 Pool *pool = repo->pool;
511 const char *filename;
514 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_REPOMD_TYPE, what, SEARCH_STRING);
515 dataiterator_prepend_keyname(&di, REPOSITORY_REPOMD);
516 if (dataiterator_step(&di))
518 dataiterator_setpos_parent(&di);
519 filename = pool_lookup_str(pool, SOLVID_POS, REPOSITORY_REPOMD_LOCATION);
521 dataiterator_free(&di);
522 if (filename && strncmp(filename, "repodata/", 9) == 0)
528 repomd_open(const char *dir, const char *filename, char **tmpp, int missingok)
536 *tmpp = solv_dupjoin(dir, "/", filename);
537 if ((fp = solv_xfopen(*tmpp, "r")) == 0)
544 *tmpp = solv_free(*tmpp);
551 repomd_extend(Repo *repo, const char *dir, const char *what, const char *language, int missingok)
553 const char *filename;
557 filename = repomd_find(repo, what);
560 fp = repomd_open(dir, filename, &tmp, missingok);
563 if (repo_add_rpmmd(repo, fp, language, REPO_EXTEND_SOLVABLES))
565 fprintf(stderr, "%s: %s\n", tmp, pool_errstr(repo->pool));
574 repomd_extend_languages(Repo *repo, const char *dir, int missingok)
576 char **susedatas = 0;
577 int nsusedatas = 0, i;
579 dataiterator_init(&di, repo->pool, repo, SOLVID_META, REPOSITORY_REPOMD_TYPE, "susedata.", SEARCH_STRINGSTART);
580 dataiterator_prepend_keyname(&di, REPOSITORY_REPOMD);
581 while (dataiterator_step(&di))
583 susedatas = solv_extend(susedatas, nsusedatas, 1, sizeof(char *), 15);
584 susedatas[nsusedatas++] = solv_strdup(di.kv.str);
586 dataiterator_free(&di);
587 for (i = 0; i < nsusedatas; i++)
589 repomd_extend(repo, dir, susedatas[i], susedatas[i] + 9, missingok);
590 susedatas[i] = solv_free(susedatas[i]);
592 solv_free(susedatas);
596 add_rpmmd_file(Repo *repo, const char *dir, const char *filename, int missingok)
601 fp = repomd_open(dir, filename, &tmp, missingok);
604 if (repo_add_rpmmd(repo, fp, 0, 0))
606 fprintf(stderr, "%s: %s\n", tmp, pool_errstr(repo->pool));
614 read_rpmmd_repo(Repo *repo, const char *dir)
616 Pool *pool = repo->pool;
619 const char *filename;
621 /* add repomd.xml and suseinfo.xml */
622 fp = repomd_open(dir, "repomd.xml", &tmp, 0);
623 if (repo_add_repomdxml(repo, fp, 0))
625 fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
629 tmp = solv_free(tmp);
630 filename = repomd_find(repo, "suseinfo");
631 if (filename && (fp = repomd_open(dir, filename, &tmp, 0)) != 0)
633 if (repo_add_repomdxml(repo, fp, REPO_REUSE_REPODATA))
635 fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
639 tmp = solv_free(tmp);
642 /* first all primary packages */
643 filename = repomd_find(repo, "primary");
646 add_rpmmd_file(repo, dir, filename, 0);
647 repomd_extend(repo, dir, "susedata", 0, 1);
648 repomd_extend_languages(repo, dir, 1);
650 repomd_extend(repo, dir, "filelists", 0, 1);
652 repomd_extend(repo, dir, "other", 0, 1);
655 /* some legacy stuff */
656 filename = repomd_find(repo, "products");
658 filename = repomd_find(repo, "product");
660 add_rpmmd_file(repo, dir, filename, 1);
661 filename = repomd_find(repo, "patterns");
662 add_rpmmd_file(repo, dir, filename, 1);
665 filename = repomd_find(repo, "updateinfo");
666 if (filename && (fp = repomd_open(dir, filename, &tmp, 0)) != 0)
668 if (repo_add_updateinfoxml(repo, fp, 0))
670 fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
674 tmp = solv_free(tmp);
678 filename = repomd_find(repo, "deltainfo");
680 filename = repomd_find(repo, "prestodelta");
681 if (filename && (fp = repomd_open(dir, filename, &tmp, 1)) != 0)
683 if (repo_add_deltainfoxml(repo, fp, 0))
685 fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
689 tmp = solv_free(tmp);
692 #ifdef ENABLE_APPDATA
694 filename = add_appdata ? repomd_find(repo, "appdata") : 0;
695 if (filename && (fp = repomd_open(dir, filename, &tmp, 1)) != 0)
697 if (repo_add_appdata(repo, fp, 0))
699 fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
703 tmp = solv_free(tmp);
707 repo_internalize(repo);
714 read_rpmmd_repo(Repo *repo, const char *dir)
716 fprintf(stderr, "rpmmd repo type is not supported\n");
725 fprintf(stderr, "\nUsage:\n"
726 "repo2solv [-R] [-X] [-A] [-o <out.solv>] <dir>\n"
727 " Convert a repository in <dir> to a solv file\n"
728 " -h : print help & exit\n"
729 " -o <out.solv>: write to this file instead of stdout\n"
730 " -F : add filelist\n"
731 " -R : also search subdirectories for rpms\n"
732 " -X : generate pattern/product pseudo packages\n"
733 " -A : add appdata packages\n"
739 main(int argc, char **argv)
747 Pool *pool = pool_create();
748 Repo *repo = repo_create(pool, "<repo>");
750 while ((c = getopt(argc, argv, "hAXRFCo:")) >= 0)
763 #ifdef ENABLE_APPDATA
768 repotype = REPO_PLAINDIR;
785 if (optind + 1 != argc)
793 if (!S_ISDIR(stb.st_mode))
795 fprintf(stderr, "%s: not a directory\n", dir);
798 dir = solv_strdup(dir);
800 repotype = autodetect_repotype(pool, dir);
805 res = read_rpmmd_repo(repo, dir);
807 case REPO_RPMMD_REPODATA:
808 dir = solv_dupappend(dir, "/repodata", 0);
809 res = read_rpmmd_repo(repo, dir);
812 res = read_susetags_repo(repo, dir);
815 res = read_plaindir_repo(repo, dir);
818 fprintf(stderr, "unknown repotype %d\n", repotype);
821 if (outfile && freopen(outfile, "w", stdout) == 0)
828 repo_add_autopattern(repo, 0);
830 tool_write(repo, 0, 0);