anaconda/anaconda-40.22.3.13/utils/dd/dd_extract.c
2024-11-14 21:39:56 -08:00

266 lines
7.2 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[] = "k:d:r:vbmlfh";
static const char *usage = "Usage: dd_extract [-vbmlfh] -k <kernel> -d <directory> -r <rpm>\n";
enum {
OPT_NONE = 0,
};
static const struct option longopts[] = {
//{name, no_argument | required_argument | optional_argument, *flag, val}
{"directory", required_argument, NULL, 'd'},
{"rpm", required_argument, NULL, 'r'},
{"kernel", required_argument, NULL, 'k'},
{"verbose", no_argument, NULL, 'v'},
{"binaries", no_argument, NULL, 'b'},
{"modules", no_argument, NULL, 'm'},
{"libraries", no_argument, NULL, 'l'},
{"firmwares", no_argument, NULL, 'f'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0 }
};
static const char *options_help [][2] = {
{"directory", "Directory to extract into"},
{"rpm", "rpm to extract - must be absolute path"},
// FIXME: It seems that this argument is not used anywhere. Check and remove it.
{"kernel", "kernel version"},
{"verbose", "Verbose output"},
{"binaries", "Extract binaries"},
{"modules", "Extract modules"},
{"libraries", "Extract libraries"},
{"firmwares", "Extract firmwares"},
{"help", "Show this help"},
{NULL, NULL}
};
/**
* 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]);
}
}
/*
* during cpio extraction, only extract files we need
* eg. module .ko files and firmware directory
*/
int dlabelFilter(const char* name, const struct stat *fstat, int packageflags, void *userptr)
{
int l = strlen(name);
logMessage(DEBUGLVL, "Unpacking %s with flags %02x\n", name, packageflags);
/* unpack bin and sbin if the package was marked as installer-enhancement */
if ((packageflags & dup_binaries)) {
if(!strncmp("bin/", name, 4))
return 1;
else if (!strncmp("sbin/", name, 5))
return 1;
else if (!strncmp("usr/bin/", name, 8))
return 1;
else if (!strncmp("usr/sbin/", name, 9))
return 1;
}
/* unpack lib and lib64 if the package was marked as installer-enhancement */
if ((packageflags & dup_libraries)) {
if(!strncmp("lib/", name, 4) &&
strncmp("lib/firmware/", name, 13) &&
strncmp("lib/modules/", name, 12))
return 1;
else if (!strncmp("lib64/", name, 6))
return 1;
else if (!strncmp("usr/lib/", name, 8))
return 1;
else if (!strncmp("usr/lib64/", name, 10))
return 1;
}
/* we want firmware files */
if ((packageflags & dup_firmwares) && !strncmp("lib/firmware/", name, 13))
return 1;
/* unpack kernel modules if the package was marked as module-package */
if ((packageflags & dup_modules)) {
/* check if the file has at least three chars eg .SS */
if (l>=3) {
if (!strcmp(".ko", name+l-3))
return 1;
}
/* check if the file has at least six chars eg .SS.CC */
if (l>=6) {
if (!strcmp(".ko.gz", name+l-6))
return 1;
if (!strcmp(".ko.xz", name+l-6))
return 1;
}
/* check if the file has at least seven chars eg .SS.CCC */
if (l>=7) {
if (!strcmp(".ko.bz2", name+l-7))
return 1;
if (!strcmp(".ko.zst", name+l-7))
return 1;
}
}
/* we do not want kernel files etc. */
return 0;
}
int main(int argc, char *argv[])
{
int rc = 0;
int option;
int option_index;
char *rpm = NULL;
char *directory = NULL;
char *kernel = NULL;
int packageflags = 0;
int verbose = 0;
char *oldcwd = NULL;
while ((option = getopt_long(argc, argv, shortopts, longopts, &option_index)) != -1) {
switch (option) {
case 0:
/* long option */
break;
case 'd':
if (directory) {
logMessage(ERROR, "Multiple -d arguments\n");
show_help();
rc = 1;
goto cleanup;
}
directory = strdup(optarg);
break;
case 'k':
if (kernel) {
logMessage(ERROR, "Multiple -k arguments\n");
show_help();
rc = 1;
goto cleanup;
}
kernel = strdup(optarg);
break;
case 'r':
if (rpm) {
logMessage(ERROR, "Multiple -r arguments\n");
show_help();
rc = 1;
goto cleanup;
}
rpm = strdup(optarg);
break;
case 'v':
verbose = 1;
break;
case 'f':
packageflags |= dup_firmwares;
break;
case 'm':
packageflags |= dup_modules;
break;
case 'b':
packageflags |= dup_binaries;
break;
case 'l':
packageflags |= dup_libraries;
break;
case 'h':
show_help();
rc = 0;
goto cleanup;
}
}
if (!directory || !kernel || !rpm) {
logMessage(ERROR, "Missing argument\n");
show_help();
rc = 1;
goto cleanup;
}
if (verbose) {
printf("Extracting DUP RPM to %s\n", directory);
}
/* get current working directory */
oldcwd = getcwd(NULL, 0);
if (!oldcwd) {
logMessage(ERROR, "getcwd() failed: %m\n");
rc = 1;
goto cleanup;
}
/* set the cwd to destination */
if (chdir(directory)) {
logMessage(ERROR, "We weren't able to CWD to \"%s\": %m\n", directory);
rc = 1;
goto cleanup;
}
init_rpm();
explodeDDRPM(rpm, dlabelFilter, packageflags, kernel);
/* restore CWD */
if (chdir(oldcwd)) {
logMessage(WARNING, "We weren't able to restore CWD to \"%s\": %m\n", oldcwd);
}
cleanup:
free(directory);
free(kernel);
free(rpm);
free(oldcwd);
return rc;
}