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