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