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