2 * Copyright (c) 2011 Nathan Whitehorn
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/param.h>
36 static int extract_files(int nfiles, const char **files);
43 int i, retval, ndists = 0;
45 if (getenv("DISTRIBUTIONS") == NULL) {
46 fprintf(stderr, "DISTRIBUTIONS variable is not set\n");
50 diststring = strdup(getenv("DISTRIBUTIONS"));
51 for (i = 0; diststring[i] != 0; i++)
52 if (isspace(diststring[i]) && !isspace(diststring[i+1]))
54 ndists++; /* Last one */
56 dists = calloc(ndists, sizeof(const char *));
58 fprintf(stderr, "Out of memory!\n");
63 for (i = 0; i < ndists; i++)
64 dists[i] = strsep(&diststring, " \t");
66 init_dialog(stdin, stdout);
67 dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer");
70 if (chdir(getenv("BSDINSTALL_CHROOT")) != 0) {
72 sprintf(error, "Could could change to directory %s: %s\n",
73 getenv("BSDINSTALL_DISTDIR"), strerror(errno));
74 dialog_msgbox("Error", error, 0, 0, TRUE);
79 retval = extract_files(ndists, dists);
90 count_files(const char *file)
92 struct archive *archive;
93 struct archive_entry *entry;
94 static FILE *manifest = NULL;
95 char path[MAXPATHLEN];
99 if (manifest == NULL) {
100 sprintf(path, "%s/MANIFEST", getenv("BSDINSTALL_DISTDIR"));
101 manifest = fopen(path, "r");
104 if (manifest != NULL) {
109 while (fgets(line, sizeof(line), manifest) != NULL) {
111 tok1 = strsep(&tok2, "\t");
112 if (tok1 == NULL || strcmp(tok1, file) != 0)
116 * We're at the right manifest line. The file count is
117 * in the third element
119 tok1 = strsep(&tok2, "\t");
120 tok1 = strsep(&tok2, "\t");
126 /* Either we didn't have a manifest, or this archive wasn't there */
127 archive = archive_read_new();
128 archive_read_support_format_all(archive);
129 archive_read_support_compression_all(archive);
130 sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), file);
131 err = archive_read_open_filename(archive, path, 4096);
132 if (err != ARCHIVE_OK) {
133 snprintf(errormsg, sizeof(errormsg),
134 "Error while extracting %s: %s\n", file,
135 archive_error_string(archive));
136 dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE);
141 while (archive_read_next_header(archive, &entry) == ARCHIVE_OK)
143 archive_read_free(archive);
149 extract_files(int nfiles, const char **files)
151 const char *items[nfiles*2];
153 int archive_files[nfiles];
154 int total_files, current_files, archive_file;
155 struct archive *archive;
156 struct archive_entry *entry;
159 int i, err, progress, last_progress;
164 /* Make the transfer list for dialog */
165 for (i = 0; i < nfiles; i++) {
166 items[i*2] = strrchr(files[i], '/');
167 if (items[i*2] != NULL)
170 items[i*2] = files[i];
171 items[i*2 + 1] = "Pending";
175 "Checking distribution archives.\nPlease wait...", 0, 0, FALSE);
177 /* Count all the files */
179 for (i = 0; i < nfiles; i++) {
180 archive_files[i] = count_files(files[i]);
181 if (archive_files[i] < 0)
183 total_files += archive_files[i];
188 for (i = 0; i < nfiles; i++) {
189 archive = archive_read_new();
190 archive_read_support_format_all(archive);
191 archive_read_support_compression_all(archive);
192 sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]);
193 err = archive_read_open_filename(archive, path, 4096);
195 items[i*2 + 1] = "In Progress";
198 while ((err = archive_read_next_header(archive, &entry)) ==
200 last_progress = progress;
201 progress = (current_files*100)/total_files;
203 sprintf(status, "-%d",
204 (archive_file*100)/archive_files[i]);
205 items[i*2 + 1] = status;
207 if (progress > last_progress)
208 dialog_mixedgauge("Archive Extraction",
209 "Extracting distribution files...", 0, 0,
211 __DECONST(char **, items));
213 err = archive_read_extract(archive, entry,
214 ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER |
215 ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL |
216 ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS);
218 if (err != ARCHIVE_OK)
225 items[i*2 + 1] = "Done";
227 if (err != ARCHIVE_EOF) {
228 snprintf(errormsg, sizeof(errormsg),
229 "Error while extracting %s: %s\n", items[i*2],
230 archive_error_string(archive));
231 items[i*2 + 1] = "Failed";
232 dialog_msgbox("Extract Error", errormsg, 0, 0,
237 archive_read_free(archive);