distextract.c revision 229688
1218799Snwhitehorn/*- 2218799Snwhitehorn * Copyright (c) 2011 Nathan Whitehorn 3218799Snwhitehorn * All rights reserved. 4218799Snwhitehorn * 5218799Snwhitehorn * Redistribution and use in source and binary forms, with or without 6218799Snwhitehorn * modification, are permitted provided that the following conditions 7218799Snwhitehorn * are met: 8218799Snwhitehorn * 1. Redistributions of source code must retain the above copyright 9218799Snwhitehorn * notice, this list of conditions and the following disclaimer. 10218799Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 11218799Snwhitehorn * notice, this list of conditions and the following disclaimer in the 12218799Snwhitehorn * documentation and/or other materials provided with the distribution. 13218799Snwhitehorn * 14218799Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15218799Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16218799Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17218799Snwhitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18218799Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19218799Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20218799Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21218799Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22218799Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23218799Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24218799Snwhitehorn * SUCH DAMAGE. 25218799Snwhitehorn * 26218799Snwhitehorn * $FreeBSD: stable/9/usr.sbin/bsdinstall/distextract/distextract.c 229688 2012-01-06 05:48:52Z kevlo $ 27218799Snwhitehorn */ 28218799Snwhitehorn 29219617Snwhitehorn#include <sys/param.h> 30218799Snwhitehorn#include <stdio.h> 31218799Snwhitehorn#include <errno.h> 32218799Snwhitehorn#include <limits.h> 33218799Snwhitehorn#include <archive.h> 34218799Snwhitehorn#include <dialog.h> 35218799Snwhitehorn 36218799Snwhitehornstatic int extract_files(int nfiles, const char **files); 37218799Snwhitehorn 38218799Snwhitehornint 39218799Snwhitehornmain(void) 40218799Snwhitehorn{ 41218799Snwhitehorn char *diststring = strdup(getenv("DISTRIBUTIONS")); 42218799Snwhitehorn const char **dists; 43218799Snwhitehorn int i, retval, ndists = 0; 44218799Snwhitehorn for (i = 0; diststring[i] != 0; i++) 45218799Snwhitehorn if (isspace(diststring[i]) && !isspace(diststring[i+1])) 46218799Snwhitehorn ndists++; 47218799Snwhitehorn ndists++; /* Last one */ 48218799Snwhitehorn 49218799Snwhitehorn dists = calloc(ndists, sizeof(const char *)); 50218915Snwhitehorn if (dists == NULL) { 51218915Snwhitehorn fprintf(stderr, "Out of memory!\n"); 52229688Skevlo free(diststring); 53218915Snwhitehorn return (1); 54218915Snwhitehorn } 55218915Snwhitehorn 56218799Snwhitehorn for (i = 0; i < ndists; i++) 57218799Snwhitehorn dists[i] = strsep(&diststring, " \t"); 58218799Snwhitehorn 59218915Snwhitehorn init_dialog(stdin, stdout); 60218915Snwhitehorn dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer"); 61218915Snwhitehorn dlg_put_backtitle(); 62218915Snwhitehorn 63218915Snwhitehorn if (chdir(getenv("BSDINSTALL_CHROOT")) != 0) { 64218915Snwhitehorn char error[512]; 65218915Snwhitehorn sprintf(error, "Could could change to directory %s: %s\n", 66218915Snwhitehorn getenv("BSDINSTALL_DISTDIR"), strerror(errno)); 67218915Snwhitehorn dialog_msgbox("Error", error, 0, 0, TRUE); 68218915Snwhitehorn end_dialog(); 69218915Snwhitehorn return (1); 70218915Snwhitehorn } 71218915Snwhitehorn 72218799Snwhitehorn retval = extract_files(ndists, dists); 73218799Snwhitehorn 74218915Snwhitehorn end_dialog(); 75218915Snwhitehorn 76218799Snwhitehorn free(diststring); 77218799Snwhitehorn free(dists); 78218799Snwhitehorn 79218799Snwhitehorn return (retval); 80218799Snwhitehorn} 81218799Snwhitehorn 82218799Snwhitehornstatic int 83219617Snwhitehorncount_files(const char *file) 84219617Snwhitehorn{ 85219617Snwhitehorn struct archive *archive; 86219617Snwhitehorn struct archive_entry *entry; 87219617Snwhitehorn static FILE *manifest = NULL; 88219617Snwhitehorn char path[MAXPATHLEN]; 89219617Snwhitehorn char errormsg[512]; 90219617Snwhitehorn int file_count, err; 91219617Snwhitehorn 92219617Snwhitehorn if (manifest == NULL) { 93219617Snwhitehorn sprintf(path, "%s/MANIFEST", getenv("BSDINSTALL_DISTDIR")); 94219617Snwhitehorn manifest = fopen(path, "r"); 95219617Snwhitehorn } 96219617Snwhitehorn 97219617Snwhitehorn if (manifest != NULL) { 98219617Snwhitehorn char line[512]; 99219617Snwhitehorn char *tok1, *tok2; 100219618Snwhitehorn 101219618Snwhitehorn rewind(manifest); 102219617Snwhitehorn while (fgets(line, sizeof(line), manifest) != NULL) { 103219617Snwhitehorn tok2 = line; 104219617Snwhitehorn tok1 = strsep(&tok2, "\t"); 105219617Snwhitehorn if (tok1 == NULL || strcmp(tok1, file) != 0) 106219617Snwhitehorn continue; 107219617Snwhitehorn 108219617Snwhitehorn /* 109219617Snwhitehorn * We're at the right manifest line. The file count is 110219617Snwhitehorn * in the third element 111219617Snwhitehorn */ 112219617Snwhitehorn tok1 = strsep(&tok2, "\t"); 113219617Snwhitehorn tok1 = strsep(&tok2, "\t"); 114219617Snwhitehorn if (tok1 != NULL) 115219617Snwhitehorn return atoi(tok1); 116219617Snwhitehorn } 117219617Snwhitehorn } 118219617Snwhitehorn 119219617Snwhitehorn /* Either we didn't have a manifest, or this archive wasn't there */ 120219617Snwhitehorn archive = archive_read_new(); 121219617Snwhitehorn archive_read_support_format_all(archive); 122219617Snwhitehorn archive_read_support_compression_all(archive); 123219617Snwhitehorn sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), file); 124219617Snwhitehorn err = archive_read_open_filename(archive, path, 4096); 125219617Snwhitehorn if (err != ARCHIVE_OK) { 126219617Snwhitehorn snprintf(errormsg, sizeof(errormsg), 127219617Snwhitehorn "Error while extracting %s: %s\n", file, 128219617Snwhitehorn archive_error_string(archive)); 129219617Snwhitehorn dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE); 130219617Snwhitehorn return (-1); 131219617Snwhitehorn } 132219617Snwhitehorn 133219617Snwhitehorn file_count = 0; 134219617Snwhitehorn while (archive_read_next_header(archive, &entry) == ARCHIVE_OK) 135219617Snwhitehorn file_count++; 136219617Snwhitehorn archive_read_free(archive); 137219617Snwhitehorn 138219617Snwhitehorn return (file_count); 139219617Snwhitehorn} 140219617Snwhitehorn 141219617Snwhitehornstatic int 142218799Snwhitehornextract_files(int nfiles, const char **files) 143218799Snwhitehorn{ 144218799Snwhitehorn const char *items[nfiles*2]; 145218799Snwhitehorn char path[PATH_MAX]; 146218799Snwhitehorn int archive_files[nfiles]; 147218799Snwhitehorn int total_files, current_files, archive_file; 148218799Snwhitehorn struct archive *archive; 149218799Snwhitehorn struct archive_entry *entry; 150218799Snwhitehorn char errormsg[512]; 151218799Snwhitehorn char status[8]; 152218799Snwhitehorn int i, err, progress, last_progress; 153218799Snwhitehorn 154218799Snwhitehorn err = 0; 155218799Snwhitehorn progress = 0; 156218799Snwhitehorn 157218799Snwhitehorn /* Make the transfer list for dialog */ 158218799Snwhitehorn for (i = 0; i < nfiles; i++) { 159218799Snwhitehorn items[i*2] = strrchr(files[i], '/'); 160218799Snwhitehorn if (items[i*2] != NULL) 161218799Snwhitehorn items[i*2]++; 162218799Snwhitehorn else 163218799Snwhitehorn items[i*2] = files[i]; 164218799Snwhitehorn items[i*2 + 1] = "Pending"; 165218799Snwhitehorn } 166218799Snwhitehorn 167218799Snwhitehorn dialog_msgbox("", 168218799Snwhitehorn "Checking distribution archives.\nPlease wait...", 0, 0, FALSE); 169218799Snwhitehorn 170219617Snwhitehorn /* Count all the files */ 171218799Snwhitehorn total_files = 0; 172218799Snwhitehorn for (i = 0; i < nfiles; i++) { 173219617Snwhitehorn archive_files[i] = count_files(files[i]); 174219617Snwhitehorn if (archive_files[i] < 0) 175219617Snwhitehorn return (-1); 176218799Snwhitehorn total_files += archive_files[i]; 177218799Snwhitehorn } 178218799Snwhitehorn 179218799Snwhitehorn current_files = 0; 180218799Snwhitehorn 181218799Snwhitehorn for (i = 0; i < nfiles; i++) { 182218799Snwhitehorn archive = archive_read_new(); 183218799Snwhitehorn archive_read_support_format_all(archive); 184218799Snwhitehorn archive_read_support_compression_all(archive); 185218799Snwhitehorn sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]); 186218799Snwhitehorn err = archive_read_open_filename(archive, path, 4096); 187218799Snwhitehorn 188218799Snwhitehorn items[i*2 + 1] = "In Progress"; 189218799Snwhitehorn archive_file = 0; 190218799Snwhitehorn 191218799Snwhitehorn while ((err = archive_read_next_header(archive, &entry)) == 192218799Snwhitehorn ARCHIVE_OK) { 193218799Snwhitehorn last_progress = progress; 194218799Snwhitehorn progress = (current_files*100)/total_files; 195218799Snwhitehorn 196218799Snwhitehorn sprintf(status, "-%d", 197218799Snwhitehorn (archive_file*100)/archive_files[i]); 198218799Snwhitehorn items[i*2 + 1] = status; 199218799Snwhitehorn 200218799Snwhitehorn if (progress > last_progress) 201218799Snwhitehorn dialog_mixedgauge("Archive Extraction", 202218799Snwhitehorn "Extracting distribution files...", 0, 0, 203218799Snwhitehorn progress, nfiles, 204218799Snwhitehorn __DECONST(char **, items)); 205218799Snwhitehorn 206218799Snwhitehorn err = archive_read_extract(archive, entry, 207218799Snwhitehorn ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER | 208218799Snwhitehorn ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | 209218799Snwhitehorn ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS); 210218799Snwhitehorn 211218799Snwhitehorn if (err != ARCHIVE_OK) 212218799Snwhitehorn break; 213218799Snwhitehorn 214218799Snwhitehorn archive_file++; 215218799Snwhitehorn current_files++; 216218799Snwhitehorn } 217218799Snwhitehorn 218218799Snwhitehorn items[i*2 + 1] = "Done"; 219218799Snwhitehorn 220218799Snwhitehorn if (err != ARCHIVE_EOF) { 221218799Snwhitehorn snprintf(errormsg, sizeof(errormsg), 222218799Snwhitehorn "Error while extracting %s: %s\n", items[i*2], 223218799Snwhitehorn archive_error_string(archive)); 224218799Snwhitehorn items[i*2 + 1] = "Failed"; 225218799Snwhitehorn dialog_msgbox("Extract Error", errormsg, 0, 0, 226218799Snwhitehorn TRUE); 227218915Snwhitehorn return (err); 228218799Snwhitehorn } 229218799Snwhitehorn 230218799Snwhitehorn archive_read_free(archive); 231218799Snwhitehorn } 232218799Snwhitehorn 233218915Snwhitehorn return (0); 234218799Snwhitehorn} 235