]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - usr.sbin/bsdinstall/distfetch/distfetch.c
MFC r228048:
[FreeBSD/stable/9.git] / usr.sbin / bsdinstall / distfetch / distfetch.c
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$
27  */
28
29 #include <sys/param.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <fetch.h>
33 #include <dialog.h>
34
35 static int fetch_files(int nfiles, char **urls);
36
37 int
38 main(void)
39 {
40         char *diststring = strdup(getenv("DISTRIBUTIONS"));
41         char **urls;
42         int i, nfetched, 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         urls = calloc(ndists, sizeof(const char *));
49         if (urls == NULL) {
50                 fprintf(stderr, "Out of memory!\n");
51                 free(diststring);
52                 return (1);
53         }
54
55         init_dialog(stdin, stdout);
56         dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer");
57         dlg_put_backtitle();
58
59         for (i = 0; i < ndists; i++) {
60                 urls[i] = malloc(PATH_MAX);
61                 sprintf(urls[i], "%s/%s", getenv("BSDINSTALL_DISTSITE"),
62                     strsep(&diststring, " \t"));
63         }
64
65         if (chdir(getenv("BSDINSTALL_DISTDIR")) != 0) {
66                 char error[512];
67                 sprintf(error, "Could could change to directory %s: %s\n",
68                     getenv("BSDINSTALL_DISTDIR"), strerror(errno));
69                 dialog_msgbox("Error", error, 0, 0, TRUE);
70                 end_dialog();
71                 return (1);
72         }
73
74         nfetched = fetch_files(ndists, urls);
75
76         end_dialog();
77
78         free(diststring);
79         for (i = 0; i < ndists; i++) 
80                 free(urls[i]);
81         free(urls);
82
83         return ((nfetched == ndists) ? 0 : 1);
84 }
85
86 static int
87 fetch_files(int nfiles, char **urls)
88 {
89         const char **items;
90         FILE *fetch_out, *file_out;
91         struct url_stat ustat;
92         off_t total_bytes, current_bytes, fsize;
93         char status[8];
94         char errormsg[512];
95         uint8_t block[4096];
96         size_t chunk;
97         int i, progress, last_progress;
98         int nsuccess = 0; /* Number of files successfully downloaded */
99
100         progress = 0;
101         
102         /* Make the transfer list for dialog */
103         items = calloc(sizeof(char *), nfiles * 2);
104         if (items == NULL) {
105                 fprintf(stderr, "Out of memory!\n");
106                 return (-1);
107         }
108
109         for (i = 0; i < nfiles; i++) {
110                 items[i*2] = strrchr(urls[i], '/');
111                 if (items[i*2] != NULL)
112                         items[i*2]++;
113                 else
114                         items[i*2] = urls[i];
115                 items[i*2 + 1] = "Pending";
116         }
117
118         dialog_msgbox("", "Connecting to server.\nPlease wait...", 0, 0, FALSE);
119
120         /* Try to stat all the files */
121         total_bytes = 0;
122         for (i = 0; i < nfiles; i++) {
123                 if (fetchStatURL(urls[i], &ustat, "") == 0 && ustat.size > 0)
124                         total_bytes += ustat.size;
125         }
126
127         current_bytes = 0;
128         for (i = 0; i < nfiles; i++) {
129                 last_progress = progress;
130                 if (total_bytes == 0)
131                         progress = (i*100)/nfiles;
132
133                 fetchLastErrCode = 0;
134                 fetch_out = fetchXGetURL(urls[i], &ustat, "");
135                 if (fetch_out == NULL) {
136                         snprintf(errormsg, sizeof(errormsg),
137                             "Error while fetching %s: %s\n", urls[i],
138                             fetchLastErrString);
139                         items[i*2 + 1] = "Failed";
140                         dialog_msgbox("Fetch Error", errormsg, 0, 0,
141                             TRUE);
142                         continue;
143                 }
144
145                 items[i*2 + 1] = "In Progress";
146                 fsize = 0;
147                 file_out = fopen(items[i*2], "w+");
148                 if (file_out == NULL) {
149                         snprintf(errormsg, sizeof(errormsg),
150                             "Error while fetching %s: %s\n",
151                             urls[i], strerror(errno));
152                         items[i*2 + 1] = "Failed";
153                         dialog_msgbox("Fetch Error", errormsg, 0, 0,
154                             TRUE);
155                         fclose(fetch_out);
156                         continue;
157                 }
158
159                 while ((chunk = fread(block, 1, sizeof(block), fetch_out))
160                     > 0) {
161                         if (fwrite(block, 1, chunk, file_out) < chunk)
162                                 break;
163
164                         current_bytes += chunk;
165                         fsize += chunk;
166         
167                         if (total_bytes > 0) {
168                                 last_progress = progress;
169                                 progress = (current_bytes*100)/total_bytes; 
170                         }
171
172                         if (ustat.size > 0) {
173                                 sprintf(status, "-%jd", (fsize*100)/ustat.size);
174                                 items[i*2 + 1] = status;
175                         }
176
177                         if (progress > last_progress)
178                                 dialog_mixedgauge("Fetching Distribution",
179                                     "Fetching distribution files...", 0, 0,
180                                     progress, nfiles,
181                                     __DECONST(char **, items));
182                 }
183
184                 if (ustat.size > 0 && fsize < ustat.size) {
185                         if (fetchLastErrCode == 0) 
186                                 snprintf(errormsg, sizeof(errormsg),
187                                     "Error while fetching %s: %s\n",
188                                     urls[i], strerror(errno));
189                         else
190                                 snprintf(errormsg, sizeof(errormsg),
191                                     "Error while fetching %s: %s\n",
192                                     urls[i], fetchLastErrString);
193                         items[i*2 + 1] = "Failed";
194                         dialog_msgbox("Fetch Error", errormsg, 0, 0,
195                                     TRUE);
196                 } else {
197                         items[i*2 + 1] = "Done";
198                         nsuccess++;
199                 }
200
201                 fclose(fetch_out);
202                 fclose(file_out);
203         }
204
205         free(items);
206         return (nsuccess);
207 }
208