12118f387SNathan Whitehorn /*- 22118f387SNathan Whitehorn * Copyright (c) 2011 Nathan Whitehorn 32118f387SNathan Whitehorn * All rights reserved. 42118f387SNathan Whitehorn * 52118f387SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 62118f387SNathan Whitehorn * modification, are permitted provided that the following conditions 72118f387SNathan Whitehorn * are met: 82118f387SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 92118f387SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 102118f387SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 112118f387SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 122118f387SNathan Whitehorn * documentation and/or other materials provided with the distribution. 132118f387SNathan Whitehorn * 142118f387SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 152118f387SNathan Whitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 162118f387SNathan Whitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 172118f387SNathan Whitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 182118f387SNathan Whitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 192118f387SNathan Whitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 202118f387SNathan Whitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 212118f387SNathan Whitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 222118f387SNathan Whitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 232118f387SNathan Whitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 242118f387SNathan Whitehorn * SUCH DAMAGE. 252118f387SNathan Whitehorn * 262118f387SNathan Whitehorn * $FreeBSD$ 272118f387SNathan Whitehorn */ 282118f387SNathan Whitehorn 2946cc2c02SNathan Whitehorn #include <sys/param.h> 302118f387SNathan Whitehorn #include <stdio.h> 312118f387SNathan Whitehorn #include <errno.h> 322118f387SNathan Whitehorn #include <limits.h> 332118f387SNathan Whitehorn #include <archive.h> 342118f387SNathan Whitehorn #include <dialog.h> 352118f387SNathan Whitehorn 362118f387SNathan Whitehorn static int extract_files(int nfiles, const char **files); 372118f387SNathan Whitehorn 382118f387SNathan Whitehorn int 392118f387SNathan Whitehorn main(void) 402118f387SNathan Whitehorn { 41*bfd258f7SNathan Whitehorn char *diststring; 422118f387SNathan Whitehorn const char **dists; 432118f387SNathan Whitehorn int i, retval, ndists = 0; 44*bfd258f7SNathan Whitehorn 45*bfd258f7SNathan Whitehorn if (getenv("DISTRIBUTIONS") == NULL) { 46*bfd258f7SNathan Whitehorn fprintf(stderr, "DISTRIBUTIONS variable is not set\n"); 47*bfd258f7SNathan Whitehorn return (1); 48*bfd258f7SNathan Whitehorn } 49*bfd258f7SNathan Whitehorn 50*bfd258f7SNathan Whitehorn diststring = strdup(getenv("DISTRIBUTIONS")); 512118f387SNathan Whitehorn for (i = 0; diststring[i] != 0; i++) 522118f387SNathan Whitehorn if (isspace(diststring[i]) && !isspace(diststring[i+1])) 532118f387SNathan Whitehorn ndists++; 542118f387SNathan Whitehorn ndists++; /* Last one */ 552118f387SNathan Whitehorn 562118f387SNathan Whitehorn dists = calloc(ndists, sizeof(const char *)); 5757bda1b6SNathan Whitehorn if (dists == NULL) { 5857bda1b6SNathan Whitehorn fprintf(stderr, "Out of memory!\n"); 59c725e3efSKevin Lo free(diststring); 6057bda1b6SNathan Whitehorn return (1); 6157bda1b6SNathan Whitehorn } 6257bda1b6SNathan Whitehorn 632118f387SNathan Whitehorn for (i = 0; i < ndists; i++) 642118f387SNathan Whitehorn dists[i] = strsep(&diststring, " \t"); 652118f387SNathan Whitehorn 6657bda1b6SNathan Whitehorn init_dialog(stdin, stdout); 6757bda1b6SNathan Whitehorn dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer"); 6857bda1b6SNathan Whitehorn dlg_put_backtitle(); 6957bda1b6SNathan Whitehorn 7057bda1b6SNathan Whitehorn if (chdir(getenv("BSDINSTALL_CHROOT")) != 0) { 7157bda1b6SNathan Whitehorn char error[512]; 7257bda1b6SNathan Whitehorn sprintf(error, "Could could change to directory %s: %s\n", 7357bda1b6SNathan Whitehorn getenv("BSDINSTALL_DISTDIR"), strerror(errno)); 7457bda1b6SNathan Whitehorn dialog_msgbox("Error", error, 0, 0, TRUE); 7557bda1b6SNathan Whitehorn end_dialog(); 7657bda1b6SNathan Whitehorn return (1); 7757bda1b6SNathan Whitehorn } 7857bda1b6SNathan Whitehorn 792118f387SNathan Whitehorn retval = extract_files(ndists, dists); 802118f387SNathan Whitehorn 8157bda1b6SNathan Whitehorn end_dialog(); 8257bda1b6SNathan Whitehorn 832118f387SNathan Whitehorn free(diststring); 842118f387SNathan Whitehorn free(dists); 852118f387SNathan Whitehorn 862118f387SNathan Whitehorn return (retval); 872118f387SNathan Whitehorn } 882118f387SNathan Whitehorn 892118f387SNathan Whitehorn static int 9046cc2c02SNathan Whitehorn count_files(const char *file) 9146cc2c02SNathan Whitehorn { 9246cc2c02SNathan Whitehorn struct archive *archive; 9346cc2c02SNathan Whitehorn struct archive_entry *entry; 9446cc2c02SNathan Whitehorn static FILE *manifest = NULL; 9546cc2c02SNathan Whitehorn char path[MAXPATHLEN]; 9646cc2c02SNathan Whitehorn char errormsg[512]; 9746cc2c02SNathan Whitehorn int file_count, err; 9846cc2c02SNathan Whitehorn 9946cc2c02SNathan Whitehorn if (manifest == NULL) { 10046cc2c02SNathan Whitehorn sprintf(path, "%s/MANIFEST", getenv("BSDINSTALL_DISTDIR")); 10146cc2c02SNathan Whitehorn manifest = fopen(path, "r"); 10246cc2c02SNathan Whitehorn } 10346cc2c02SNathan Whitehorn 10446cc2c02SNathan Whitehorn if (manifest != NULL) { 10546cc2c02SNathan Whitehorn char line[512]; 10646cc2c02SNathan Whitehorn char *tok1, *tok2; 107896a9484SNathan Whitehorn 108896a9484SNathan Whitehorn rewind(manifest); 10946cc2c02SNathan Whitehorn while (fgets(line, sizeof(line), manifest) != NULL) { 11046cc2c02SNathan Whitehorn tok2 = line; 11146cc2c02SNathan Whitehorn tok1 = strsep(&tok2, "\t"); 11246cc2c02SNathan Whitehorn if (tok1 == NULL || strcmp(tok1, file) != 0) 11346cc2c02SNathan Whitehorn continue; 11446cc2c02SNathan Whitehorn 11546cc2c02SNathan Whitehorn /* 11646cc2c02SNathan Whitehorn * We're at the right manifest line. The file count is 11746cc2c02SNathan Whitehorn * in the third element 11846cc2c02SNathan Whitehorn */ 11946cc2c02SNathan Whitehorn tok1 = strsep(&tok2, "\t"); 12046cc2c02SNathan Whitehorn tok1 = strsep(&tok2, "\t"); 12146cc2c02SNathan Whitehorn if (tok1 != NULL) 12246cc2c02SNathan Whitehorn return atoi(tok1); 12346cc2c02SNathan Whitehorn } 12446cc2c02SNathan Whitehorn } 12546cc2c02SNathan Whitehorn 12646cc2c02SNathan Whitehorn /* Either we didn't have a manifest, or this archive wasn't there */ 12746cc2c02SNathan Whitehorn archive = archive_read_new(); 12846cc2c02SNathan Whitehorn archive_read_support_format_all(archive); 12946cc2c02SNathan Whitehorn archive_read_support_compression_all(archive); 13046cc2c02SNathan Whitehorn sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), file); 13146cc2c02SNathan Whitehorn err = archive_read_open_filename(archive, path, 4096); 13246cc2c02SNathan Whitehorn if (err != ARCHIVE_OK) { 13346cc2c02SNathan Whitehorn snprintf(errormsg, sizeof(errormsg), 13446cc2c02SNathan Whitehorn "Error while extracting %s: %s\n", file, 13546cc2c02SNathan Whitehorn archive_error_string(archive)); 13646cc2c02SNathan Whitehorn dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE); 13746cc2c02SNathan Whitehorn return (-1); 13846cc2c02SNathan Whitehorn } 13946cc2c02SNathan Whitehorn 14046cc2c02SNathan Whitehorn file_count = 0; 14146cc2c02SNathan Whitehorn while (archive_read_next_header(archive, &entry) == ARCHIVE_OK) 14246cc2c02SNathan Whitehorn file_count++; 14346cc2c02SNathan Whitehorn archive_read_free(archive); 14446cc2c02SNathan Whitehorn 14546cc2c02SNathan Whitehorn return (file_count); 14646cc2c02SNathan Whitehorn } 14746cc2c02SNathan Whitehorn 14846cc2c02SNathan Whitehorn static int 1492118f387SNathan Whitehorn extract_files(int nfiles, const char **files) 1502118f387SNathan Whitehorn { 1512118f387SNathan Whitehorn const char *items[nfiles*2]; 1522118f387SNathan Whitehorn char path[PATH_MAX]; 1532118f387SNathan Whitehorn int archive_files[nfiles]; 1542118f387SNathan Whitehorn int total_files, current_files, archive_file; 1552118f387SNathan Whitehorn struct archive *archive; 1562118f387SNathan Whitehorn struct archive_entry *entry; 1572118f387SNathan Whitehorn char errormsg[512]; 1582118f387SNathan Whitehorn char status[8]; 1592118f387SNathan Whitehorn int i, err, progress, last_progress; 1602118f387SNathan Whitehorn 1612118f387SNathan Whitehorn err = 0; 1622118f387SNathan Whitehorn progress = 0; 1632118f387SNathan Whitehorn 1642118f387SNathan Whitehorn /* Make the transfer list for dialog */ 1652118f387SNathan Whitehorn for (i = 0; i < nfiles; i++) { 1662118f387SNathan Whitehorn items[i*2] = strrchr(files[i], '/'); 1672118f387SNathan Whitehorn if (items[i*2] != NULL) 1682118f387SNathan Whitehorn items[i*2]++; 1692118f387SNathan Whitehorn else 1702118f387SNathan Whitehorn items[i*2] = files[i]; 1712118f387SNathan Whitehorn items[i*2 + 1] = "Pending"; 1722118f387SNathan Whitehorn } 1732118f387SNathan Whitehorn 1742118f387SNathan Whitehorn dialog_msgbox("", 1752118f387SNathan Whitehorn "Checking distribution archives.\nPlease wait...", 0, 0, FALSE); 1762118f387SNathan Whitehorn 17746cc2c02SNathan Whitehorn /* Count all the files */ 1782118f387SNathan Whitehorn total_files = 0; 1792118f387SNathan Whitehorn for (i = 0; i < nfiles; i++) { 18046cc2c02SNathan Whitehorn archive_files[i] = count_files(files[i]); 18146cc2c02SNathan Whitehorn if (archive_files[i] < 0) 18246cc2c02SNathan Whitehorn return (-1); 1832118f387SNathan Whitehorn total_files += archive_files[i]; 1842118f387SNathan Whitehorn } 1852118f387SNathan Whitehorn 1862118f387SNathan Whitehorn current_files = 0; 1872118f387SNathan Whitehorn 1882118f387SNathan Whitehorn for (i = 0; i < nfiles; i++) { 1892118f387SNathan Whitehorn archive = archive_read_new(); 1902118f387SNathan Whitehorn archive_read_support_format_all(archive); 1912118f387SNathan Whitehorn archive_read_support_compression_all(archive); 1922118f387SNathan Whitehorn sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]); 1932118f387SNathan Whitehorn err = archive_read_open_filename(archive, path, 4096); 1942118f387SNathan Whitehorn 1952118f387SNathan Whitehorn items[i*2 + 1] = "In Progress"; 1962118f387SNathan Whitehorn archive_file = 0; 1972118f387SNathan Whitehorn 1982118f387SNathan Whitehorn while ((err = archive_read_next_header(archive, &entry)) == 1992118f387SNathan Whitehorn ARCHIVE_OK) { 2002118f387SNathan Whitehorn last_progress = progress; 2012118f387SNathan Whitehorn progress = (current_files*100)/total_files; 2022118f387SNathan Whitehorn 2032118f387SNathan Whitehorn sprintf(status, "-%d", 2042118f387SNathan Whitehorn (archive_file*100)/archive_files[i]); 2052118f387SNathan Whitehorn items[i*2 + 1] = status; 2062118f387SNathan Whitehorn 2072118f387SNathan Whitehorn if (progress > last_progress) 2082118f387SNathan Whitehorn dialog_mixedgauge("Archive Extraction", 2092118f387SNathan Whitehorn "Extracting distribution files...", 0, 0, 2102118f387SNathan Whitehorn progress, nfiles, 2112118f387SNathan Whitehorn __DECONST(char **, items)); 2122118f387SNathan Whitehorn 2132118f387SNathan Whitehorn err = archive_read_extract(archive, entry, 2142118f387SNathan Whitehorn ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER | 2152118f387SNathan Whitehorn ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | 2162118f387SNathan Whitehorn ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS); 2172118f387SNathan Whitehorn 2182118f387SNathan Whitehorn if (err != ARCHIVE_OK) 2192118f387SNathan Whitehorn break; 2202118f387SNathan Whitehorn 2212118f387SNathan Whitehorn archive_file++; 2222118f387SNathan Whitehorn current_files++; 2232118f387SNathan Whitehorn } 2242118f387SNathan Whitehorn 2252118f387SNathan Whitehorn items[i*2 + 1] = "Done"; 2262118f387SNathan Whitehorn 2272118f387SNathan Whitehorn if (err != ARCHIVE_EOF) { 2282118f387SNathan Whitehorn snprintf(errormsg, sizeof(errormsg), 2292118f387SNathan Whitehorn "Error while extracting %s: %s\n", items[i*2], 2302118f387SNathan Whitehorn archive_error_string(archive)); 2312118f387SNathan Whitehorn items[i*2 + 1] = "Failed"; 2322118f387SNathan Whitehorn dialog_msgbox("Extract Error", errormsg, 0, 0, 2332118f387SNathan Whitehorn TRUE); 23457bda1b6SNathan Whitehorn return (err); 2352118f387SNathan Whitehorn } 2362118f387SNathan Whitehorn 2372118f387SNathan Whitehorn archive_read_free(archive); 2382118f387SNathan Whitehorn } 2392118f387SNathan Whitehorn 24057bda1b6SNathan Whitehorn return (0); 2412118f387SNathan Whitehorn } 242