12118f387SNathan Whitehorn /*- 22118f387SNathan Whitehorn * Copyright (c) 2011 Nathan Whitehorn 3*82ac9f2bSDevin Teske * Copyright (c) 2014 Devin Teske <dteske@FreeBSD.org> 42118f387SNathan Whitehorn * All rights reserved. 52118f387SNathan Whitehorn * 62118f387SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 72118f387SNathan Whitehorn * modification, are permitted provided that the following conditions 82118f387SNathan Whitehorn * are met: 92118f387SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 102118f387SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 112118f387SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 122118f387SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 132118f387SNathan Whitehorn * documentation and/or other materials provided with the distribution. 142118f387SNathan Whitehorn * 152118f387SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 162118f387SNathan Whitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 172118f387SNathan Whitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 182118f387SNathan Whitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 192118f387SNathan Whitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 202118f387SNathan Whitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 212118f387SNathan Whitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 222118f387SNathan Whitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 232118f387SNathan Whitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 242118f387SNathan Whitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 252118f387SNathan Whitehorn * SUCH DAMAGE. 262118f387SNathan Whitehorn */ 272118f387SNathan Whitehorn 28*82ac9f2bSDevin Teske #include <sys/cdefs.h> 29*82ac9f2bSDevin Teske __FBSDID("$FreeBSD$"); 30*82ac9f2bSDevin Teske 3146cc2c02SNathan Whitehorn #include <sys/param.h> 32*82ac9f2bSDevin Teske #include <archive.h> 33*82ac9f2bSDevin Teske #include <ctype.h> 34*82ac9f2bSDevin Teske #include <dialog.h> 35*82ac9f2bSDevin Teske #include <err.h> 362118f387SNathan Whitehorn #include <errno.h> 372118f387SNathan Whitehorn #include <limits.h> 38*82ac9f2bSDevin Teske #include <stdio.h> 39*82ac9f2bSDevin Teske #include <stdlib.h> 40*82ac9f2bSDevin Teske #include <string.h> 41*82ac9f2bSDevin Teske #include <unistd.h> 422118f387SNathan Whitehorn 43*82ac9f2bSDevin Teske static int count_files(const char *file); 442118f387SNathan Whitehorn static int extract_files(int nfiles, const char **files); 452118f387SNathan Whitehorn 462118f387SNathan Whitehorn int 472118f387SNathan Whitehorn main(void) 482118f387SNathan Whitehorn { 492118f387SNathan Whitehorn const char **dists; 50*82ac9f2bSDevin Teske char *diststring; 51*82ac9f2bSDevin Teske int i; 52*82ac9f2bSDevin Teske int ndists = 0; 53*82ac9f2bSDevin Teske int retval; 54*82ac9f2bSDevin Teske char error[PATH_MAX + 512]; 55bfd258f7SNathan Whitehorn 56*82ac9f2bSDevin Teske if (getenv("DISTRIBUTIONS") == NULL) 57*82ac9f2bSDevin Teske errx(EXIT_FAILURE, "DISTRIBUTIONS variable is not set"); 58bfd258f7SNathan Whitehorn 59bfd258f7SNathan Whitehorn diststring = strdup(getenv("DISTRIBUTIONS")); 602118f387SNathan Whitehorn for (i = 0; diststring[i] != 0; i++) 612118f387SNathan Whitehorn if (isspace(diststring[i]) && !isspace(diststring[i+1])) 622118f387SNathan Whitehorn ndists++; 632118f387SNathan Whitehorn ndists++; /* Last one */ 642118f387SNathan Whitehorn 652118f387SNathan Whitehorn dists = calloc(ndists, sizeof(const char *)); 6657bda1b6SNathan Whitehorn if (dists == NULL) { 67c725e3efSKevin Lo free(diststring); 68*82ac9f2bSDevin Teske errx(EXIT_FAILURE, "Out of memory!"); 6957bda1b6SNathan Whitehorn } 7057bda1b6SNathan Whitehorn 712118f387SNathan Whitehorn for (i = 0; i < ndists; i++) 722118f387SNathan Whitehorn dists[i] = strsep(&diststring, " \t"); 732118f387SNathan Whitehorn 7457bda1b6SNathan Whitehorn init_dialog(stdin, stdout); 7557bda1b6SNathan Whitehorn dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer"); 7657bda1b6SNathan Whitehorn dlg_put_backtitle(); 7757bda1b6SNathan Whitehorn 7857bda1b6SNathan Whitehorn if (chdir(getenv("BSDINSTALL_CHROOT")) != 0) { 79*82ac9f2bSDevin Teske snprintf(error, sizeof(error), 80*82ac9f2bSDevin Teske "Could could change to directory %s: %s\n", 8157bda1b6SNathan Whitehorn getenv("BSDINSTALL_DISTDIR"), strerror(errno)); 8257bda1b6SNathan Whitehorn dialog_msgbox("Error", error, 0, 0, TRUE); 8357bda1b6SNathan Whitehorn end_dialog(); 84*82ac9f2bSDevin Teske return (EXIT_FAILURE); 8557bda1b6SNathan Whitehorn } 8657bda1b6SNathan Whitehorn 872118f387SNathan Whitehorn retval = extract_files(ndists, dists); 882118f387SNathan Whitehorn 8957bda1b6SNathan Whitehorn end_dialog(); 9057bda1b6SNathan Whitehorn 912118f387SNathan Whitehorn free(diststring); 922118f387SNathan Whitehorn free(dists); 932118f387SNathan Whitehorn 942118f387SNathan Whitehorn return (retval); 952118f387SNathan Whitehorn } 962118f387SNathan Whitehorn 972118f387SNathan Whitehorn static int 9846cc2c02SNathan Whitehorn count_files(const char *file) 9946cc2c02SNathan Whitehorn { 100*82ac9f2bSDevin Teske static FILE *manifest = NULL; 101*82ac9f2bSDevin Teske char *tok1; 102*82ac9f2bSDevin Teske char *tok2; 103*82ac9f2bSDevin Teske int file_count; 104*82ac9f2bSDevin Teske int retval; 10546cc2c02SNathan Whitehorn struct archive *archive; 10646cc2c02SNathan Whitehorn struct archive_entry *entry; 107*82ac9f2bSDevin Teske char line[512]; 108*82ac9f2bSDevin Teske char path[PATH_MAX]; 109*82ac9f2bSDevin Teske char errormsg[PATH_MAX + 512]; 11046cc2c02SNathan Whitehorn 11146cc2c02SNathan Whitehorn if (manifest == NULL) { 112*82ac9f2bSDevin Teske snprintf(path, sizeof(path), "%s/MANIFEST", 113*82ac9f2bSDevin Teske getenv("BSDINSTALL_DISTDIR")); 11446cc2c02SNathan Whitehorn manifest = fopen(path, "r"); 11546cc2c02SNathan Whitehorn } 11646cc2c02SNathan Whitehorn 11746cc2c02SNathan Whitehorn if (manifest != NULL) { 118896a9484SNathan Whitehorn rewind(manifest); 11946cc2c02SNathan Whitehorn while (fgets(line, sizeof(line), manifest) != NULL) { 12046cc2c02SNathan Whitehorn tok2 = line; 12146cc2c02SNathan Whitehorn tok1 = strsep(&tok2, "\t"); 12246cc2c02SNathan Whitehorn if (tok1 == NULL || strcmp(tok1, file) != 0) 12346cc2c02SNathan Whitehorn continue; 12446cc2c02SNathan Whitehorn 12546cc2c02SNathan Whitehorn /* 12646cc2c02SNathan Whitehorn * We're at the right manifest line. The file count is 12746cc2c02SNathan Whitehorn * in the third element 12846cc2c02SNathan Whitehorn */ 12946cc2c02SNathan Whitehorn tok1 = strsep(&tok2, "\t"); 13046cc2c02SNathan Whitehorn tok1 = strsep(&tok2, "\t"); 13146cc2c02SNathan Whitehorn if (tok1 != NULL) 13246cc2c02SNathan Whitehorn return atoi(tok1); 13346cc2c02SNathan Whitehorn } 13446cc2c02SNathan Whitehorn } 13546cc2c02SNathan Whitehorn 13646cc2c02SNathan Whitehorn /* Either we didn't have a manifest, or this archive wasn't there */ 13746cc2c02SNathan Whitehorn archive = archive_read_new(); 13846cc2c02SNathan Whitehorn archive_read_support_format_all(archive); 139ebb8fc42SMartin Matuska archive_read_support_filter_all(archive); 140*82ac9f2bSDevin Teske snprintf(path, sizeof(path), "%s/%s", getenv("BSDINSTALL_DISTDIR"), 141*82ac9f2bSDevin Teske file); 142*82ac9f2bSDevin Teske retval = archive_read_open_filename(archive, path, 4096); 143*82ac9f2bSDevin Teske if (retval != ARCHIVE_OK) { 14446cc2c02SNathan Whitehorn snprintf(errormsg, sizeof(errormsg), 14546cc2c02SNathan Whitehorn "Error while extracting %s: %s\n", file, 14646cc2c02SNathan Whitehorn archive_error_string(archive)); 14746cc2c02SNathan Whitehorn dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE); 14846cc2c02SNathan Whitehorn return (-1); 14946cc2c02SNathan Whitehorn } 15046cc2c02SNathan Whitehorn 15146cc2c02SNathan Whitehorn file_count = 0; 15246cc2c02SNathan Whitehorn while (archive_read_next_header(archive, &entry) == ARCHIVE_OK) 15346cc2c02SNathan Whitehorn file_count++; 15446cc2c02SNathan Whitehorn archive_read_free(archive); 15546cc2c02SNathan Whitehorn 15646cc2c02SNathan Whitehorn return (file_count); 15746cc2c02SNathan Whitehorn } 15846cc2c02SNathan Whitehorn 15946cc2c02SNathan Whitehorn static int 1602118f387SNathan Whitehorn extract_files(int nfiles, const char **files) 1612118f387SNathan Whitehorn { 162*82ac9f2bSDevin Teske int archive_file; 1632118f387SNathan Whitehorn int archive_files[nfiles]; 164*82ac9f2bSDevin Teske int current_files = 0; 165*82ac9f2bSDevin Teske int i; 166*82ac9f2bSDevin Teske int last_progress; 167*82ac9f2bSDevin Teske int progress = 0; 168*82ac9f2bSDevin Teske int retval; 169*82ac9f2bSDevin Teske int total_files = 0; 1702118f387SNathan Whitehorn struct archive *archive; 1712118f387SNathan Whitehorn struct archive_entry *entry; 1722118f387SNathan Whitehorn char status[8]; 173*82ac9f2bSDevin Teske char path[PATH_MAX]; 174*82ac9f2bSDevin Teske char errormsg[PATH_MAX + 512]; 175*82ac9f2bSDevin Teske const char *items[nfiles*2]; 1762118f387SNathan Whitehorn 1772118f387SNathan Whitehorn /* Make the transfer list for dialog */ 1782118f387SNathan Whitehorn for (i = 0; i < nfiles; i++) { 1792118f387SNathan Whitehorn items[i*2] = strrchr(files[i], '/'); 1802118f387SNathan Whitehorn if (items[i*2] != NULL) 1812118f387SNathan Whitehorn items[i*2]++; 1822118f387SNathan Whitehorn else 1832118f387SNathan Whitehorn items[i*2] = files[i]; 1842118f387SNathan Whitehorn items[i*2 + 1] = "Pending"; 1852118f387SNathan Whitehorn } 1862118f387SNathan Whitehorn 1872118f387SNathan Whitehorn dialog_msgbox("", 1882118f387SNathan Whitehorn "Checking distribution archives.\nPlease wait...", 0, 0, FALSE); 1892118f387SNathan Whitehorn 19046cc2c02SNathan Whitehorn /* Count all the files */ 1912118f387SNathan Whitehorn for (i = 0; i < nfiles; i++) { 19246cc2c02SNathan Whitehorn archive_files[i] = count_files(files[i]); 19346cc2c02SNathan Whitehorn if (archive_files[i] < 0) 19446cc2c02SNathan Whitehorn return (-1); 1952118f387SNathan Whitehorn total_files += archive_files[i]; 1962118f387SNathan Whitehorn } 1972118f387SNathan Whitehorn 1982118f387SNathan Whitehorn for (i = 0; i < nfiles; i++) { 1992118f387SNathan Whitehorn archive = archive_read_new(); 2002118f387SNathan Whitehorn archive_read_support_format_all(archive); 201ebb8fc42SMartin Matuska archive_read_support_filter_all(archive); 202*82ac9f2bSDevin Teske snprintf(path, sizeof(path), "%s/%s", 203*82ac9f2bSDevin Teske getenv("BSDINSTALL_DISTDIR"), files[i]); 204*82ac9f2bSDevin Teske retval = archive_read_open_filename(archive, path, 4096); 2052118f387SNathan Whitehorn 2062118f387SNathan Whitehorn items[i*2 + 1] = "In Progress"; 2072118f387SNathan Whitehorn archive_file = 0; 2082118f387SNathan Whitehorn 209*82ac9f2bSDevin Teske while ((retval = archive_read_next_header(archive, &entry)) == 2102118f387SNathan Whitehorn ARCHIVE_OK) { 2112118f387SNathan Whitehorn last_progress = progress; 2122118f387SNathan Whitehorn progress = (current_files*100)/total_files; 2132118f387SNathan Whitehorn 214*82ac9f2bSDevin Teske snprintf(status, sizeof(status), "-%d", 2152118f387SNathan Whitehorn (archive_file*100)/archive_files[i]); 2162118f387SNathan Whitehorn items[i*2 + 1] = status; 2172118f387SNathan Whitehorn 2182118f387SNathan Whitehorn if (progress > last_progress) 2192118f387SNathan Whitehorn dialog_mixedgauge("Archive Extraction", 2202118f387SNathan Whitehorn "Extracting distribution files...", 0, 0, 2212118f387SNathan Whitehorn progress, nfiles, 2222118f387SNathan Whitehorn __DECONST(char **, items)); 2232118f387SNathan Whitehorn 224*82ac9f2bSDevin Teske retval = archive_read_extract(archive, entry, 2252118f387SNathan Whitehorn ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER | 2262118f387SNathan Whitehorn ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | 2272118f387SNathan Whitehorn ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS); 2282118f387SNathan Whitehorn 229*82ac9f2bSDevin Teske if (retval != ARCHIVE_OK) 2302118f387SNathan Whitehorn break; 2312118f387SNathan Whitehorn 2322118f387SNathan Whitehorn archive_file++; 2332118f387SNathan Whitehorn current_files++; 2342118f387SNathan Whitehorn } 2352118f387SNathan Whitehorn 2362118f387SNathan Whitehorn items[i*2 + 1] = "Done"; 2372118f387SNathan Whitehorn 238*82ac9f2bSDevin Teske if (retval != ARCHIVE_EOF) { 2392118f387SNathan Whitehorn snprintf(errormsg, sizeof(errormsg), 2402118f387SNathan Whitehorn "Error while extracting %s: %s\n", items[i*2], 2412118f387SNathan Whitehorn archive_error_string(archive)); 2422118f387SNathan Whitehorn items[i*2 + 1] = "Failed"; 2432118f387SNathan Whitehorn dialog_msgbox("Extract Error", errormsg, 0, 0, 2442118f387SNathan Whitehorn TRUE); 245*82ac9f2bSDevin Teske return (retval); 2462118f387SNathan Whitehorn } 2472118f387SNathan Whitehorn 2482118f387SNathan Whitehorn archive_read_free(archive); 2492118f387SNathan Whitehorn } 2502118f387SNathan Whitehorn 251*82ac9f2bSDevin Teske return (EXIT_SUCCESS); 2522118f387SNathan Whitehorn } 253