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