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$
27218799Snwhitehorn */
28218799Snwhitehorn
29218799Snwhitehorn#include <sys/param.h>
30218799Snwhitehorn#include <stdio.h>
31218799Snwhitehorn#include <errno.h>
32218799Snwhitehorn#include <fetch.h>
33218799Snwhitehorn#include <dialog.h>
34218799Snwhitehorn
35218799Snwhitehornstatic int fetch_files(int nfiles, char **urls);
36218799Snwhitehorn
37218799Snwhitehornint
38218799Snwhitehornmain(void)
39218799Snwhitehorn{
40232200Snwhitehorn	char *diststring;
41218799Snwhitehorn	char **urls;
42218799Snwhitehorn	int i, nfetched, ndists = 0;
43232200Snwhitehorn
44232200Snwhitehorn	if (getenv("DISTRIBUTIONS") == NULL) {
45232200Snwhitehorn		fprintf(stderr, "DISTRIBUTIONS variable is not set\n");
46232200Snwhitehorn		return (1);
47232200Snwhitehorn	}
48232200Snwhitehorn
49232200Snwhitehorn	diststring = strdup(getenv("DISTRIBUTIONS"));
50218799Snwhitehorn	for (i = 0; diststring[i] != 0; i++)
51218799Snwhitehorn		if (isspace(diststring[i]) && !isspace(diststring[i+1]))
52218799Snwhitehorn			ndists++;
53218799Snwhitehorn	ndists++; /* Last one */
54218799Snwhitehorn
55218799Snwhitehorn	urls = calloc(ndists, sizeof(const char *));
56218915Snwhitehorn	if (urls == NULL) {
57218915Snwhitehorn		fprintf(stderr, "Out of memory!\n");
58228048Skevlo		free(diststring);
59218915Snwhitehorn		return (1);
60218915Snwhitehorn	}
61218915Snwhitehorn
62218915Snwhitehorn	init_dialog(stdin, stdout);
63218915Snwhitehorn	dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer");
64218915Snwhitehorn	dlg_put_backtitle();
65218915Snwhitehorn
66218799Snwhitehorn	for (i = 0; i < ndists; i++) {
67218799Snwhitehorn		urls[i] = malloc(PATH_MAX);
68218799Snwhitehorn		sprintf(urls[i], "%s/%s", getenv("BSDINSTALL_DISTSITE"),
69218799Snwhitehorn		    strsep(&diststring, " \t"));
70218799Snwhitehorn	}
71218799Snwhitehorn
72218915Snwhitehorn	if (chdir(getenv("BSDINSTALL_DISTDIR")) != 0) {
73218915Snwhitehorn		char error[512];
74218915Snwhitehorn		sprintf(error, "Could could change to directory %s: %s\n",
75218915Snwhitehorn		    getenv("BSDINSTALL_DISTDIR"), strerror(errno));
76218915Snwhitehorn		dialog_msgbox("Error", error, 0, 0, TRUE);
77218915Snwhitehorn		end_dialog();
78218915Snwhitehorn		return (1);
79218915Snwhitehorn	}
80218915Snwhitehorn
81218799Snwhitehorn	nfetched = fetch_files(ndists, urls);
82218799Snwhitehorn
83218915Snwhitehorn	end_dialog();
84218915Snwhitehorn
85218799Snwhitehorn	free(diststring);
86218799Snwhitehorn	for (i = 0; i < ndists; i++)
87218799Snwhitehorn		free(urls[i]);
88218799Snwhitehorn	free(urls);
89218799Snwhitehorn
90218799Snwhitehorn	return ((nfetched == ndists) ? 0 : 1);
91218799Snwhitehorn}
92218799Snwhitehorn
93218799Snwhitehornstatic int
94218799Snwhitehornfetch_files(int nfiles, char **urls)
95218799Snwhitehorn{
96218799Snwhitehorn	const char **items;
97218799Snwhitehorn	FILE *fetch_out, *file_out;
98218799Snwhitehorn	struct url_stat ustat;
99218799Snwhitehorn	off_t total_bytes, current_bytes, fsize;
100218799Snwhitehorn	char status[8];
101218799Snwhitehorn	char errormsg[512];
102218799Snwhitehorn	uint8_t block[4096];
103218799Snwhitehorn	size_t chunk;
104218799Snwhitehorn	int i, progress, last_progress;
105218799Snwhitehorn	int nsuccess = 0; /* Number of files successfully downloaded */
106218799Snwhitehorn
107218799Snwhitehorn	progress = 0;
108218799Snwhitehorn
109218799Snwhitehorn	/* Make the transfer list for dialog */
110218799Snwhitehorn	items = calloc(sizeof(char *), nfiles * 2);
111218915Snwhitehorn	if (items == NULL) {
112218915Snwhitehorn		fprintf(stderr, "Out of memory!\n");
113218915Snwhitehorn		return (-1);
114218915Snwhitehorn	}
115218915Snwhitehorn
116218799Snwhitehorn	for (i = 0; i < nfiles; i++) {
117218799Snwhitehorn		items[i*2] = strrchr(urls[i], '/');
118218799Snwhitehorn		if (items[i*2] != NULL)
119218799Snwhitehorn			items[i*2]++;
120218799Snwhitehorn		else
121218799Snwhitehorn			items[i*2] = urls[i];
122218799Snwhitehorn		items[i*2 + 1] = "Pending";
123218799Snwhitehorn	}
124218799Snwhitehorn
125218799Snwhitehorn	dialog_msgbox("", "Connecting to server.\nPlease wait...", 0, 0, FALSE);
126218799Snwhitehorn
127218799Snwhitehorn	/* Try to stat all the files */
128218799Snwhitehorn	total_bytes = 0;
129218799Snwhitehorn	for (i = 0; i < nfiles; i++) {
130218799Snwhitehorn		if (fetchStatURL(urls[i], &ustat, "") == 0 && ustat.size > 0)
131218799Snwhitehorn			total_bytes += ustat.size;
132218799Snwhitehorn	}
133218799Snwhitehorn
134218799Snwhitehorn	current_bytes = 0;
135218799Snwhitehorn	for (i = 0; i < nfiles; i++) {
136218799Snwhitehorn		last_progress = progress;
137218799Snwhitehorn		if (total_bytes == 0)
138218799Snwhitehorn			progress = (i*100)/nfiles;
139218799Snwhitehorn
140218799Snwhitehorn		fetchLastErrCode = 0;
141218799Snwhitehorn		fetch_out = fetchXGetURL(urls[i], &ustat, "");
142218799Snwhitehorn		if (fetch_out == NULL) {
143218799Snwhitehorn			snprintf(errormsg, sizeof(errormsg),
144218799Snwhitehorn			    "Error while fetching %s: %s\n", urls[i],
145218799Snwhitehorn			    fetchLastErrString);
146218799Snwhitehorn			items[i*2 + 1] = "Failed";
147218799Snwhitehorn			dialog_msgbox("Fetch Error", errormsg, 0, 0,
148218799Snwhitehorn			    TRUE);
149218799Snwhitehorn			continue;
150218799Snwhitehorn		}
151218799Snwhitehorn
152218799Snwhitehorn		items[i*2 + 1] = "In Progress";
153218799Snwhitehorn		fsize = 0;
154218799Snwhitehorn		file_out = fopen(items[i*2], "w+");
155218799Snwhitehorn		if (file_out == NULL) {
156218799Snwhitehorn			snprintf(errormsg, sizeof(errormsg),
157218799Snwhitehorn			    "Error while fetching %s: %s\n",
158218799Snwhitehorn			    urls[i], strerror(errno));
159218799Snwhitehorn			items[i*2 + 1] = "Failed";
160218799Snwhitehorn			dialog_msgbox("Fetch Error", errormsg, 0, 0,
161218799Snwhitehorn			    TRUE);
162218799Snwhitehorn			fclose(fetch_out);
163218799Snwhitehorn			continue;
164218799Snwhitehorn		}
165218799Snwhitehorn
166218799Snwhitehorn		while ((chunk = fread(block, 1, sizeof(block), fetch_out))
167218799Snwhitehorn		    > 0) {
168218799Snwhitehorn			if (fwrite(block, 1, chunk, file_out) < chunk)
169218799Snwhitehorn				break;
170218799Snwhitehorn
171218799Snwhitehorn			current_bytes += chunk;
172218799Snwhitehorn			fsize += chunk;
173218799Snwhitehorn
174218799Snwhitehorn			if (total_bytes > 0) {
175218799Snwhitehorn				last_progress = progress;
176218799Snwhitehorn				progress = (current_bytes*100)/total_bytes;
177218799Snwhitehorn			}
178218799Snwhitehorn
179218799Snwhitehorn			if (ustat.size > 0) {
180218799Snwhitehorn				sprintf(status, "-%jd", (fsize*100)/ustat.size);
181218799Snwhitehorn				items[i*2 + 1] = status;
182218799Snwhitehorn			}
183218799Snwhitehorn
184218799Snwhitehorn			if (progress > last_progress)
185218799Snwhitehorn				dialog_mixedgauge("Fetching Distribution",
186218799Snwhitehorn				    "Fetching distribution files...", 0, 0,
187218799Snwhitehorn				    progress, nfiles,
188218799Snwhitehorn				    __DECONST(char **, items));
189218799Snwhitehorn		}
190218799Snwhitehorn
191218799Snwhitehorn		if (ustat.size > 0 && fsize < ustat.size) {
192218799Snwhitehorn			if (fetchLastErrCode == 0)
193218799Snwhitehorn				snprintf(errormsg, sizeof(errormsg),
194218799Snwhitehorn				    "Error while fetching %s: %s\n",
195218799Snwhitehorn				    urls[i], strerror(errno));
196218799Snwhitehorn			else
197218799Snwhitehorn				snprintf(errormsg, sizeof(errormsg),
198218799Snwhitehorn				    "Error while fetching %s: %s\n",
199218799Snwhitehorn				    urls[i], fetchLastErrString);
200218799Snwhitehorn			items[i*2 + 1] = "Failed";
201218799Snwhitehorn			dialog_msgbox("Fetch Error", errormsg, 0, 0,
202218799Snwhitehorn				    TRUE);
203218799Snwhitehorn		} else {
204218799Snwhitehorn			items[i*2 + 1] = "Done";
205218799Snwhitehorn			nsuccess++;
206218799Snwhitehorn		}
207218799Snwhitehorn
208218799Snwhitehorn		fclose(fetch_out);
209218799Snwhitehorn		fclose(file_out);
210218799Snwhitehorn	}
211218799Snwhitehorn
212218799Snwhitehorn	free(items);
213218799Snwhitehorn	return (nsuccess);
214218799Snwhitehorn}
215218915Snwhitehorn
216