- add bitmask for precise control of signature/digest verification.
[platform/upstream/rpm.git] / tools / rpmgraph.c
1 #include "system.h"
2
3 #include <rpmcli.h>
4
5 #include "rpmdb.h"
6 #include "rpmps.h"
7
8 #include "rpmte.h"
9
10 #define _RPMTS_INTERNAL         /* ts->goal, ts->dbmode, ts->suggests */
11 #include "rpmts.h"
12
13 #include "manifest.h"
14 #include "misc.h"               /* rpmGlob */
15 #include "debug.h"
16
17 static int noDeps = 1;
18 static int noChainsaw = 0;
19
20 static rpmVSFlags vsflags = 0;
21
22 static inline /*@observer@*/ const char * const identifyDepend(int_32 f)
23         /*@*/
24 {
25     if (isLegacyPreReq(f))
26         return "PreReq:";
27     f = _notpre(f);
28     if (f & RPMSENSE_SCRIPT_PRE)
29         return "Requires(pre):";
30     if (f & RPMSENSE_SCRIPT_POST)
31         return "Requires(post):";
32     if (f & RPMSENSE_SCRIPT_PREUN)
33         return "Requires(preun):";
34     if (f & RPMSENSE_SCRIPT_POSTUN)
35         return "Requires(postun):";
36     if (f & RPMSENSE_SCRIPT_VERIFY)
37         return "Requires(verify):";
38     if (f & RPMSENSE_FIND_REQUIRES)
39         return "Requires(auto):";
40     return "Requires:";
41 }
42
43 static int
44 rpmGraph(rpmts ts, struct rpmInstallArguments_s * ia, const char ** fileArgv)
45         /*@*/
46 {
47     rpmps ps;
48     const char ** pkgURL = NULL;
49     char * pkgState = NULL;
50     const char ** fnp;
51     const char * fileURL = NULL;
52     int numPkgs = 0;
53     int numFailed = 0;
54     int prevx = 0;
55     int pkgx = 0;
56     const char ** argv = NULL;
57     int argc = 0;
58     const char ** av = NULL;
59     int ac = 0;
60     int tsflags;
61     Header h;
62     rpmRC rpmrc;
63     int rc = 0;
64     rpmVSFlags ovsflags;
65     int i;
66
67     if (fileArgv == NULL)
68         return 0;
69
70     tsflags = rpmtsFlags(ts);
71     if (!noChainsaw)
72         tsflags |= RPMTRANS_FLAG_CHAINSAW;
73     (void) rpmtsSetFlags(ts, tsflags);
74
75     if (ia->qva_flags & VERIFY_DIGEST)
76         vsflags |= _RPMVSF_NODIGESTS;
77     if (ia->qva_flags & VERIFY_SIGNATURE)
78         vsflags |= _RPMVSF_NOSIGNATURES;
79     ovsflags = rpmtsSetVSFlags(ts, vsflags);
80
81     /* Build fully globbed list of arguments in argv[argc]. */
82     for (fnp = fileArgv; *fnp; fnp++) {
83         av = _free(av);
84         ac = 0;
85         rc = rpmGlob(*fnp, &ac, &av);
86         if (rc || ac == 0) continue;
87
88         argv = xrealloc(argv, (argc+2) * sizeof(*argv));
89         memcpy(argv+argc, av, ac * sizeof(*av));
90         argc += ac;
91         argv[argc] = NULL;
92     }
93     av = _free(av);     ac = 0;
94
95 restart:
96     /* Allocate sufficient storage for next set of args. */
97     if (pkgx >= numPkgs) {
98         numPkgs = pkgx + argc;
99         pkgURL = xrealloc(pkgURL, (numPkgs + 1) * sizeof(*pkgURL));
100         memset(pkgURL + pkgx, 0, ((argc + 1) * sizeof(*pkgURL)));
101         pkgState = xrealloc(pkgState, (numPkgs + 1) * sizeof(*pkgState));
102         memset(pkgState + pkgx, 0, ((argc + 1) * sizeof(*pkgState)));
103     }
104
105     /* Copy next set of args. */
106     for (i = 0; i < argc; i++) {
107         fileURL = _free(fileURL);
108         fileURL = argv[i];
109         argv[i] = NULL;
110
111         pkgURL[pkgx] = fileURL;
112         fileURL = NULL;
113         pkgx++;
114     }
115     fileURL = _free(fileURL);
116
117     /* Continue processing file arguments, building transaction set. */
118     for (fnp = pkgURL+prevx; *fnp != NULL; fnp++, prevx++) {
119         const char * fileName;
120         FD_t fd;
121
122         (void) urlPath(*fnp, &fileName);
123
124         /* Try to read the header from a package file. */
125         fd = Fopen(*fnp, "r.ufdio");
126         if (fd == NULL || Ferror(fd)) {
127             rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), *fnp,
128                         Fstrerror(fd));
129             if (fd) {
130                 Fclose(fd);
131                 fd = NULL;
132             }
133             numFailed++; *fnp = NULL;
134             continue;
135         }
136
137         /* Read the header, verifying signatures (if present). */
138         ovsflags = rpmtsSetVSFlags(ts, vsflags);
139         rpmrc = rpmReadPackageFile(ts, fd, *fnp, &h);
140         ovsflags = rpmtsSetVSFlags(ts, ovsflags);
141         Fclose(fd);
142         fd = NULL;
143
144         if (rpmrc == RPMRC_FAIL || rpmrc == RPMRC_SHORTREAD) {
145             numFailed++; *fnp = NULL;
146             continue;
147         }
148
149         if (rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE) {
150             rc = rpmtsAddInstallElement(ts, h, (fnpyKey)fileName, 0, NULL);
151             h = headerFree(h); 
152             continue;
153         }
154
155         if (rpmrc != RPMRC_NOTFOUND) {
156             rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), *fnp);
157             numFailed++; *fnp = NULL;
158             break;
159         }
160
161         /* Try to read a package manifest. */
162         fd = Fopen(*fnp, "r.fpio");
163         if (fd == NULL || Ferror(fd)) {
164             rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), *fnp,
165                         Fstrerror(fd));
166             if (fd) {
167                 Fclose(fd);
168                 fd = NULL;
169             }
170             numFailed++; *fnp = NULL;
171             break;
172         }
173
174         /* Read list of packages from manifest. */
175         rc = rpmReadPackageManifest(fd, &argc, &argv);
176         if (rc)
177             rpmError(RPMERR_MANIFEST, _("%s: read manifest failed: %s\n"),
178                         fileURL, Fstrerror(fd));
179         Fclose(fd);
180         fd = NULL;
181
182         /* If successful, restart the query loop. */
183         if (rc == 0) {
184             prevx++;
185             goto restart;
186         }
187
188         numFailed++; *fnp = NULL;
189         break;
190     }
191
192     if (numFailed > 0) goto exit;
193
194     if (!noDeps) {
195         rc = rpmtsCheck(ts);
196         if (rc) {
197             numFailed += numPkgs;
198             goto exit;
199         }
200         ps = rpmtsProblems(ts);
201         if (rpmpsNumProblems(ps) > 0) {
202             rpmMessage(RPMMESS_ERROR, _("Failed dependencies:\n"));
203             rpmpsPrint(NULL, ps);
204             numFailed += numPkgs;
205
206             /*@-branchstate@*/
207             if (ts->suggests != NULL && ts->nsuggests > 0) {
208                 rpmMessage(RPMMESS_NORMAL, _("    Suggested resolutions:\n"));
209                 for (i = 0; i < ts->nsuggests; i++) {
210                     const char * str = ts->suggests[i];
211
212                     if (str == NULL)
213                         break;
214
215                     rpmMessage(RPMMESS_NORMAL, "\t%s\n", str);
216                     ts->suggests[i] = NULL;
217                     str = _free(str);
218                 }
219                 ts->suggests = _free(ts->suggests);
220             }
221             /*@=branchstate@*/
222         }
223         ps = rpmpsFree(ps);
224     }
225
226     if (numFailed > 0) goto exit;
227
228     rc = rpmtsOrder(ts);
229     if (rc)
230         goto exit;
231
232     {   rpmtsi pi;
233         rpmte p;
234         rpmte q;
235         unsigned char * selected =
236                         alloca(sizeof(*selected) * (rpmtsNElements(ts) + 1));
237         int oType = TR_ADDED;
238
239         fprintf(stdout, "digraph XXX {\n");
240
241         fprintf(stdout, "  rankdir=LR\n");
242
243         fprintf(stdout, "//===== Packages:\n");
244         pi = rpmtsiInit(ts);
245         while ((p = rpmtsiNext(pi, oType)) != NULL) {
246             fprintf(stdout, "//%5d%5d %s\n", rpmteTree(p), rpmteDepth(p), rpmteN(p));
247             q = rpmteParent(p);
248             if (q != NULL)
249                 fprintf(stdout, "  \"%s\" -> \"%s\"\n", rpmteN(p), rpmteN(q));
250             else {
251                 fprintf(stdout, "  \"%s\"\n", rpmteN(p));
252                 fprintf(stdout, "  { rank=max ; \"%s\" }\n", rpmteN(p));
253             }
254         }
255         pi = rpmtsiFree(pi);
256
257         fprintf(stdout, "}\n");
258     }
259
260     rc = 0;
261
262 exit:
263     for (i = 0; i < numPkgs; i++)
264         pkgURL[i] = _free(pkgURL[i]);
265     pkgState = _free(pkgState);
266     pkgURL = _free(pkgURL);
267     argv = _free(argv);
268
269     return rc;
270 }
271
272 static struct poptOption optionsTable[] = {
273  { "check", '\0', POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &noDeps, 0,
274         N_("don't verify package dependencies"), NULL },
275  { "nolegacy", '\0', POPT_BIT_SET,      &vsflags, RPMVSF_NEEDPAYLOAD,
276         N_("don't verify header+payload signature"), NULL },
277
278  { "nochainsaw", '\0', POPT_ARGFLAG_DOC_HIDDEN, &noChainsaw, 0,
279         NULL, NULL},
280
281  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
282         N_("Common options for all rpm modes and executables:"),
283         NULL }, 
284
285    POPT_AUTOALIAS
286    POPT_AUTOHELP
287    POPT_TABLEEND
288 };
289
290 int
291 main(int argc, char *const argv[])
292 {
293     rpmts ts = NULL;
294     struct rpmInstallArguments_s * ia = &rpmIArgs;
295     poptContext optCon;
296     int ec = 0;
297
298     optCon = rpmcliInit(argc, argv, optionsTable);
299     if (optCon == NULL)
300         exit(EXIT_FAILURE);
301
302     ts = rpmtsCreate();
303     if (rpmcliQueryFlags & VERIFY_DIGEST)
304         vsflags |= _RPMVSF_NODIGESTS;
305     if (rpmcliQueryFlags & VERIFY_SIGNATURE)
306         vsflags |= _RPMVSF_NOSIGNATURES;
307     if (rpmcliQueryFlags & VERIFY_HDRCHK)
308         vsflags |= RPMVSF_NOHDRCHK;
309     (void) rpmtsSetVSFlags(ts, vsflags);
310
311     ec = rpmGraph(ts, ia, poptGetArgs(optCon));
312
313     ts = rpmtsFree(ts);
314
315     optCon = rpmcliFini(optCon);
316
317     return ec;
318 }