1 /*
2  * Copyright (c) 2007, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7 
8 /*
9  * rpmdb2solv
10  *
11  * Reads rpm database (and evtl. more, like product metadata) to build
12  * a .solv file of 'installed' solvables.
13  * Writes .solv to stdout
14  *
15  */
16 
17 #include <sys/types.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 
23 #ifdef ENABLE_RPMDB_LIBRPM
24 #include <rpm/rpmmacro.h>
25 #endif
26 
27 
28 #include "pool.h"
29 #include "repo.h"
30 #include "repo_rpmdb.h"
31 #ifdef ENABLE_PUBKEY
32 #include "repo_pubkey.h"
33 #endif
34 #include "repo_products.h"
35 #include "repo_solv.h"
36 #include "common_write.h"
37 #ifdef ENABLE_APPDATA
38 #include "repo_appdata.h"
39 #endif
40 #ifdef SUSE
41 #include "repo_autopattern.h"
42 #endif
43 
44 
45 static void
usage(int status)46 usage(int status)
47 {
48   fprintf(stderr, "\nUsage:\n"
49 	  "rpmdb2solv [-P] [-C] [-n] [-b <basefile>] [-p <productsdir>] [-r <root>]\n"
50 	  " -n : No packages, do not read rpmdb, useful to only parse products\n"
51 	  " -p <productsdir> : Scan <productsdir> for .prod files, representing installed products\n"
52 	  " -r <root> : Prefix rpmdb path and <productsdir> with <root>\n"
53 	  " -o <solv> : Write .solv to file instead of stdout\n"
54           " -P : print percentage done\n"
55           " -C : include the changelog\n"
56 	 );
57   exit(status);
58 }
59 
60 
61 int
main(int argc,char ** argv)62 main(int argc, char **argv)
63 {
64   FILE *reffp = 0;
65   Pool *pool = pool_create();
66   Repo *repo;
67   Repodata *data;
68   int c, percent = 0;
69   int nopacks = 0;
70   int add_changelog = 0;
71   const char *root = 0;
72   const char *dbpath = 0;
73   const char *refname = 0;
74 #ifdef ENABLE_SUSEREPO
75   char *proddir = 0;
76 #endif
77   char *outfile = 0;
78 #ifdef ENABLE_PUBKEY
79   int pubkeys = 0;
80 #endif
81 #ifdef ENABLE_APPDATA
82   int add_appdata = 0;
83 #endif
84 #ifdef SUSE
85   int add_auto = 0;
86 #endif
87 
88   /*
89    * parse arguments
90    */
91 
92   while ((c = getopt(argc, argv, "ACD:PhnkxXr:p:o:")) >= 0)
93     switch (c)
94       {
95       case 'h':
96 	  usage(0);
97 	break;
98       case 'r':
99         root = optarg;
100         break;
101       case 'D':
102         dbpath = optarg;
103         break;
104       case 'n':
105 	nopacks = 1;
106 	break;
107       case 'P':
108 	percent = 1;
109 	break;
110       case 'p':
111 #ifdef ENABLE_SUSEREPO
112 	proddir = optarg;
113 #endif
114 	break;
115       case 'x':
116         break;	/* extrapool no longer supported */
117       case 'X':
118 #ifdef SUSE
119 	add_auto = 1;
120 #endif
121 	break;
122       case 'A':
123 #ifdef ENABLE_APPDATA
124 	add_appdata = 1;
125 #endif
126 	break;
127       case 'o':
128         outfile = optarg;
129         break;
130 #ifdef ENABLE_PUBKEY
131       case 'k':
132         nopacks = 1;
133         pubkeys = 1;
134         break;
135 #endif
136       case 'C':
137 	add_changelog = 1;
138 	break;
139       default:
140 	usage(1);
141       }
142 
143   if (outfile && !freopen(outfile, "w", stdout))
144     {
145       perror(outfile);
146       exit(1);
147     }
148 
149   /*
150    * optional arg is old version of rpmdb solv file
151    * should make this a real option instead
152    */
153 
154   if (optind < argc)
155     refname = argv[optind];
156 
157   if (refname && !nopacks)
158     {
159       if ((reffp = fopen(refname, "r")) == NULL)
160         perror(refname);
161     }
162 
163   /*
164    * create 'installed' repository
165    * add products
166    * add rpmdb
167    * write .solv
168    */
169 
170   if (root && *root)
171     pool_set_rootdir(pool, root);
172 #ifdef ENABLE_PUBKEY
173   if (dbpath && *dbpath && (!nopacks || pubkeys))
174 #else
175   if (dbpath && *dbpath && !nopacks)
176 #endif
177     {
178 #ifdef ENABLE_RPMDB_LIBRPM
179       char *macro = solv_dupjoin("_dbpath ", dbpath, 0);
180       rpmDefineMacro(NULL, macro, 0);
181       free(macro);
182 #else
183       fprintf(stderr, "cannot set dbpath without librpm\n");
184       exit(1);
185 #endif
186     }
187 
188   repo = repo_create(pool, "installed");
189   data = repo_add_repodata(repo, 0);
190 
191   if (!nopacks)
192     {
193       int flags = REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE;
194       if (percent)
195 	flags |= RPMDB_REPORT_PROGRESS;
196       if (add_changelog)
197 	flags |= RPM_ADD_WITH_CHANGELOG;
198       if (repo_add_rpmdb_reffp(repo, reffp, flags))
199 	{
200 	  fprintf(stderr, "rpmdb2solv: %s\n", pool_errstr(pool));
201 	  exit(1);
202 	}
203     }
204 #ifdef ENABLE_PUBKEY
205   if (pubkeys)
206     {
207       if (repo_add_rpmdb_pubkeys(repo, REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | ADD_WITH_KEYSIGNATURES))
208 	{
209 	  fprintf(stderr, "rpmdb2solv: %s\n", pool_errstr(pool));
210 	  exit(1);
211 	}
212     }
213 #endif
214 
215 #ifdef ENABLE_SUSEREPO
216   if (proddir && *proddir)
217     {
218       if (root && *root)
219 	{
220 	  int rootlen = strlen(root);
221 	  if (!strncmp(root, proddir, rootlen))
222 	    {
223 	      proddir += rootlen;
224 	      if (*proddir != '/' && proddir[-1] == '/')
225 		proddir--;
226 	    }
227 	}
228       if (repo_add_products(repo, proddir, REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
229 	{
230 	  fprintf(stderr, "rpmdb2solv: %s\n", pool_errstr(pool));
231 	  exit(1);
232 	}
233     }
234 #endif
235 
236 #ifdef ENABLE_APPDATA
237   if (add_appdata)
238     {
239       repo_add_appdata_dir(repo, "/usr/share/metainfo", REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | APPDATA_SEARCH_UNINTERNALIZED_FILELIST);
240       repo_add_appdata_dir(repo, "/usr/share/appdata", REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | APPDATA_SEARCH_UNINTERNALIZED_FILELIST);
241     }
242 #endif
243   repodata_internalize(data);
244 
245   if (reffp)
246     fclose(reffp);
247 
248 #ifdef SUSE
249   if (add_auto)
250     repo_add_autopattern(repo, ADD_NO_AUTOPRODUCTS);
251 #endif
252 
253   tool_write(repo, stdout);
254   pool_free(pool);
255   exit(0);
256 }
257