distextract.c revision 218799
1/*- 2 * Copyright (c) 2011 Nathan Whitehorn 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/usr.sbin/bsdinstall/distextract/distextract.c 218799 2011-02-18 14:54:34Z nwhitehorn $ 27 */ 28 29#include <stdio.h> 30#include <errno.h> 31#include <limits.h> 32#include <archive.h> 33#include <dialog.h> 34 35static int extract_files(int nfiles, const char **files); 36 37int 38main(void) 39{ 40 char *diststring = strdup(getenv("DISTRIBUTIONS")); 41 const char **dists; 42 int i, retval, ndists = 0; 43 for (i = 0; diststring[i] != 0; i++) 44 if (isspace(diststring[i]) && !isspace(diststring[i+1])) 45 ndists++; 46 ndists++; /* Last one */ 47 48 dists = calloc(ndists, sizeof(const char *)); 49 for (i = 0; i < ndists; i++) 50 dists[i] = strsep(&diststring, " \t"); 51 52 chdir(getenv("BSDINSTALL_CHROOT")); 53 retval = extract_files(ndists, dists); 54 55 free(diststring); 56 free(dists); 57 58 return (retval); 59} 60 61static int 62extract_files(int nfiles, const char **files) 63{ 64 const char *items[nfiles*2]; 65 char path[PATH_MAX]; 66 int archive_files[nfiles]; 67 int total_files, current_files, archive_file; 68 struct archive *archive; 69 struct archive_entry *entry; 70 char errormsg[512]; 71 char status[8]; 72 int i, err, progress, last_progress; 73 74 err = 0; 75 progress = 0; 76 77 /* Make the transfer list for dialog */ 78 for (i = 0; i < nfiles; i++) { 79 items[i*2] = strrchr(files[i], '/'); 80 if (items[i*2] != NULL) 81 items[i*2]++; 82 else 83 items[i*2] = files[i]; 84 items[i*2 + 1] = "Pending"; 85 } 86 87 init_dialog(stdin, stdout); 88 dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer"); 89 dlg_put_backtitle(); 90 dialog_msgbox("", 91 "Checking distribution archives.\nPlease wait...", 0, 0, FALSE); 92 93 /* Open all the archives */ 94 total_files = 0; 95 for (i = 0; i < nfiles; i++) { 96 archive = archive_read_new(); 97 archive_read_support_format_all(archive); 98 archive_read_support_compression_all(archive); 99 sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]); 100 err = archive_read_open_filename(archive, path, 4096); 101 if (err != ARCHIVE_OK) { 102 snprintf(errormsg, sizeof(errormsg), 103 "Error while extracting %s: %s\n", items[i*2], 104 archive_error_string(archive)); 105 items[i*2 + 1] = "Failed"; 106 dialog_msgbox("Extract Error", errormsg, 0, 0, 107 TRUE); 108 goto exit; 109 } 110 archive_files[i] = 0; 111 while (archive_read_next_header(archive, &entry) == ARCHIVE_OK) 112 archive_files[i]++; 113 total_files += archive_files[i]; 114 archive_read_free(archive); 115 } 116 117 current_files = 0; 118 119 for (i = 0; i < nfiles; i++) { 120 archive = archive_read_new(); 121 archive_read_support_format_all(archive); 122 archive_read_support_compression_all(archive); 123 sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]); 124 err = archive_read_open_filename(archive, path, 4096); 125 126 items[i*2 + 1] = "In Progress"; 127 archive_file = 0; 128 129 while ((err = archive_read_next_header(archive, &entry)) == 130 ARCHIVE_OK) { 131 last_progress = progress; 132 progress = (current_files*100)/total_files; 133 134 sprintf(status, "-%d", 135 (archive_file*100)/archive_files[i]); 136 items[i*2 + 1] = status; 137 138 if (progress > last_progress) 139 dialog_mixedgauge("Archive Extraction", 140 "Extracting distribution files...", 0, 0, 141 progress, nfiles, 142 __DECONST(char **, items)); 143 144 err = archive_read_extract(archive, entry, 145 ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER | 146 ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | 147 ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS); 148 149 if (err != ARCHIVE_OK) 150 break; 151 152 archive_file++; 153 current_files++; 154 } 155 156 items[i*2 + 1] = "Done"; 157 158 if (err != ARCHIVE_EOF) { 159 snprintf(errormsg, sizeof(errormsg), 160 "Error while extracting %s: %s\n", items[i*2], 161 archive_error_string(archive)); 162 items[i*2 + 1] = "Failed"; 163 dialog_msgbox("Extract Error", errormsg, 0, 0, 164 TRUE); 165 goto exit; 166 } 167 168 archive_read_free(archive); 169 } 170 171 err = 0; 172exit: 173 end_dialog(); 174 175 return (err); 176} 177