distextract.c revision 218915
1218799Snwhitehorn/*-
2218799Snwhitehorn * Copyright (c) 2011 Nathan Whitehorn
3218799Snwhitehorn * All rights reserved.
4218799Snwhitehorn *
5218799Snwhitehorn * Redistribution and use in source and binary forms, with or without
6218799Snwhitehorn * modification, are permitted provided that the following conditions
7218799Snwhitehorn * are met:
8218799Snwhitehorn * 1. Redistributions of source code must retain the above copyright
9218799Snwhitehorn *    notice, this list of conditions and the following disclaimer.
10218799Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
11218799Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
12218799Snwhitehorn *    documentation and/or other materials provided with the distribution.
13218799Snwhitehorn *
14218799Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15218799Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16218799Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17218799Snwhitehorn * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18218799Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19218799Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20218799Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21218799Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22218799Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23218799Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24218799Snwhitehorn * SUCH DAMAGE.
25218799Snwhitehorn *
26218799Snwhitehorn * $FreeBSD: head/usr.sbin/bsdinstall/distextract/distextract.c 218915 2011-02-21 14:28:31Z nwhitehorn $
27218799Snwhitehorn */
28218799Snwhitehorn
29218799Snwhitehorn#include <stdio.h>
30218799Snwhitehorn#include <errno.h>
31218799Snwhitehorn#include <limits.h>
32218799Snwhitehorn#include <archive.h>
33218799Snwhitehorn#include <dialog.h>
34218799Snwhitehorn
35218799Snwhitehornstatic int extract_files(int nfiles, const char **files);
36218799Snwhitehorn
37218799Snwhitehornint
38218799Snwhitehornmain(void)
39218799Snwhitehorn{
40218799Snwhitehorn	char *diststring = strdup(getenv("DISTRIBUTIONS"));
41218799Snwhitehorn	const char **dists;
42218799Snwhitehorn	int i, retval, ndists = 0;
43218799Snwhitehorn	for (i = 0; diststring[i] != 0; i++)
44218799Snwhitehorn		if (isspace(diststring[i]) && !isspace(diststring[i+1]))
45218799Snwhitehorn			ndists++;
46218799Snwhitehorn	ndists++; /* Last one */
47218799Snwhitehorn
48218799Snwhitehorn	dists = calloc(ndists, sizeof(const char *));
49218915Snwhitehorn	if (dists == NULL) {
50218915Snwhitehorn		fprintf(stderr, "Out of memory!\n");
51218915Snwhitehorn		return (1);
52218915Snwhitehorn	}
53218915Snwhitehorn
54218799Snwhitehorn	for (i = 0; i < ndists; i++)
55218799Snwhitehorn		dists[i] = strsep(&diststring, " \t");
56218799Snwhitehorn
57218915Snwhitehorn	init_dialog(stdin, stdout);
58218915Snwhitehorn	dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer");
59218915Snwhitehorn	dlg_put_backtitle();
60218915Snwhitehorn
61218915Snwhitehorn	if (chdir(getenv("BSDINSTALL_CHROOT")) != 0) {
62218915Snwhitehorn		char error[512];
63218915Snwhitehorn		sprintf(error, "Could could change to directory %s: %s\n",
64218915Snwhitehorn		    getenv("BSDINSTALL_DISTDIR"), strerror(errno));
65218915Snwhitehorn		dialog_msgbox("Error", error, 0, 0, TRUE);
66218915Snwhitehorn		end_dialog();
67218915Snwhitehorn		return (1);
68218915Snwhitehorn	}
69218915Snwhitehorn
70218799Snwhitehorn	retval = extract_files(ndists, dists);
71218799Snwhitehorn
72218915Snwhitehorn	end_dialog();
73218915Snwhitehorn
74218799Snwhitehorn	free(diststring);
75218799Snwhitehorn	free(dists);
76218799Snwhitehorn
77218799Snwhitehorn	return (retval);
78218799Snwhitehorn}
79218799Snwhitehorn
80218799Snwhitehornstatic int
81218799Snwhitehornextract_files(int nfiles, const char **files)
82218799Snwhitehorn{
83218799Snwhitehorn	const char *items[nfiles*2];
84218799Snwhitehorn	char path[PATH_MAX];
85218799Snwhitehorn	int archive_files[nfiles];
86218799Snwhitehorn	int total_files, current_files, archive_file;
87218799Snwhitehorn	struct archive *archive;
88218799Snwhitehorn	struct archive_entry *entry;
89218799Snwhitehorn	char errormsg[512];
90218799Snwhitehorn	char status[8];
91218799Snwhitehorn	int i, err, progress, last_progress;
92218799Snwhitehorn
93218799Snwhitehorn	err = 0;
94218799Snwhitehorn	progress = 0;
95218799Snwhitehorn
96218799Snwhitehorn	/* Make the transfer list for dialog */
97218799Snwhitehorn	for (i = 0; i < nfiles; i++) {
98218799Snwhitehorn		items[i*2] = strrchr(files[i], '/');
99218799Snwhitehorn		if (items[i*2] != NULL)
100218799Snwhitehorn			items[i*2]++;
101218799Snwhitehorn		else
102218799Snwhitehorn			items[i*2] = files[i];
103218799Snwhitehorn		items[i*2 + 1] = "Pending";
104218799Snwhitehorn	}
105218799Snwhitehorn
106218799Snwhitehorn	dialog_msgbox("",
107218799Snwhitehorn	    "Checking distribution archives.\nPlease wait...", 0, 0, FALSE);
108218799Snwhitehorn
109218799Snwhitehorn	/* Open all the archives */
110218799Snwhitehorn	total_files = 0;
111218799Snwhitehorn	for (i = 0; i < nfiles; i++) {
112218799Snwhitehorn		archive = archive_read_new();
113218799Snwhitehorn		archive_read_support_format_all(archive);
114218799Snwhitehorn		archive_read_support_compression_all(archive);
115218799Snwhitehorn		sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]);
116218799Snwhitehorn		err = archive_read_open_filename(archive, path, 4096);
117218799Snwhitehorn		if (err != ARCHIVE_OK) {
118218799Snwhitehorn			snprintf(errormsg, sizeof(errormsg),
119218799Snwhitehorn			    "Error while extracting %s: %s\n", items[i*2],
120218799Snwhitehorn			    archive_error_string(archive));
121218799Snwhitehorn			items[i*2 + 1] = "Failed";
122218799Snwhitehorn			dialog_msgbox("Extract Error", errormsg, 0, 0,
123218799Snwhitehorn			    TRUE);
124218915Snwhitehorn			return (err);
125218799Snwhitehorn		}
126218799Snwhitehorn		archive_files[i] = 0;
127218799Snwhitehorn		while (archive_read_next_header(archive, &entry) == ARCHIVE_OK)
128218799Snwhitehorn			archive_files[i]++;
129218799Snwhitehorn		total_files += archive_files[i];
130218799Snwhitehorn		archive_read_free(archive);
131218799Snwhitehorn	}
132218799Snwhitehorn
133218799Snwhitehorn	current_files = 0;
134218799Snwhitehorn
135218799Snwhitehorn	for (i = 0; i < nfiles; i++) {
136218799Snwhitehorn		archive = archive_read_new();
137218799Snwhitehorn		archive_read_support_format_all(archive);
138218799Snwhitehorn		archive_read_support_compression_all(archive);
139218799Snwhitehorn		sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]);
140218799Snwhitehorn		err = archive_read_open_filename(archive, path, 4096);
141218799Snwhitehorn
142218799Snwhitehorn		items[i*2 + 1] = "In Progress";
143218799Snwhitehorn		archive_file = 0;
144218799Snwhitehorn
145218799Snwhitehorn		while ((err = archive_read_next_header(archive, &entry)) ==
146218799Snwhitehorn		    ARCHIVE_OK) {
147218799Snwhitehorn			last_progress = progress;
148218799Snwhitehorn			progress = (current_files*100)/total_files;
149218799Snwhitehorn
150218799Snwhitehorn			sprintf(status, "-%d",
151218799Snwhitehorn			    (archive_file*100)/archive_files[i]);
152218799Snwhitehorn			items[i*2 + 1] = status;
153218799Snwhitehorn
154218799Snwhitehorn			if (progress > last_progress)
155218799Snwhitehorn				dialog_mixedgauge("Archive Extraction",
156218799Snwhitehorn				    "Extracting distribution files...", 0, 0,
157218799Snwhitehorn				    progress, nfiles,
158218799Snwhitehorn				    __DECONST(char **, items));
159218799Snwhitehorn
160218799Snwhitehorn			err = archive_read_extract(archive, entry,
161218799Snwhitehorn			    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER |
162218799Snwhitehorn			    ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL |
163218799Snwhitehorn			    ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS);
164218799Snwhitehorn
165218799Snwhitehorn			if (err != ARCHIVE_OK)
166218799Snwhitehorn				break;
167218799Snwhitehorn
168218799Snwhitehorn			archive_file++;
169218799Snwhitehorn			current_files++;
170218799Snwhitehorn		}
171218799Snwhitehorn
172218799Snwhitehorn		items[i*2 + 1] = "Done";
173218799Snwhitehorn
174218799Snwhitehorn		if (err != ARCHIVE_EOF) {
175218799Snwhitehorn			snprintf(errormsg, sizeof(errormsg),
176218799Snwhitehorn			    "Error while extracting %s: %s\n", items[i*2],
177218799Snwhitehorn			    archive_error_string(archive));
178218799Snwhitehorn			items[i*2 + 1] = "Failed";
179218799Snwhitehorn			dialog_msgbox("Extract Error", errormsg, 0, 0,
180218799Snwhitehorn			    TRUE);
181218915Snwhitehorn			return (err);
182218799Snwhitehorn		}
183218799Snwhitehorn
184218799Snwhitehorn		archive_read_free(archive);
185218799Snwhitehorn	}
186218799Snwhitehorn
187218915Snwhitehorn	return (0);
188218799Snwhitehorn}
189