xref: /freebsd/usr.sbin/bsdinstall/distextract/distextract.c (revision 57bda1b6393f9d89594a24a78ad33bb4e2d0183a)
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 
292118f387SNathan Whitehorn #include <stdio.h>
302118f387SNathan Whitehorn #include <errno.h>
312118f387SNathan Whitehorn #include <limits.h>
322118f387SNathan Whitehorn #include <archive.h>
332118f387SNathan Whitehorn #include <dialog.h>
342118f387SNathan Whitehorn 
352118f387SNathan Whitehorn static int extract_files(int nfiles, const char **files);
362118f387SNathan Whitehorn 
372118f387SNathan Whitehorn int
382118f387SNathan Whitehorn main(void)
392118f387SNathan Whitehorn {
402118f387SNathan Whitehorn 	char *diststring = strdup(getenv("DISTRIBUTIONS"));
412118f387SNathan Whitehorn 	const char **dists;
422118f387SNathan Whitehorn 	int i, retval, ndists = 0;
432118f387SNathan Whitehorn 	for (i = 0; diststring[i] != 0; i++)
442118f387SNathan Whitehorn 		if (isspace(diststring[i]) && !isspace(diststring[i+1]))
452118f387SNathan Whitehorn 			ndists++;
462118f387SNathan Whitehorn 	ndists++; /* Last one */
472118f387SNathan Whitehorn 
482118f387SNathan Whitehorn 	dists = calloc(ndists, sizeof(const char *));
49*57bda1b6SNathan Whitehorn 	if (dists == NULL) {
50*57bda1b6SNathan Whitehorn 		fprintf(stderr, "Out of memory!\n");
51*57bda1b6SNathan Whitehorn 		return (1);
52*57bda1b6SNathan Whitehorn 	}
53*57bda1b6SNathan Whitehorn 
542118f387SNathan Whitehorn 	for (i = 0; i < ndists; i++)
552118f387SNathan Whitehorn 		dists[i] = strsep(&diststring, " \t");
562118f387SNathan Whitehorn 
57*57bda1b6SNathan Whitehorn 	init_dialog(stdin, stdout);
58*57bda1b6SNathan Whitehorn 	dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer");
59*57bda1b6SNathan Whitehorn 	dlg_put_backtitle();
60*57bda1b6SNathan Whitehorn 
61*57bda1b6SNathan Whitehorn 	if (chdir(getenv("BSDINSTALL_CHROOT")) != 0) {
62*57bda1b6SNathan Whitehorn 		char error[512];
63*57bda1b6SNathan Whitehorn 		sprintf(error, "Could could change to directory %s: %s\n",
64*57bda1b6SNathan Whitehorn 		    getenv("BSDINSTALL_DISTDIR"), strerror(errno));
65*57bda1b6SNathan Whitehorn 		dialog_msgbox("Error", error, 0, 0, TRUE);
66*57bda1b6SNathan Whitehorn 		end_dialog();
67*57bda1b6SNathan Whitehorn 		return (1);
68*57bda1b6SNathan Whitehorn 	}
69*57bda1b6SNathan Whitehorn 
702118f387SNathan Whitehorn 	retval = extract_files(ndists, dists);
712118f387SNathan Whitehorn 
72*57bda1b6SNathan Whitehorn 	end_dialog();
73*57bda1b6SNathan Whitehorn 
742118f387SNathan Whitehorn 	free(diststring);
752118f387SNathan Whitehorn 	free(dists);
762118f387SNathan Whitehorn 
772118f387SNathan Whitehorn 	return (retval);
782118f387SNathan Whitehorn }
792118f387SNathan Whitehorn 
802118f387SNathan Whitehorn static int
812118f387SNathan Whitehorn extract_files(int nfiles, const char **files)
822118f387SNathan Whitehorn {
832118f387SNathan Whitehorn 	const char *items[nfiles*2];
842118f387SNathan Whitehorn 	char path[PATH_MAX];
852118f387SNathan Whitehorn 	int archive_files[nfiles];
862118f387SNathan Whitehorn 	int total_files, current_files, archive_file;
872118f387SNathan Whitehorn 	struct archive *archive;
882118f387SNathan Whitehorn 	struct archive_entry *entry;
892118f387SNathan Whitehorn 	char errormsg[512];
902118f387SNathan Whitehorn 	char status[8];
912118f387SNathan Whitehorn 	int i, err, progress, last_progress;
922118f387SNathan Whitehorn 
932118f387SNathan Whitehorn 	err = 0;
942118f387SNathan Whitehorn 	progress = 0;
952118f387SNathan Whitehorn 
962118f387SNathan Whitehorn 	/* Make the transfer list for dialog */
972118f387SNathan Whitehorn 	for (i = 0; i < nfiles; i++) {
982118f387SNathan Whitehorn 		items[i*2] = strrchr(files[i], '/');
992118f387SNathan Whitehorn 		if (items[i*2] != NULL)
1002118f387SNathan Whitehorn 			items[i*2]++;
1012118f387SNathan Whitehorn 		else
1022118f387SNathan Whitehorn 			items[i*2] = files[i];
1032118f387SNathan Whitehorn 		items[i*2 + 1] = "Pending";
1042118f387SNathan Whitehorn 	}
1052118f387SNathan Whitehorn 
1062118f387SNathan Whitehorn 	dialog_msgbox("",
1072118f387SNathan Whitehorn 	    "Checking distribution archives.\nPlease wait...", 0, 0, FALSE);
1082118f387SNathan Whitehorn 
1092118f387SNathan Whitehorn 	/* Open all the archives */
1102118f387SNathan Whitehorn 	total_files = 0;
1112118f387SNathan Whitehorn 	for (i = 0; i < nfiles; i++) {
1122118f387SNathan Whitehorn 		archive = archive_read_new();
1132118f387SNathan Whitehorn 		archive_read_support_format_all(archive);
1142118f387SNathan Whitehorn 		archive_read_support_compression_all(archive);
1152118f387SNathan Whitehorn 		sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]);
1162118f387SNathan Whitehorn 		err = archive_read_open_filename(archive, path, 4096);
1172118f387SNathan Whitehorn 		if (err != ARCHIVE_OK) {
1182118f387SNathan Whitehorn 			snprintf(errormsg, sizeof(errormsg),
1192118f387SNathan Whitehorn 			    "Error while extracting %s: %s\n", items[i*2],
1202118f387SNathan Whitehorn 			    archive_error_string(archive));
1212118f387SNathan Whitehorn 			items[i*2 + 1] = "Failed";
1222118f387SNathan Whitehorn 			dialog_msgbox("Extract Error", errormsg, 0, 0,
1232118f387SNathan Whitehorn 			    TRUE);
124*57bda1b6SNathan Whitehorn 			return (err);
1252118f387SNathan Whitehorn 		}
1262118f387SNathan Whitehorn 		archive_files[i] = 0;
1272118f387SNathan Whitehorn 		while (archive_read_next_header(archive, &entry) == ARCHIVE_OK)
1282118f387SNathan Whitehorn 			archive_files[i]++;
1292118f387SNathan Whitehorn 		total_files += archive_files[i];
1302118f387SNathan Whitehorn 		archive_read_free(archive);
1312118f387SNathan Whitehorn 	}
1322118f387SNathan Whitehorn 
1332118f387SNathan Whitehorn 	current_files = 0;
1342118f387SNathan Whitehorn 
1352118f387SNathan Whitehorn 	for (i = 0; i < nfiles; i++) {
1362118f387SNathan Whitehorn 		archive = archive_read_new();
1372118f387SNathan Whitehorn 		archive_read_support_format_all(archive);
1382118f387SNathan Whitehorn 		archive_read_support_compression_all(archive);
1392118f387SNathan Whitehorn 		sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]);
1402118f387SNathan Whitehorn 		err = archive_read_open_filename(archive, path, 4096);
1412118f387SNathan Whitehorn 
1422118f387SNathan Whitehorn 		items[i*2 + 1] = "In Progress";
1432118f387SNathan Whitehorn 		archive_file = 0;
1442118f387SNathan Whitehorn 
1452118f387SNathan Whitehorn 		while ((err = archive_read_next_header(archive, &entry)) ==
1462118f387SNathan Whitehorn 		    ARCHIVE_OK) {
1472118f387SNathan Whitehorn 			last_progress = progress;
1482118f387SNathan Whitehorn 			progress = (current_files*100)/total_files;
1492118f387SNathan Whitehorn 
1502118f387SNathan Whitehorn 			sprintf(status, "-%d",
1512118f387SNathan Whitehorn 			    (archive_file*100)/archive_files[i]);
1522118f387SNathan Whitehorn 			items[i*2 + 1] = status;
1532118f387SNathan Whitehorn 
1542118f387SNathan Whitehorn 			if (progress > last_progress)
1552118f387SNathan Whitehorn 				dialog_mixedgauge("Archive Extraction",
1562118f387SNathan Whitehorn 				    "Extracting distribution files...", 0, 0,
1572118f387SNathan Whitehorn 				    progress, nfiles,
1582118f387SNathan Whitehorn 				    __DECONST(char **, items));
1592118f387SNathan Whitehorn 
1602118f387SNathan Whitehorn 			err = archive_read_extract(archive, entry,
1612118f387SNathan Whitehorn 			    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER |
1622118f387SNathan Whitehorn 			    ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL |
1632118f387SNathan Whitehorn 			    ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS);
1642118f387SNathan Whitehorn 
1652118f387SNathan Whitehorn 			if (err != ARCHIVE_OK)
1662118f387SNathan Whitehorn 				break;
1672118f387SNathan Whitehorn 
1682118f387SNathan Whitehorn 			archive_file++;
1692118f387SNathan Whitehorn 			current_files++;
1702118f387SNathan Whitehorn 		}
1712118f387SNathan Whitehorn 
1722118f387SNathan Whitehorn 		items[i*2 + 1] = "Done";
1732118f387SNathan Whitehorn 
1742118f387SNathan Whitehorn 		if (err != ARCHIVE_EOF) {
1752118f387SNathan Whitehorn 			snprintf(errormsg, sizeof(errormsg),
1762118f387SNathan Whitehorn 			    "Error while extracting %s: %s\n", items[i*2],
1772118f387SNathan Whitehorn 			    archive_error_string(archive));
1782118f387SNathan Whitehorn 			items[i*2 + 1] = "Failed";
1792118f387SNathan Whitehorn 			dialog_msgbox("Extract Error", errormsg, 0, 0,
1802118f387SNathan Whitehorn 			    TRUE);
181*57bda1b6SNathan Whitehorn 			return (err);
1822118f387SNathan Whitehorn 		}
1832118f387SNathan Whitehorn 
1842118f387SNathan Whitehorn 		archive_read_free(archive);
1852118f387SNathan Whitehorn 	}
1862118f387SNathan Whitehorn 
187*57bda1b6SNathan Whitehorn 	return (0);
1882118f387SNathan Whitehorn }
189