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