281 lines
7.4 KiB
C
281 lines
7.4 KiB
C
/*
|
|
* Copyright (C) 2011-2013 Red Hat, Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <getopt.h>
|
|
#include <glob.h>
|
|
|
|
#include "rpmutils.h"
|
|
#include "dd_utils.h"
|
|
|
|
static const char shortopts[] = "a:d:k:v";
|
|
static const char *usage = "Usage: dd_list [-vh] -k <kernel> -d <directory> -a <anaconda>\n";
|
|
|
|
enum {
|
|
OPT_NONE = 0,
|
|
};
|
|
|
|
static const struct option longopts[] = {
|
|
//{name, no_argument | required_argument | optional_argument, *flag, val}
|
|
{"directory", required_argument, NULL, 'd'},
|
|
{"kernel", required_argument, NULL, 'k'},
|
|
{"anaconda", required_argument, NULL, 'a'},
|
|
{"verbose", no_argument, NULL, 'v'},
|
|
{"help", no_argument, NULL, 'h'},
|
|
{NULL, 0, NULL, 0}
|
|
};
|
|
|
|
static const char *options_help [][2] = {
|
|
{"directory", "Directory to search for *.rpm files"},
|
|
{"kernel", "kernel version"},
|
|
{"anaconda", "anaconda version"},
|
|
{"verbose", "Verbose output"},
|
|
{"help", "Show this help"},
|
|
{NULL, NULL}
|
|
};
|
|
|
|
struct _version_struct {
|
|
char* kernel;
|
|
char* anaconda;
|
|
};
|
|
|
|
int globErrFunc(const char *epath, int eerrno)
|
|
{
|
|
/* TODO check fatal errors */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Show the available options and their help strings
|
|
*/
|
|
void show_help() {
|
|
int i;
|
|
|
|
printf("%s", usage);
|
|
for (i=0; options_help[i][0]; i++) {
|
|
printf(" -%c, --%-20s %s\n", options_help[i][0][0],
|
|
options_help[i][0],
|
|
options_help[i][1]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* check if the RPM in question provides
|
|
* Provides: <dep> = <version>
|
|
* we use it to check if kernel-modules = <kernel version>
|
|
* and installer-enhancement = <anaconda version>
|
|
*/
|
|
int dlabelProvides(const char* dep, const char* version, uint32_t sense, void *userptr)
|
|
{
|
|
char *kernelver = ((struct _version_struct*)userptr)->kernel;
|
|
char *anacondaver = ((struct _version_struct*)userptr)->anaconda;
|
|
|
|
int packageflags = 0;
|
|
|
|
if (version == NULL) {
|
|
logMessage(DEBUGLVL, "Provides does not have version specified!");
|
|
return 0;
|
|
}
|
|
|
|
logMessage(DEBUGLVL, "Provides: %s = %s\n", dep, version);
|
|
|
|
/* is it a modules package? */
|
|
if (!strcmp(dep, "kernel-modules")) {
|
|
|
|
/*
|
|
* exception for 6.0 and 6.1 DDs, we changed the logic a bit and need to maintain compatibility.
|
|
*/
|
|
if ((!strncmp(version, "2.6.32-131", 10)) || (!strncmp(version, "2.6.32-71", 9)))
|
|
packageflags |= dup_modules | dup_firmwares;
|
|
|
|
/*
|
|
* Use this package only if the version match string is true for this kernel version
|
|
*/
|
|
if (!matchVersions(kernelver, sense, version))
|
|
packageflags |= dup_modules | dup_firmwares;
|
|
}
|
|
|
|
/* is it an app package? */
|
|
if (!strcmp(dep, "installer-enhancement")) {
|
|
|
|
/*
|
|
* If the version string matches anaconda version, unpack binaries to /tmp/DD
|
|
*/
|
|
if (!matchVersions(anacondaver, sense, version))
|
|
packageflags |= dup_binaries | dup_libraries;
|
|
}
|
|
|
|
return packageflags;
|
|
}
|
|
|
|
/**
|
|
* Print information about the rpm to stdout
|
|
*/
|
|
int dlabelOK(const char* source, Header *h, int packageflags)
|
|
{
|
|
struct rpmtd_s tdname;
|
|
struct rpmtd_s tddesc;
|
|
|
|
const char *name;
|
|
const char *description;
|
|
|
|
if (!headerGet(*h, RPMTAG_NAME, &tdname, HEADERGET_MINMEM))
|
|
return 0;
|
|
|
|
if (!headerGet(*h, RPMTAG_DESCRIPTION, &tddesc, HEADERGET_MINMEM)){
|
|
rpmtdFreeData(&tdname);
|
|
return 0;
|
|
}
|
|
|
|
/* iterator */
|
|
name = rpmtdNextString(&tdname);
|
|
description = rpmtdNextString(&tddesc);
|
|
|
|
fprintf(stdout, "%s\n%s\n", source, name);
|
|
|
|
if (packageflags & dup_modules) fprintf(stdout, "modules ");
|
|
if (packageflags & dup_firmwares) fprintf(stdout, "firmwares ");
|
|
if (packageflags & dup_binaries) fprintf(stdout, "binaries ");
|
|
if (packageflags & dup_libraries) fprintf(stdout, "libraries ");
|
|
|
|
fprintf(stdout, "\n%s\n---\n", description);
|
|
|
|
rpmtdFreeData(&tdname);
|
|
rpmtdFreeData(&tddesc);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int rc = 0;
|
|
int option;
|
|
int option_index;
|
|
|
|
char *path = NULL;
|
|
int path_len;
|
|
int verbose = 0;
|
|
|
|
struct _version_struct versions = {NULL, NULL};
|
|
|
|
char *globpattern;
|
|
glob_t globres;
|
|
char** globitem;
|
|
|
|
while ((option = getopt_long(argc, argv, shortopts, longopts, &option_index)) != -1) {
|
|
switch (option) {
|
|
case 0:
|
|
/* long option */
|
|
break;
|
|
|
|
case 'd':
|
|
if (path) {
|
|
logMessage(ERROR, "Multiple -d arguments\n");
|
|
show_help();
|
|
rc = 1;
|
|
goto cleanup;
|
|
}
|
|
path = strdup(optarg);
|
|
break;
|
|
|
|
case 'k':
|
|
if (versions.kernel) {
|
|
logMessage(ERROR, "Multiple -k arguments\n");
|
|
show_help();
|
|
rc = 1;
|
|
goto cleanup;
|
|
}
|
|
versions.kernel = strdup(optarg);
|
|
break;
|
|
|
|
case 'a':
|
|
if (versions.anaconda) {
|
|
logMessage(ERROR, "Multiple -a arguments\n");
|
|
show_help();
|
|
rc = 1;
|
|
goto cleanup;
|
|
}
|
|
versions.anaconda = strdup(optarg);
|
|
break;
|
|
|
|
case 'v':
|
|
verbose = 1;
|
|
break;
|
|
|
|
case 'h':
|
|
show_help();
|
|
rc = 0;
|
|
goto cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
if (!path || !versions.kernel || !versions.anaconda) {
|
|
show_help();
|
|
rc = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
init_rpm();
|
|
|
|
path_len = strlen(path);
|
|
|
|
/* determine if the path is rpm filename or directory */
|
|
if ((path_len > 5) && (strcmp(path + path_len - 4, ".rpm") == 0)) {
|
|
if (verbose) {
|
|
/* careful - standard output is being parsed */
|
|
printf("Listing DD file %s\n", path);
|
|
}
|
|
|
|
checkDDRPM(path, dlabelProvides, NULL, dlabelOK, &versions);
|
|
|
|
} else {
|
|
if (verbose) {
|
|
/* careful - standard output is being parsed */
|
|
printf("Listing DD dir %s\n", path);
|
|
}
|
|
|
|
/* look for all .rpm files in a given direcory */
|
|
checked_asprintf(&globpattern, "%s/*.rpm", path);
|
|
|
|
if (!glob(globpattern, GLOB_NOSORT|GLOB_NOESCAPE, globErrFunc, &globres)) {
|
|
/* iterate over all rpm files */
|
|
globitem = globres.gl_pathv;
|
|
while (globres.gl_pathc>0 && globitem != NULL && *globitem != NULL) {
|
|
checkDDRPM(*globitem, dlabelProvides, NULL, dlabelOK, &versions);
|
|
globitem++;
|
|
}
|
|
globfree(&globres);
|
|
/* end of iteration */
|
|
}
|
|
free(globpattern);
|
|
}
|
|
|
|
cleanup:
|
|
free(path);
|
|
free(versions.kernel);
|
|
free(versions.anaconda);
|
|
|
|
return rc;
|
|
}
|