distextract.c revision 218915
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 218915 2011-02-21 14:28:31Z 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 if (dists == NULL) { 50 fprintf(stderr, "Out of memory!\n"); 51 return (1); 52 } 53 54 for (i = 0; i < ndists; i++) 55 dists[i] = strsep(&diststring, " \t"); 56 57 init_dialog(stdin, stdout); 58 dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer"); 59 dlg_put_backtitle(); 60 61 if (chdir(getenv("BSDINSTALL_CHROOT")) != 0) { 62 char error[512]; 63 sprintf(error, "Could could change to directory %s: %s\n", 64 getenv("BSDINSTALL_DISTDIR"), strerror(errno)); 65 dialog_msgbox("Error", error, 0, 0, TRUE); 66 end_dialog(); 67 return (1); 68 } 69 70 retval = extract_files(ndists, dists); 71 72 end_dialog(); 73 74 free(diststring); 75 free(dists); 76 77 return (retval); 78} 79 80static int 81extract_files(int nfiles, const char **files) 82{ 83 const char *items[nfiles*2]; 84 char path[PATH_MAX]; 85 int archive_files[nfiles]; 86 int total_files, current_files, archive_file; 87 struct archive *archive; 88 struct archive_entry *entry; 89 char errormsg[512]; 90 char status[8]; 91 int i, err, progress, last_progress; 92 93 err = 0; 94 progress = 0; 95 96 /* Make the transfer list for dialog */ 97 for (i = 0; i < nfiles; i++) { 98 items[i*2] = strrchr(files[i], '/'); 99 if (items[i*2] != NULL) 100 items[i*2]++; 101 else 102 items[i*2] = files[i]; 103 items[i*2 + 1] = "Pending"; 104 } 105 106 dialog_msgbox("", 107 "Checking distribution archives.\nPlease wait...", 0, 0, FALSE); 108 109 /* Open all the archives */ 110 total_files = 0; 111 for (i = 0; i < nfiles; i++) { 112 archive = archive_read_new(); 113 archive_read_support_format_all(archive); 114 archive_read_support_compression_all(archive); 115 sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]); 116 err = archive_read_open_filename(archive, path, 4096); 117 if (err != ARCHIVE_OK) { 118 snprintf(errormsg, sizeof(errormsg), 119 "Error while extracting %s: %s\n", items[i*2], 120 archive_error_string(archive)); 121 items[i*2 + 1] = "Failed"; 122 dialog_msgbox("Extract Error", errormsg, 0, 0, 123 TRUE); 124 return (err); 125 } 126 archive_files[i] = 0; 127 while (archive_read_next_header(archive, &entry) == ARCHIVE_OK) 128 archive_files[i]++; 129 total_files += archive_files[i]; 130 archive_read_free(archive); 131 } 132 133 current_files = 0; 134 135 for (i = 0; i < nfiles; i++) { 136 archive = archive_read_new(); 137 archive_read_support_format_all(archive); 138 archive_read_support_compression_all(archive); 139 sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]); 140 err = archive_read_open_filename(archive, path, 4096); 141 142 items[i*2 + 1] = "In Progress"; 143 archive_file = 0; 144 145 while ((err = archive_read_next_header(archive, &entry)) == 146 ARCHIVE_OK) { 147 last_progress = progress; 148 progress = (current_files*100)/total_files; 149 150 sprintf(status, "-%d", 151 (archive_file*100)/archive_files[i]); 152 items[i*2 + 1] = status; 153 154 if (progress > last_progress) 155 dialog_mixedgauge("Archive Extraction", 156 "Extracting distribution files...", 0, 0, 157 progress, nfiles, 158 __DECONST(char **, items)); 159 160 err = archive_read_extract(archive, entry, 161 ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER | 162 ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | 163 ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS); 164 165 if (err != ARCHIVE_OK) 166 break; 167 168 archive_file++; 169 current_files++; 170 } 171 172 items[i*2 + 1] = "Done"; 173 174 if (err != ARCHIVE_EOF) { 175 snprintf(errormsg, sizeof(errormsg), 176 "Error while extracting %s: %s\n", items[i*2], 177 archive_error_string(archive)); 178 items[i*2 + 1] = "Failed"; 179 dialog_msgbox("Extract Error", errormsg, 0, 0, 180 TRUE); 181 return (err); 182 } 183 184 archive_read_free(archive); 185 } 186 187 return (0); 188} 189