/* * 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 . * * Author(s): Martin Sivak * Brian C. Lane */ #include "config.h" #include #include #include #include #include #include #include "rpmutils.h" #include "dd_utils.h" static const char shortopts[] = "k:d:r:vbmlfh"; static const char *usage = "Usage: dd_extract [-vbmlfh] -k -d -r \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"}, {"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)) 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; /* we do not want kernel files */ if (!(packageflags & dup_modules)) return 0; /* check if the file has at least four chars eg X.SS */ if (l<3) return 0; l-=3; /* and we want only .ko files here */ if (strcmp(".ko", name+l)) return 0; /* we are unpacking kernel module.. */ return 1; } 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': directory = strdup(optarg); break; case 'k': kernel = strdup(optarg); break; case 'r': 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; }