Imported Upstream version 0.6.35
[platform/upstream/libsolv.git] / tools / repo2solv.c
1 /*
2  * Copyright (c) 2018, SUSE LLC.
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 <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <dirent.h>
14 #include <sys/stat.h>
15 #include <sys/wait.h>
16 #include <errno.h>
17
18 #include "pool.h"
19 #include "repo.h"
20
21 #ifdef ENABLE_RPMPKG
22 #include "repo_rpmdb.h"
23 #endif
24
25 #ifdef ENABLE_RPMMD
26 #include "repo_repomdxml.h"
27 #include "repo_rpmmd.h"
28 #include "repo_updateinfoxml.h"
29 #include "repo_deltainfoxml.h"
30 #endif
31
32 #ifdef ENABLE_SUSEREPO
33 #include "repo_content.h"
34 #include "repo_susetags.h"
35 #endif
36
37 #ifdef SUSE
38 #include "repo_autopattern.h"
39 #endif
40 #ifdef ENABLE_APPDATA
41 #include "repo_appdata.h"
42 #endif
43 #include "common_write.h"
44 #include "solv_xfopen.h"
45
46
47 #ifdef SUSE
48 int add_auto = 0;
49 #endif
50 #ifdef ENABLE_APPDATA
51 int add_appdata = 0;
52 #endif
53 int recursive = 0;
54 int add_filelist = 0;
55 int add_changelog = 0;
56 int filtered_filelist = 0;
57
58
59 #define REPO_PLAINDIR           1
60 #define REPO_RPMMD              2
61 #define REPO_RPMMD_REPODATA     3
62 #define REPO_SUSETAGS           4
63
64 int
65 autodetect_repotype(Pool *pool, const char *dir)
66 {
67   struct stat stb;
68   char *tmp;
69   FILE *fp;
70
71   tmp = pool_tmpjoin(pool, dir, "/repomd.xml", 0);
72   if (stat(tmp, &stb) == 0)
73     return REPO_RPMMD;
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)
79     {
80       char buf[512], *descrdir = 0;
81       while (fgets(buf, sizeof(buf), fp))
82         {
83           int l = strlen(buf);
84           char *bp = buf;
85           if (buf[l - 1] != '\n')
86             {
87               int c;
88               while ((c = getc(fp)) != EOF && c != '\n')
89                 ;
90               continue;
91             }
92           while (l && (buf[l - 1] == '\n' || buf[l - 1] == ' ' || buf[l - 1] == '\t'))
93             l--;
94           buf[l] = 0;
95           while (*bp == ' ' || *bp == '\t')
96             bp++;
97           if (strncmp(bp, "DESCRDIR", 8) != 0 || (bp[8] != ' ' && bp[8] != '\t'))
98             continue;
99           bp += 9;
100           while (*bp == ' ' || *bp == '\t')
101             bp++;
102           descrdir = bp;
103           break;
104         }
105       fclose(fp);
106       if (descrdir)
107         {
108           tmp = pool_tmpjoin(pool, dir, "/", descrdir);
109           if (stat(tmp, &stb) == 0 && S_ISDIR(stb.st_mode))
110             return REPO_SUSETAGS;
111         }
112     }
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;
117 }
118
119
120 #ifdef ENABLE_RPMPKG
121
122 int
123 read_plaindir_repo(Repo *repo, const char *dir)
124 {
125   Pool *pool = repo->pool;
126   Repodata *data;
127   int c;
128   FILE *fp;
129   int wstatus;
130   int fds[2];
131   pid_t pid;
132   char *buf = 0;
133   char *buf_end = 0;
134   char *bp = 0;
135   char *rpm;
136   int res = 0;
137   Id p;
138
139   /* run find command */
140   if (pipe(fds))
141     {
142       perror("pipe");
143       exit(1);
144     }
145   while ((pid = fork()) == (pid_t)-1)
146     {
147       if (errno != EAGAIN)
148         {
149           perror("fork");
150           exit(1);
151         }
152       sleep(3);
153     }
154   if (pid == 0)
155     {
156       if (chdir(dir))
157         {
158           perror(dir);
159           _exit(1);
160         }
161       close(fds[0]);
162       if (fds[1] != 1)
163         {
164           if (dup2(fds[1], 1) == -1)
165             {
166               perror("dup2");
167               _exit(1);
168             }
169           close(fds[1]);
170         }
171       if (recursive)
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);
173       else
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");
176       _exit(1);
177     }
178   close(fds[1]);
179   if ((fp = fdopen(fds[0], "r")) == 0)
180     {
181       perror("fdopen");
182       exit(1);
183     }
184   data = repo_add_repodata(repo, 0);
185   bp = buf;
186   while ((c = getc(fp)) != EOF)
187     {
188       if (bp == buf_end)
189         {
190           size_t len = bp - buf;
191           buf = solv_realloc(buf, len + 4096);
192           bp = buf + len;
193           buf_end = bp + 4096;
194         }
195       *bp++ = c;
196       if (c)
197         continue;
198       bp = buf;
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)
201         {
202           fprintf(stderr, "%s: %s\n", rpm, pool_errstr(pool));
203 #if 0
204           res = 1;
205 #endif
206         }
207       else
208         repodata_set_location(data, p, 0, 0, bp[0] == '.' && bp[1] == '/' ? bp + 2 : bp);
209       solv_free(rpm);
210     }
211   fclose(fp);
212   while (waitpid(pid, &wstatus, 0) == -1)
213     {
214       if (errno == EINTR)
215         continue;
216       perror("waitpid");
217       exit(1);
218     }
219   if (wstatus)
220     {
221       fprintf(stderr, "find: exit status %d\n", (wstatus >> 8) | (wstatus & 255) << 8);
222 #if 0
223       res = 1;
224 #endif
225     }
226   repo_internalize(repo);
227   return res;
228 }
229
230 #else
231
232 int
233 read_plaindir_repo(Repo *repo, const char *dir)
234 {
235   fprintf(stderr, "plaindir repo type is not supported\n");
236   exit(1);
237 }
238
239 #endif
240
241 #ifdef ENABLE_SUSEREPO
242
243 static const char *
244 susetags_find(char **files, int nfiles, const char *what)
245 {
246   int i;
247   size_t l = strlen(what);
248   for (i = 0; i < nfiles; i++)
249     {
250       char *fn = files[i];
251       if (strncmp(fn, what, l) != 0)
252         continue;
253       if (fn[l] == 0)
254         return fn;
255       if (fn[l] != '.')
256         continue;
257       if (strchr(fn + l + 1, '.') != 0)
258         continue;
259       if (solv_xfopen_iscompressed(fn) <= 0)
260         continue;
261       return fn;
262     }
263   return 0;
264 }
265
266 static FILE *
267 susetags_open(const char *dir, const char *filename, char **tmpp, int missingok)
268 {
269   FILE *fp;
270   if (!filename)
271     {
272       *tmpp = 0;
273       return 0;
274     }
275   *tmpp = solv_dupjoin(dir, "/", filename);
276   if ((fp = solv_xfopen(*tmpp, "r")) == 0)
277     {
278       if (!missingok)
279         {
280           perror(*tmpp);
281           exit(1);
282         }
283       *tmpp = solv_free(*tmpp);
284       return 0;
285     }
286   return fp;
287 }
288
289 static void
290 susetags_extend(Repo *repo, const char *dir, char **files, int nfiles, char *what, Id defvendor, char *language, int missingok)
291 {
292   const char *filename;
293   FILE *fp;
294   char *tmp;
295
296   filename = susetags_find(files, nfiles, what);
297   if (!filename)
298     return;
299   if ((fp = susetags_open(dir, filename, &tmp, missingok)) != 0)
300     {
301       if (repo_add_susetags(repo, fp, defvendor, language, REPO_EXTEND_SOLVABLES))
302         {
303           fprintf(stderr, "%s: %s\n", tmp, pool_errstr(repo->pool));
304           exit(1);
305         }
306       fclose(fp);
307       solv_free(tmp);
308     }
309 }
310
311 static void
312 susetags_extend_languages(Repo *repo, const char *dir, char **files, int nfiles, Id defvendor, int missingok)
313 {
314   int i;
315   for (i = 0; i < nfiles; i++)
316     {
317       char *fn = files[i];
318       char lang[64], *p;
319       if (strncmp(fn, "packages.", 9) != 0)
320         continue;
321       if (strlen(fn + 9) + 1 >= sizeof(lang))
322         continue;
323       strncpy(lang, fn + 9, sizeof(lang) - 1);
324       lang[sizeof(lang) - 1] = 0;
325       p = strrchr(lang, '.');
326       if (p)
327         {
328           if (solv_xfopen_iscompressed(lang) <= 0)
329             continue;
330           *p = 0;
331         }
332       if (strchr(lang, '.'))
333         continue;
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);
343     }
344 }
345
346 static int
347 susetags_dircmp(const void *ap, const void *bp, void *dp)
348 {
349   return strcmp(*(const char **)ap, *(const char **)bp);
350 }
351
352 int
353 read_susetags_repo(Repo *repo, const char *dir)
354 {
355   Pool *pool = repo->pool;
356   const char *filename;
357   char *ddir;
358   char *tmp;
359   FILE *fp;
360   Id defvendor = 0;
361   const char *descrdir = 0;
362   char **files = 0;
363   int nfiles = 0;
364   DIR *dp;
365   struct dirent *de;
366
367   /* read content file */
368   repo_add_repodata(repo, 0);
369   tmp = solv_dupjoin(dir, "/content", 0);
370   if ((fp = fopen(tmp, "r")) != 0)
371     {
372       if (repo_add_content(repo, fp, REPO_REUSE_REPODATA))
373         {
374           fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
375           exit(1);
376         }
377       fclose(fp);
378       descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR);
379       defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
380     }
381   if (!descrdir)
382     descrdir = "suse/setup/descr";
383   tmp = solv_free(tmp);
384
385   /* get content of descrdir directory */
386   ddir = solv_dupjoin(dir, "/", descrdir);
387   if ((dp = opendir(ddir)) == 0)
388     {
389       perror(ddir);
390       exit(1);
391     }
392   while ((de = readdir(dp)) != 0)
393     {
394       if (de->d_name[0] == 0 || de->d_name[0] == '.')
395         continue;
396       files = solv_extend(files, nfiles, 1, sizeof(char *), 63);
397       files[nfiles++] = solv_strdup(de->d_name);
398     }
399   closedir(dp);
400   if (nfiles > 1)
401     solv_sort(files, nfiles, sizeof(char *), susetags_dircmp, 0);
402   
403   /* add packages */
404   filename = susetags_find(files, nfiles, "packages");
405   if (filename && (fp = susetags_open(ddir, filename, &tmp, 1)) != 0)
406     {
407       if (repo_add_susetags(repo, fp, defvendor, 0, REPO_NO_INTERNALIZE|SUSETAGS_RECORD_SHARES))
408         {
409           fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
410           exit(1);
411         }
412       fclose(fp);
413       tmp = solv_free(tmp);
414
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);
419       if (add_filelist)
420         susetags_extend(repo, ddir, files, nfiles, "packages.FL", defvendor, 0, 1);
421     }
422
423   /* add deltas */
424   filename = susetags_find(files, nfiles, "packages.DL");
425   if (filename && (fp = susetags_open(ddir, filename, &tmp, 1)) != 0)
426     {
427       if (repo_add_susetags(repo, fp, defvendor, 0, 0))
428         {
429           fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
430           exit(1);
431         }
432       fclose(fp);
433       tmp = solv_free(tmp);
434     }
435
436   /* add legacy patterns */
437   tmp = solv_dupjoin(ddir, "/patterns", 0);
438   if ((fp = fopen(tmp, "r")) != 0)
439     {
440       char pbuf[4096];
441
442       repo_add_repodata(repo, 0);
443       while (fgets(pbuf, sizeof(pbuf), fp))
444         {
445           char *p;
446           FILE *pfp;
447           if (strchr(pbuf, '/') != 0)
448             continue;
449           if ((p = strchr(pbuf, '\n')) != 0)
450             *p = 0;
451           if (*pbuf == 0)
452             continue;
453           solv_free(tmp);
454           tmp = solv_dupjoin(ddir, "/", pbuf);
455           if ((pfp = solv_xfopen(tmp, "r")) != 0)
456             {
457               if (repo_add_susetags(repo, pfp, defvendor, 0, REPO_NO_INTERNALIZE|REPO_REUSE_REPODATA))
458                 {
459                   fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
460                   exit(1);
461                 }
462               fclose(pfp);
463             }
464         }
465       fclose(fp);
466     }
467   tmp = solv_free(tmp);
468  
469 #ifdef ENABLE_APPDATA
470   /* appdata */
471   filename = add_appdata ? susetags_find(files, nfiles, "appdata.xml") : 0;
472   if (filename && (fp = susetags_open(ddir, filename, &tmp, 1)) != 0)
473     {
474       if (repo_add_appdata(repo, fp, 0))
475         {
476           fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
477           exit(1);
478         }
479       fclose(fp);
480       tmp = solv_free(tmp);
481     }
482 #endif
483
484   while (nfiles > 0)
485     solv_free(files[--nfiles]);
486   solv_free(files);
487   solv_free(ddir);
488   repo_internalize(repo);
489   return 0;
490 }
491
492 #else
493
494 int
495 read_susetags_repo(Repo *repo, const char *dir)
496 {
497   fprintf(stderr, "susetags repo type is not supported\n");
498   exit(1);
499 }
500
501 #endif
502
503
504 #ifdef ENABLE_RPMMD
505
506 static const char *
507 repomd_find(Repo *repo, const char *what)
508 {
509   Pool *pool = repo->pool;
510   Dataiterator di;
511   const char *filename;
512
513   filename = 0;
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))
517     {
518       dataiterator_setpos_parent(&di);
519       filename = pool_lookup_str(pool, SOLVID_POS, REPOSITORY_REPOMD_LOCATION);
520     }
521   dataiterator_free(&di);
522   if (filename && strncmp(filename, "repodata/", 9) == 0)
523     filename += 9;
524   return filename;
525 }
526
527 static FILE *
528 repomd_open(const char *dir, const char *filename, char **tmpp, int missingok)
529 {
530   FILE *fp;
531   if (!filename)
532     {
533       *tmpp = 0;
534       return 0;
535     }
536   *tmpp = solv_dupjoin(dir, "/", filename);
537   if ((fp = solv_xfopen(*tmpp, "r")) == 0)
538     {
539       if (!missingok)
540         {
541           perror(*tmpp);
542           exit(1);
543         }
544       *tmpp = solv_free(*tmpp);
545       return 0;
546     }
547   return fp;
548 }
549
550 static void
551 repomd_extend(Repo *repo, const char *dir, const char *what, const char *language, int missingok)
552 {
553   const char *filename;
554   FILE *fp;
555   char *tmp;
556
557   filename = repomd_find(repo, what);
558   if (!filename)
559     return;
560   fp = repomd_open(dir, filename, &tmp, missingok);
561   if (fp)
562     {
563       if (repo_add_rpmmd(repo, fp, language, REPO_EXTEND_SOLVABLES))
564         {
565           fprintf(stderr, "%s: %s\n", tmp, pool_errstr(repo->pool));
566           exit(1);
567         }
568       fclose(fp);
569     }
570   solv_free(tmp);
571 }
572
573 static void
574 repomd_extend_languages(Repo *repo, const char *dir, int missingok)
575 {
576   char **susedatas = 0;
577   int nsusedatas = 0, i;
578   Dataiterator di;
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))
582     {
583       susedatas = solv_extend(susedatas, nsusedatas, 1, sizeof(char *), 15);
584       susedatas[nsusedatas++] = solv_strdup(di.kv.str);
585     }
586   dataiterator_free(&di);
587   for (i = 0; i < nsusedatas; i++)
588     {
589       repomd_extend(repo, dir, susedatas[i], susedatas[i] + 9, missingok);
590       susedatas[i] = solv_free(susedatas[i]);
591     }
592   solv_free(susedatas);
593 }
594
595 static void
596 add_rpmmd_file(Repo *repo, const char *dir, const char *filename, int missingok)
597 {
598   FILE *fp;
599   char *tmp;
600
601   fp = repomd_open(dir, filename, &tmp, missingok);
602   if (!fp)
603     return;
604   if (repo_add_rpmmd(repo, fp, 0, 0))
605     {
606       fprintf(stderr, "%s: %s\n", tmp, pool_errstr(repo->pool));
607       exit(1);
608     }
609   fclose(fp);
610   solv_free(tmp);
611 }
612
613 int
614 read_rpmmd_repo(Repo *repo, const char *dir)
615 {
616   Pool *pool = repo->pool;
617   FILE *fp;
618   char *tmp = 0;
619   const char *filename;
620
621   /* add repomd.xml and suseinfo.xml */
622   fp = repomd_open(dir, "repomd.xml", &tmp, 0);
623   if (repo_add_repomdxml(repo, fp, 0))
624     {
625       fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
626       exit(1);
627     }
628   fclose(fp);
629   tmp = solv_free(tmp);
630   filename = repomd_find(repo, "suseinfo");
631   if (filename && (fp = repomd_open(dir, filename, &tmp, 0)) != 0)
632     {
633       if (repo_add_repomdxml(repo, fp, REPO_REUSE_REPODATA))
634         {
635           fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
636           exit(1);
637         }
638       fclose(fp);
639       tmp = solv_free(tmp);
640     }
641   
642   /* first all primary packages */
643   filename = repomd_find(repo, "primary");
644   if (filename)
645     {
646       add_rpmmd_file(repo, dir, filename, 0);
647       repomd_extend(repo, dir, "susedata", 0, 1);
648       repomd_extend_languages(repo, dir, 1);
649       if (add_filelist)
650         repomd_extend(repo, dir, "filelists", 0, 1);
651       if (add_changelog)
652         repomd_extend(repo, dir, "other", 0, 1);
653     }
654
655   /* some legacy stuff */
656   filename = repomd_find(repo, "products");
657   if (!filename)
658     filename = repomd_find(repo, "product");
659   if (filename)
660     add_rpmmd_file(repo, dir, filename, 1);
661   filename = repomd_find(repo, "patterns");
662     add_rpmmd_file(repo, dir, filename, 1);
663   
664   /* updateinfo */
665   filename = repomd_find(repo, "updateinfo");
666   if (filename && (fp = repomd_open(dir, filename, &tmp, 0)) != 0)
667     {
668       if (repo_add_updateinfoxml(repo, fp, 0))
669         {
670           fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
671           exit(1);
672         }
673       fclose(fp);
674       tmp = solv_free(tmp);
675     }
676
677   /* deltainfo */
678   filename = repomd_find(repo, "deltainfo");
679   if (!filename)
680     filename = repomd_find(repo, "prestodelta");
681   if (filename && (fp = repomd_open(dir, filename, &tmp, 1)) != 0)
682     {
683       if (repo_add_deltainfoxml(repo, fp, 0))
684         {
685           fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
686           exit(1);
687         }
688       fclose(fp);
689       tmp = solv_free(tmp);
690     }
691
692 #ifdef ENABLE_APPDATA
693   /* appdata */
694   filename = add_appdata ? repomd_find(repo, "appdata") : 0;
695   if (filename && (fp = repomd_open(dir, filename, &tmp, 1)) != 0)
696     {
697       if (repo_add_appdata(repo, fp, 0))
698         {
699           fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
700           exit(1);
701         }
702       fclose(fp);
703       tmp = solv_free(tmp);
704     }
705 #endif
706
707   repo_internalize(repo);
708   return 0;
709 }
710
711 #else
712
713 int
714 read_rpmmd_repo(Repo *repo, const char *dir)
715 {
716   fprintf(stderr, "rpmmd repo type is not supported\n");
717   exit(1);
718 }
719
720 #endif
721
722 static void
723 usage(int status)
724 {
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"
734          );
735    exit(status);
736 }
737
738 int
739 main(int argc, char **argv)
740 {
741   int c, res;
742   int repotype = 0;
743   char *outfile = 0;
744   char *dir;
745   struct stat stb;
746   
747   Pool *pool = pool_create();
748   Repo *repo = repo_create(pool, "<repo>");
749
750   while ((c = getopt(argc, argv, "hAXRFCo:")) >= 0)
751     {
752       switch(c)
753         {
754         case 'h':
755           usage(0);
756           break;
757         case 'X':
758 #ifdef SUSE
759           add_auto = 1;
760 #endif
761           break;
762         case 'A':
763 #ifdef ENABLE_APPDATA
764           add_appdata = 1;
765 #endif
766           break;
767         case 'R':
768           repotype = REPO_PLAINDIR;
769           recursive = 1;
770           break;
771         case 'F':
772           add_filelist = 1;
773           break;
774         case 'C':
775           add_changelog = 1;
776           break;
777         case 'o':
778           outfile = optarg;
779           break;
780         default:
781           usage(1);
782           break;
783         }
784     }
785   if (optind + 1 != argc)
786     usage(1);
787   dir = argv[optind];
788   if (stat(dir, &stb))
789     {
790       perror(dir);
791       exit(1);
792     }
793   if (!S_ISDIR(stb.st_mode))
794     {
795       fprintf(stderr, "%s: not a directory\n", dir);
796       exit(1);
797     }
798   dir = solv_strdup(dir);
799   if (repotype == 0)
800     repotype = autodetect_repotype(pool, dir);
801
802   switch (repotype)
803     {
804     case REPO_RPMMD:
805       res = read_rpmmd_repo(repo, dir);
806       break;
807     case REPO_RPMMD_REPODATA:
808       dir = solv_dupappend(dir, "/repodata", 0);
809       res = read_rpmmd_repo(repo, dir);
810       break;
811     case REPO_SUSETAGS:
812       res = read_susetags_repo(repo, dir);
813       break;
814     case REPO_PLAINDIR:
815       res = read_plaindir_repo(repo, dir);
816       break;
817     default:
818       fprintf(stderr, "unknown repotype %d\n", repotype);
819       exit(1);
820     }
821   if (outfile && freopen(outfile, "w", stdout) == 0)
822     {
823       perror(outfile);
824       exit(1);
825     }
826 #ifdef SUSE
827   if (add_auto)
828     repo_add_autopattern(repo, 0);
829 #endif
830   tool_write(repo, 0, 0);
831   if (fflush(stdout))
832     {
833       perror("fflush");
834       exit(1);
835     }
836   pool_free(pool);
837   solv_free(dir);
838   exit(res);
839 }