2 * The new sysinstall program.
4 * This is probably the last attempt in the `sysinstall' line, the next
5 * generation being slated to essentially a complete rewrite.
10 * Jordan Hubbard. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer,
17 * verbatim and that no modifications are made prior to this
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
23 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include "sysinstall.h"
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <sys/param.h>
47 Boolean ftpInitted = FALSE;
48 static FILE *OpenConn;
51 /* List of sub directories to look for under a given FTP server. */
52 const char *ftp_dirs[] = { ".", "releases/"MACHINE, "snapshots/"MACHINE,
53 "releases/"MACHINE"/"MACHINE_ARCH, "snapshots/"MACHINE"/"MACHINE_ARCH,
54 "pub/FreeBSD", "pub/FreeBSD/releases/"MACHINE,
55 "pub/FreeBSD/snapshots/"MACHINE,
56 "pub/FreeBSD/releases/"MACHINE"/"MACHINE_ARCH,
57 "pub/FreeBSD/snapshots/"MACHINE"/"MACHINE_ARCH,
60 /* Brings up attached network device, if any - takes FTP device as arg */
64 Device *netdev = (Device *)dev->private;
67 return DEVICE_INIT(netdev);
69 return TRUE; /* No net == happy net */
72 /* Brings down attached network device, if any - takes FTP device as arg */
76 Device *netdev = (Device *)dev->private;
79 DEVICE_SHUTDOWN(netdev);
83 mediaInitFTP(Device *dev)
85 int i, code, af, fdir;
86 char *cp, *rel, *hostname, *dir;
87 char *user, *login_name, password[80];
97 /* If we can't initialize the network, bag it! */
102 cp = variable_get(VAR_FTP_PATH);
104 if (DITEM_STATUS(mediaSetFTP(NULL)) == DITEM_FAILURE || (cp = variable_get(VAR_FTP_PATH)) == NULL) {
105 msgConfirm("Unable to get proper FTP path. FTP media not initialized.");
111 hostname = variable_get(VAR_FTP_HOST);
112 dir = variable_get(VAR_FTP_DIR);
113 if (!hostname || !dir) {
114 msgConfirm("Missing FTP host or directory specification. FTP media not initialized.");
118 user = variable_get(VAR_FTP_USER);
119 login_name = (!user || !*user) ? "anonymous" : user;
121 if (variable_get(VAR_FTP_PASS))
122 SAFE_STRCPY(password, variable_get(VAR_FTP_PASS));
123 else if (RunningAsInit)
124 sprintf(password, "installer@%s", variable_get(VAR_HOSTNAME));
129 pw = getpwuid(getuid());
130 user = pw ? pw->pw_name : "ftp";
131 sprintf(password, "%s@%s", user, variable_get(VAR_HOSTNAME));
133 af = variable_cmp(VAR_IPV6_ENABLE, "YES") ? AF_INET : AF_UNSPEC;
134 msgNotify("Logging in to %s@%s..", login_name, hostname);
135 if ((OpenConn = ftpLoginAf(hostname, af, login_name, password, FtpPort, isDebug(), &code)) == NULL) {
136 msgConfirm("Couldn't open FTP connection to %s:\n %s.", hostname, ftpErrString(code));
140 ftpPassive(OpenConn, !strcmp(variable_get(VAR_FTP_STATE), "passive"));
142 if (dir && *dir != '\0') {
143 if ((i = ftpChdir(OpenConn, dir)) != 0) {
145 msgConfirm("No such directory ftp://%s/%s\n"
146 "please check your URL and try again.", hostname, dir);
148 msgConfirm("FTP chdir to ftp://%s/%s returned error status:\n %s.", hostname, dir, ftpErrString(i));
154 * Now that we've verified that the path we're given is ok, let's try to
155 * be a bit intelligent in locating the release we are looking for. First
156 * off, if the release is specified as "__RELEASE" or "any", then just
157 * assume that the current directory is the one we want and give up.
159 rel = variable_get(VAR_RELNAME);
160 if (strcmp(rel, "__RELEASE") && strcmp(rel, "any")) {
162 * Ok, since we have a release variable, let's walk through the list
163 * of directories looking for a release directory. The first one to
164 * match wins. For each case, we chdir to ftp_dirs[fdir] first. If
165 * that fails, we skip to the next one. Otherwise, we try to chdir to
166 * rel. If it succeeds we break out. If it fails, then we go back to
167 * the base directory and try again. Lots of chdirs, but oh well. :)
169 for (fdir = 0; ftp_dirs[fdir]; fdir++) {
170 /* Avoid sending CWD . commands which confuse some ftp servers */
171 if (strcmp(ftp_dirs[fdir], ".") &&
172 (ftpChdir(OpenConn, (char *)ftp_dirs[fdir]) != 0))
174 if (ftpChdir(OpenConn, rel) == 0) {
178 else /* reset to "root" dir for a fresh try */
179 ftpChdir(OpenConn, "/");
183 * If we get here, then all of the directories we tried failed, so
184 * print out the error message and ask the user if they want to try
187 if (!msgYesNo("Warning: Can't find the `%s' distribution on this\n"
188 "FTP server. You may need to visit a different server for\n"
189 "the release you are trying to fetch or go to the Options\n"
190 "menu and to set the release name to explicitly match what's\n"
191 "available on %s (or set to \"any\").\n\n"
192 "Would you like to select another FTP server?",
194 variable_unset(VAR_FTP_PATH);
195 if (DITEM_STATUS(mediaSetFTP(NULL)) != DITEM_FAILURE)
205 if (OpenConn != NULL) {
210 variable_unset(VAR_FTP_PATH);
215 mediaGetFTP(Device *dev, char *file, Boolean probe)
219 char *try, buf[PATH_MAX];
222 msgDebug("No FTP connection open, can't get file %s\n", file);
227 while ((fp = ftpGet(OpenConn, try, 0)) == NULL) {
228 int ftperr = ftpErrno(OpenConn);
230 /* If a hard fail, try to "bounce" the ftp server to clear it */
232 if (ftperr != 421) /* Timeout? */
233 variable_unset(VAR_FTP_PATH);
234 /* If we can't re-initialize, just forget it */
235 DEVICE_SHUTDOWN(dev);
236 if (!DEVICE_INIT(dev)) {
242 variable_unset(VAR_FTP_PATH);
249 /* Try some alternatives */
250 switch (nretries++) {
252 sprintf(buf, "releases/%s", file);
257 sprintf(buf, "%s/%s", variable_get(VAR_RELNAME), file);
262 sprintf(buf, "%s/releases/%s", variable_get(VAR_RELNAME), file);
276 mediaShutdownFTP(Device *dev)
281 if (OpenConn != NULL) {