324 lines
7.0 KiB
C
324 lines
7.0 KiB
C
#include "system.h"
|
|
const char *__progname;
|
|
|
|
#include <rpmlib.h>
|
|
#include <rpmmacro.h>
|
|
#include <rpmurl.h>
|
|
|
|
#include "rpmdb.h"
|
|
#include "rpmps.h"
|
|
#include "rpmte.h"
|
|
#include "rpmts.h"
|
|
|
|
#include "manifest.h"
|
|
#include "misc.h"
|
|
#include "debug.h"
|
|
|
|
static int _depends_debug;
|
|
|
|
static int noAvailable = 1;
|
|
#ifdef DYING
|
|
static const char * avdbpath =
|
|
"/usr/lib/rpmdb/%{_arch}-%{_vendor}-%{_os}/redhat";
|
|
#endif
|
|
static int noDeps = 0;
|
|
|
|
static inline const char * identifyDepend(int_32 f)
|
|
{
|
|
if (isLegacyPreReq(f))
|
|
return "PreReq:";
|
|
f = _notpre(f);
|
|
if (f & RPMSENSE_SCRIPT_PRE)
|
|
return "Requires(pre):";
|
|
if (f & RPMSENSE_SCRIPT_POST)
|
|
return "Requires(post):";
|
|
if (f & RPMSENSE_SCRIPT_PREUN)
|
|
return "Requires(preun):";
|
|
if (f & RPMSENSE_SCRIPT_POSTUN)
|
|
return "Requires(postun):";
|
|
if (f & RPMSENSE_SCRIPT_VERIFY)
|
|
return "Requires(verify):";
|
|
if (f & RPMSENSE_FIND_REQUIRES)
|
|
return "Requires(auto):";
|
|
return "Requires:";
|
|
}
|
|
|
|
static int
|
|
do_tsort(const char *fileArgv[])
|
|
{
|
|
rpmts ts = NULL;
|
|
const char ** pkgURL = NULL;
|
|
char * pkgState = NULL;
|
|
const char ** fnp;
|
|
const char * fileURL = NULL;
|
|
int numPkgs = 0;
|
|
int numFailed = 0;
|
|
int prevx;
|
|
int pkgx;
|
|
const char ** argv = NULL;
|
|
int argc = 0;
|
|
const char ** av = NULL;
|
|
int ac = 0;
|
|
Header h;
|
|
int rc = 0;
|
|
int i;
|
|
|
|
if (fileArgv == NULL)
|
|
return 0;
|
|
|
|
ts = rpmtsCreate();
|
|
|
|
rc = rpmtsOpenDB(ts, O_RDONLY);
|
|
if (rc) {
|
|
rpmlog(RPMMESS_ERROR, _("cannot open Packages database\n"));
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
#ifdef DYING
|
|
/* Load all the available packages. */
|
|
if (!(noDeps || noAvailable)) {
|
|
rpmdbMatchIterator mi = NULL;
|
|
struct rpmdb_s * avdb = NULL;
|
|
const char * rootdir = "/";
|
|
|
|
addMacro(NULL, "_dbpath", NULL, avdbpath, RMIL_CMDLINE);
|
|
rc = rpmdbOpen(rootdir, &avdb, O_RDONLY, 0644);
|
|
delMacro(NULL, "_dbpath");
|
|
if (rc) {
|
|
rpmlog(RPMMESS_ERROR, _("cannot open Available database\n"));
|
|
goto endavail;
|
|
}
|
|
mi = rpmdbInitIterator(avdb, RPMDBI_PACKAGES, NULL, 0);
|
|
while ((h = rpmdbNextIterator(mi)) != NULL) {
|
|
rpmtsAvailablePackage(ts, h, NULL);
|
|
}
|
|
|
|
endavail:
|
|
if (mi) rpmdbFreeIterator(mi);
|
|
if (avdb) rpmdbClose(avdb);
|
|
}
|
|
#endif
|
|
|
|
/* Build fully globbed list of arguments in argv[argc]. */
|
|
for (fnp = fileArgv; *fnp; fnp++) {
|
|
av = _free(av);
|
|
ac = 0;
|
|
rc = rpmGlob(*fnp, &ac, &av);
|
|
if (rc || ac == 0) continue;
|
|
|
|
argv = (argc == 0)
|
|
? xmalloc((argc+2) * sizeof(*argv))
|
|
: xrealloc(argv, (argc+2) * sizeof(*argv));
|
|
memcpy(argv+argc, av, ac * sizeof(*av));
|
|
argc += ac;
|
|
argv[argc] = NULL;
|
|
}
|
|
av = _free(av);
|
|
|
|
numPkgs = 0;
|
|
prevx = 0;
|
|
pkgx = 0;
|
|
|
|
restart:
|
|
/* Allocate sufficient storage for next set of args. */
|
|
if (pkgx >= numPkgs) {
|
|
numPkgs = pkgx + argc;
|
|
pkgURL = (pkgURL == NULL)
|
|
? xmalloc( (numPkgs + 1) * sizeof(*pkgURL))
|
|
: xrealloc(pkgURL, (numPkgs + 1) * sizeof(*pkgURL));
|
|
memset(pkgURL + pkgx, 0, ((argc + 1) * sizeof(*pkgURL)));
|
|
pkgState = (pkgState == NULL)
|
|
? xmalloc( (numPkgs + 1) * sizeof(*pkgState))
|
|
: xrealloc(pkgState, (numPkgs + 1) * sizeof(*pkgState));
|
|
memset(pkgState + pkgx, 0, ((argc + 1) * sizeof(*pkgState)));
|
|
}
|
|
|
|
/* Copy next set of args. */
|
|
for (i = 0; i < argc; i++) {
|
|
fileURL = _free(fileURL);
|
|
fileURL = argv[i];
|
|
argv[i] = NULL;
|
|
pkgURL[pkgx] = fileURL;
|
|
fileURL = NULL;
|
|
pkgx++;
|
|
}
|
|
fileURL = _free(fileURL);
|
|
|
|
/* Continue processing file arguments, building transaction set. */
|
|
for (fnp = pkgURL+prevx; *fnp; fnp++, prevx++) {
|
|
const char * fileName;
|
|
FD_t fd;
|
|
|
|
(void) urlPath(*fnp, &fileName);
|
|
|
|
/* Try to read the header from a package file. */
|
|
fd = Fopen(*fnp, "r.ufdio");
|
|
if (fd == NULL || Ferror(fd)) {
|
|
rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), *fnp,
|
|
Fstrerror(fd));
|
|
if (fd) Fclose(fd);
|
|
numFailed++; *fnp = NULL;
|
|
continue;
|
|
}
|
|
|
|
rc = rpmReadPackageFile(ts, fd, *fnp, &h);
|
|
Fclose(fd);
|
|
|
|
if (rc == RPMRC_OK) {
|
|
rc = rpmtsAddInstallElement(ts, h, (fnpyKey)fileName, 0, NULL);
|
|
h = headerFree(h);
|
|
continue;
|
|
}
|
|
|
|
if (rc != RPMRC_NOTFOUND) {
|
|
rpmlog(RPMMESS_ERROR, _("%s cannot be installed\n"), *fnp);
|
|
numFailed++; *fnp = NULL;
|
|
break;
|
|
}
|
|
|
|
/* Try to read a package manifest. */
|
|
fd = Fopen(*fnp, "r.fpio");
|
|
if (fd == NULL || Ferror(fd)) {
|
|
rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), *fnp,
|
|
Fstrerror(fd));
|
|
if (fd) Fclose(fd);
|
|
numFailed++; *fnp = NULL;
|
|
break;
|
|
}
|
|
|
|
/* Read list of packages from manifest. */
|
|
rc = rpmReadPackageManifest(fd, &argc, &argv);
|
|
if (rc)
|
|
rpmError(RPMERR_MANIFEST, _("%s: read manifest failed: %s\n"),
|
|
fileURL, Fstrerror(fd));
|
|
Fclose(fd);
|
|
|
|
/* If successful, restart the query loop. */
|
|
if (rc == 0) {
|
|
prevx++;
|
|
goto restart;
|
|
}
|
|
|
|
numFailed++; *fnp = NULL;
|
|
break;
|
|
}
|
|
|
|
if (numFailed) goto exit;
|
|
|
|
if (!noDeps) {
|
|
rpmps ps;
|
|
|
|
rc = rpmtsCheck(ts);
|
|
|
|
ps = rpmtsProblems(ts);
|
|
if (ps) {
|
|
rpmlog(RPMMESS_ERROR, _("Failed dependencies:\n"));
|
|
rpmpsPrint(NULL, ps);
|
|
ps = rpmpsFree(ps);
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
ps = rpmpsFree(ps);
|
|
}
|
|
|
|
rc = rpmtsOrder(ts);
|
|
if (rc)
|
|
goto exit;
|
|
|
|
{ rpmtsi pi;
|
|
rpmte p;
|
|
rpmte q;
|
|
int oType = TR_ADDED;
|
|
|
|
fprintf(stdout, "digraph XXX {\n");
|
|
|
|
fprintf(stdout, " rankdir=LR\n");
|
|
|
|
fprintf(stdout, "//===== Packages:\n");
|
|
pi = rpmtsiInit(ts);
|
|
while ((p = rpmtsiNext(pi, oType)) != NULL) {
|
|
fprintf(stdout, "//%5d%5d %s\n", rpmteTree(p), rpmteDepth(p), rpmteN(p));
|
|
q = rpmteParent(p);
|
|
if (q != NULL)
|
|
fprintf(stdout, " \"%s\" -> \"%s\"\n", rpmteN(p), rpmteN(q));
|
|
else {
|
|
fprintf(stdout, " \"%s\"\n", rpmteN(p));
|
|
fprintf(stdout, " { rank=max ; \"%s\" }\n", rpmteN(p));
|
|
}
|
|
}
|
|
pi = rpmtsiFree(pi);
|
|
|
|
fprintf(stdout, "}\n");
|
|
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
exit:
|
|
for (i = 0; i < numPkgs; i++) {
|
|
pkgURL[i] = _free(pkgURL[i]);
|
|
}
|
|
pkgState = _free(pkgState);
|
|
pkgURL = _free(pkgURL);
|
|
argv = _free(argv);
|
|
|
|
ts = rpmtsFree(ts);
|
|
return rc;
|
|
}
|
|
|
|
static struct poptOption optionsTable[] = {
|
|
{ "noavailable", '\0', 0, &noAvailable, 0, NULL, NULL},
|
|
{ "nodeps", '\0', 0, &noDeps, 0, NULL, NULL},
|
|
{ "verbose", 'v', 0, 0, 'v', NULL, NULL},
|
|
{ NULL, 0, 0, 0, 0, NULL, NULL}
|
|
};
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
poptContext optCon;
|
|
const char * optArg;
|
|
int arg;
|
|
int ec = 0;
|
|
|
|
#if HAVE_MCHECK_H && HAVE_MTRACE
|
|
mtrace(); /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */
|
|
#endif
|
|
setprogname(argv[0]); /* Retrofit glibc __progname */
|
|
#if defined(ENABLE_NLS)
|
|
(void)setlocale(LC_ALL, "" );
|
|
|
|
(void)bindtextdomain(PACKAGE, LOCALEDIR);
|
|
(void)textdomain(PACKAGE);
|
|
#endif
|
|
|
|
_depends_debug = 1;
|
|
|
|
optCon = poptGetContext("rpmsort", argc, argv, optionsTable, 0);
|
|
#if RPM_USES_POPTREADDEFAULTCONFIG
|
|
poptReadDefaultConfig(optCon, 1);
|
|
#endif
|
|
|
|
while ((arg = poptGetNextOpt(optCon)) > 0) {
|
|
optArg = poptGetOptArg(optCon);
|
|
switch (arg) {
|
|
case 'v':
|
|
rpmIncreaseVerbosity();
|
|
break;
|
|
default:
|
|
fprintf(stderr, _("unknown popt return (%d)"), arg);
|
|
exit(EXIT_FAILURE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
rpmReadConfigFiles(NULL, NULL);
|
|
|
|
ec = do_tsort(poptGetArgs(optCon));
|
|
|
|
optCon = poptFreeContext(optCon);
|
|
|
|
return ec;
|
|
}
|