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$ 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{ 41232433Snwhitehorn char *diststring; 42218799Snwhitehorn const char **dists; 43218799Snwhitehorn int i, retval, ndists = 0; 44232433Snwhitehorn 45232433Snwhitehorn if (getenv("DISTRIBUTIONS") == NULL) { 46232433Snwhitehorn fprintf(stderr, "DISTRIBUTIONS variable is not set\n"); 47232433Snwhitehorn return (1); 48232433Snwhitehorn } 49232433Snwhitehorn 50232433Snwhitehorn diststring = strdup(getenv("DISTRIBUTIONS")); 51218799Snwhitehorn for (i = 0; diststring[i] != 0; i++) 52218799Snwhitehorn if (isspace(diststring[i]) && !isspace(diststring[i+1])) 53218799Snwhitehorn ndists++; 54218799Snwhitehorn ndists++; /* Last one */ 55218799Snwhitehorn 56218799Snwhitehorn dists = calloc(ndists, sizeof(const char *)); 57218915Snwhitehorn if (dists == NULL) { 58218915Snwhitehorn fprintf(stderr, "Out of memory!\n"); 59229688Skevlo free(diststring); 60218915Snwhitehorn return (1); 61218915Snwhitehorn } 62218915Snwhitehorn 63218799Snwhitehorn for (i = 0; i < ndists; i++) 64218799Snwhitehorn dists[i] = strsep(&diststring, " \t"); 65218799Snwhitehorn 66218915Snwhitehorn init_dialog(stdin, stdout); 67218915Snwhitehorn dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer"); 68218915Snwhitehorn dlg_put_backtitle(); 69218915Snwhitehorn 70218915Snwhitehorn if (chdir(getenv("BSDINSTALL_CHROOT")) != 0) { 71218915Snwhitehorn char error[512]; 72218915Snwhitehorn sprintf(error, "Could could change to directory %s: %s\n", 73218915Snwhitehorn getenv("BSDINSTALL_DISTDIR"), strerror(errno)); 74218915Snwhitehorn dialog_msgbox("Error", error, 0, 0, TRUE); 75218915Snwhitehorn end_dialog(); 76218915Snwhitehorn return (1); 77218915Snwhitehorn } 78218915Snwhitehorn 79218799Snwhitehorn retval = extract_files(ndists, dists); 80218799Snwhitehorn 81218915Snwhitehorn end_dialog(); 82218915Snwhitehorn 83218799Snwhitehorn free(diststring); 84218799Snwhitehorn free(dists); 85218799Snwhitehorn 86218799Snwhitehorn return (retval); 87218799Snwhitehorn} 88218799Snwhitehorn 89218799Snwhitehornstatic int 90219617Snwhitehorncount_files(const char *file) 91219617Snwhitehorn{ 92219617Snwhitehorn struct archive *archive; 93219617Snwhitehorn struct archive_entry *entry; 94219617Snwhitehorn static FILE *manifest = NULL; 95219617Snwhitehorn char path[MAXPATHLEN]; 96219617Snwhitehorn char errormsg[512]; 97219617Snwhitehorn int file_count, err; 98219617Snwhitehorn 99219617Snwhitehorn if (manifest == NULL) { 100219617Snwhitehorn sprintf(path, "%s/MANIFEST", getenv("BSDINSTALL_DISTDIR")); 101219617Snwhitehorn manifest = fopen(path, "r"); 102219617Snwhitehorn } 103219617Snwhitehorn 104219617Snwhitehorn if (manifest != NULL) { 105219617Snwhitehorn char line[512]; 106219617Snwhitehorn char *tok1, *tok2; 107219618Snwhitehorn 108219618Snwhitehorn rewind(manifest); 109219617Snwhitehorn while (fgets(line, sizeof(line), manifest) != NULL) { 110219617Snwhitehorn tok2 = line; 111219617Snwhitehorn tok1 = strsep(&tok2, "\t"); 112219617Snwhitehorn if (tok1 == NULL || strcmp(tok1, file) != 0) 113219617Snwhitehorn continue; 114219617Snwhitehorn 115219617Snwhitehorn /* 116219617Snwhitehorn * We're at the right manifest line. The file count is 117219617Snwhitehorn * in the third element 118219617Snwhitehorn */ 119219617Snwhitehorn tok1 = strsep(&tok2, "\t"); 120219617Snwhitehorn tok1 = strsep(&tok2, "\t"); 121219617Snwhitehorn if (tok1 != NULL) 122219617Snwhitehorn return atoi(tok1); 123219617Snwhitehorn } 124219617Snwhitehorn } 125219617Snwhitehorn 126219617Snwhitehorn /* Either we didn't have a manifest, or this archive wasn't there */ 127219617Snwhitehorn archive = archive_read_new(); 128219617Snwhitehorn archive_read_support_format_all(archive); 129219617Snwhitehorn archive_read_support_compression_all(archive); 130219617Snwhitehorn sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), file); 131219617Snwhitehorn err = archive_read_open_filename(archive, path, 4096); 132219617Snwhitehorn if (err != ARCHIVE_OK) { 133219617Snwhitehorn snprintf(errormsg, sizeof(errormsg), 134219617Snwhitehorn "Error while extracting %s: %s\n", file, 135219617Snwhitehorn archive_error_string(archive)); 136219617Snwhitehorn dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE); 137219617Snwhitehorn return (-1); 138219617Snwhitehorn } 139219617Snwhitehorn 140219617Snwhitehorn file_count = 0; 141219617Snwhitehorn while (archive_read_next_header(archive, &entry) == ARCHIVE_OK) 142219617Snwhitehorn file_count++; 143219617Snwhitehorn archive_read_free(archive); 144219617Snwhitehorn 145219617Snwhitehorn return (file_count); 146219617Snwhitehorn} 147219617Snwhitehorn 148219617Snwhitehornstatic int 149218799Snwhitehornextract_files(int nfiles, const char **files) 150218799Snwhitehorn{ 151218799Snwhitehorn const char *items[nfiles*2]; 152218799Snwhitehorn char path[PATH_MAX]; 153218799Snwhitehorn int archive_files[nfiles]; 154218799Snwhitehorn int total_files, current_files, archive_file; 155218799Snwhitehorn struct archive *archive; 156218799Snwhitehorn struct archive_entry *entry; 157218799Snwhitehorn char errormsg[512]; 158218799Snwhitehorn char status[8]; 159218799Snwhitehorn int i, err, progress, last_progress; 160218799Snwhitehorn 161218799Snwhitehorn err = 0; 162218799Snwhitehorn progress = 0; 163218799Snwhitehorn 164218799Snwhitehorn /* Make the transfer list for dialog */ 165218799Snwhitehorn for (i = 0; i < nfiles; i++) { 166218799Snwhitehorn items[i*2] = strrchr(files[i], '/'); 167218799Snwhitehorn if (items[i*2] != NULL) 168218799Snwhitehorn items[i*2]++; 169218799Snwhitehorn else 170218799Snwhitehorn items[i*2] = files[i]; 171218799Snwhitehorn items[i*2 + 1] = "Pending"; 172218799Snwhitehorn } 173218799Snwhitehorn 174218799Snwhitehorn dialog_msgbox("", 175218799Snwhitehorn "Checking distribution archives.\nPlease wait...", 0, 0, FALSE); 176218799Snwhitehorn 177219617Snwhitehorn /* Count all the files */ 178218799Snwhitehorn total_files = 0; 179218799Snwhitehorn for (i = 0; i < nfiles; i++) { 180219617Snwhitehorn archive_files[i] = count_files(files[i]); 181219617Snwhitehorn if (archive_files[i] < 0) 182219617Snwhitehorn return (-1); 183218799Snwhitehorn total_files += archive_files[i]; 184218799Snwhitehorn } 185218799Snwhitehorn 186218799Snwhitehorn current_files = 0; 187218799Snwhitehorn 188218799Snwhitehorn for (i = 0; i < nfiles; i++) { 189218799Snwhitehorn archive = archive_read_new(); 190218799Snwhitehorn archive_read_support_format_all(archive); 191218799Snwhitehorn archive_read_support_compression_all(archive); 192218799Snwhitehorn sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]); 193218799Snwhitehorn err = archive_read_open_filename(archive, path, 4096); 194218799Snwhitehorn 195218799Snwhitehorn items[i*2 + 1] = "In Progress"; 196218799Snwhitehorn archive_file = 0; 197218799Snwhitehorn 198218799Snwhitehorn while ((err = archive_read_next_header(archive, &entry)) == 199218799Snwhitehorn ARCHIVE_OK) { 200218799Snwhitehorn last_progress = progress; 201218799Snwhitehorn progress = (current_files*100)/total_files; 202218799Snwhitehorn 203218799Snwhitehorn sprintf(status, "-%d", 204218799Snwhitehorn (archive_file*100)/archive_files[i]); 205218799Snwhitehorn items[i*2 + 1] = status; 206218799Snwhitehorn 207218799Snwhitehorn if (progress > last_progress) 208218799Snwhitehorn dialog_mixedgauge("Archive Extraction", 209218799Snwhitehorn "Extracting distribution files...", 0, 0, 210218799Snwhitehorn progress, nfiles, 211218799Snwhitehorn __DECONST(char **, items)); 212218799Snwhitehorn 213218799Snwhitehorn err = archive_read_extract(archive, entry, 214218799Snwhitehorn ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER | 215218799Snwhitehorn ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | 216218799Snwhitehorn ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS); 217218799Snwhitehorn 218218799Snwhitehorn if (err != ARCHIVE_OK) 219218799Snwhitehorn break; 220218799Snwhitehorn 221218799Snwhitehorn archive_file++; 222218799Snwhitehorn current_files++; 223218799Snwhitehorn } 224218799Snwhitehorn 225218799Snwhitehorn items[i*2 + 1] = "Done"; 226218799Snwhitehorn 227218799Snwhitehorn if (err != ARCHIVE_EOF) { 228218799Snwhitehorn snprintf(errormsg, sizeof(errormsg), 229218799Snwhitehorn "Error while extracting %s: %s\n", items[i*2], 230218799Snwhitehorn archive_error_string(archive)); 231218799Snwhitehorn items[i*2 + 1] = "Failed"; 232218799Snwhitehorn dialog_msgbox("Extract Error", errormsg, 0, 0, 233218799Snwhitehorn TRUE); 234218915Snwhitehorn return (err); 235218799Snwhitehorn } 236218799Snwhitehorn 237218799Snwhitehorn archive_read_free(archive); 238218799Snwhitehorn } 239218799Snwhitehorn 240218915Snwhitehorn return (0); 241218799Snwhitehorn} 242