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.
7 * $FreeBSD: src/release/sysinstall/ftp.c,v 1.37.2.8 2002/10/24 13:00:52 nyan Exp $
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. */
53 const char *ftp_dirs[] = { ".", "releases/pc98", "snapshots/pc98",
54 "pub/FreeBSD", "pub/FreeBSD/releases/pc98",
55 "pub/FreeBSD/snapshots/pc98", NULL };
57 const char *ftp_dirs[] = { ".", "releases/"MACHINE, "snapshots/"MACHINE,
58 "pub/FreeBSD", "pub/FreeBSD/releases/"MACHINE,
59 "pub/FreeBSD/snapshots/"MACHINE, NULL };
62 /* Brings up attached network device, if any - takes FTP device as arg */
66 Device *netdev = (Device *)dev->private;
69 return DEVICE_INIT(netdev);
71 return TRUE; /* No net == happy net */
74 /* Brings down attached network device, if any - takes FTP device as arg */
78 Device *netdev = (Device *)dev->private;
81 DEVICE_SHUTDOWN(netdev);
85 mediaInitFTP(Device *dev)
87 int i, code, af, fdir;
88 char *cp, *rel, *hostname, *dir;
89 char *user, *login_name, password[80];
99 /* If we can't initialize the network, bag it! */
104 cp = variable_get(VAR_FTP_PATH);
106 if (DITEM_STATUS(mediaSetFTP(NULL)) == DITEM_FAILURE || (cp = variable_get(VAR_FTP_PATH)) == NULL) {
107 msgConfirm("Unable to get proper FTP path. FTP media not initialized.");
113 hostname = variable_get(VAR_FTP_HOST);
114 dir = variable_get(VAR_FTP_DIR);
115 if (!hostname || !dir) {
116 msgConfirm("Missing FTP host or directory specification. FTP media not initialized,");
120 user = variable_get(VAR_FTP_USER);
121 login_name = (!user || !*user) ? "anonymous" : user;
123 if (variable_get(VAR_FTP_PASS))
124 SAFE_STRCPY(password, variable_get(VAR_FTP_PASS));
125 else if (RunningAsInit)
126 sprintf(password, "installer@%s", variable_get(VAR_HOSTNAME));
131 pw = getpwuid(getuid());
132 user = pw ? pw->pw_name : "ftp";
133 sprintf(password, "%s@%s", user, variable_get(VAR_HOSTNAME));
135 af = variable_cmp(VAR_IPV6_ENABLE, "YES") ? AF_INET : AF_UNSPEC;
136 msgNotify("Logging in to %s@%s..", login_name, hostname);
137 if ((OpenConn = ftpLoginAf(hostname, af, login_name, password, FtpPort, isDebug(), &code)) == NULL) {
138 msgConfirm("Couldn't open FTP connection to %s:\n %s.", hostname, ftpErrString(code));
142 ftpPassive(OpenConn, !strcmp(variable_get(VAR_FTP_STATE), "passive"));
144 if (dir && *dir != '\0') {
145 if ((i = ftpChdir(OpenConn, dir)) != 0) {
147 msgConfirm("No such directory ftp://%s/%s\n"
148 "please check your URL and try again.", hostname, dir);
150 msgConfirm("FTP chdir to ftp://%s/%s returned error status:\n %s.", hostname, dir, ftpErrString(i));
156 * Now that we've verified that the path we're given is ok, let's try to
157 * be a bit intelligent in locating the release we are looking for. First
158 * off, if the release is specified as "__RELEASE" or "any", then just
159 * assume that the current directory is the one we want and give up.
161 rel = variable_get(VAR_RELNAME);
162 if (strcmp(rel, "__RELEASE") && strcmp(rel, "any")) {
164 * Ok, since we have a release variable, let's walk through the list
165 * of directories looking for a release directory. The first one to
166 * match wins. For each case, we chdir to ftp_dirs[fdir] first. If
167 * that fails, we skip to the next one. Otherwise, we try to chdir to
168 * rel. If it succeeds we break out. If it fails, then we go back to
169 * the base directory and try again. Lots of chdirs, but oh well. :)
171 for (fdir = 0; ftp_dirs[fdir]; fdir++) {
172 /* Avoid sending CWD . commands which confuse some ftp servers */
173 if (strcmp(ftp_dirs[fdir], ".") &&
174 (ftpChdir(OpenConn, (char *)ftp_dirs[fdir]) != 0))
176 if (ftpChdir(OpenConn, rel) == 0) {
180 else /* reset to "root" dir for a fresh try */
181 ftpChdir(OpenConn, "/");
185 * If we get here, then all of the directories we tried failed, so
186 * print out the error message and ask the user if they want to try
189 if (!msgYesNo("Warning: Can't find the `%s' distribution on this\n"
190 "FTP server. You may need to visit a different server for\n"
191 "the release you are trying to fetch or go to the Options\n"
192 "menu and to set the release name to explicitly match what's\n"
193 "available on %s (or set to \"any\").\n\n"
194 "Would you like to select another FTP server?",
196 variable_unset(VAR_FTP_PATH);
197 if (DITEM_STATUS(mediaSetFTP(NULL)) != DITEM_FAILURE)
207 if (OpenConn != NULL) {
212 variable_unset(VAR_FTP_PATH);
217 mediaGetFTP(Device *dev, char *file, Boolean probe)
221 char *try, buf[PATH_MAX];
224 msgDebug("No FTP connection open, can't get file %s\n", file);
229 while ((fp = ftpGet(OpenConn, try, 0)) == NULL) {
230 int ftperr = ftpErrno(OpenConn);
232 /* If a hard fail, try to "bounce" the ftp server to clear it */
234 if (ftperr != 421) /* Timeout? */
235 variable_unset(VAR_FTP_PATH);
236 /* If we can't re-initialize, just forget it */
237 DEVICE_SHUTDOWN(dev);
238 if (!DEVICE_INIT(dev)) {
244 variable_unset(VAR_FTP_PATH);
251 /* Try some alternatives */
252 switch (nretries++) {
254 sprintf(buf, "releases/%s", file);
259 sprintf(buf, "%s/%s", variable_get(VAR_RELNAME), file);
264 sprintf(buf, "%s/releases/%s", variable_get(VAR_RELNAME), file);
278 mediaShutdownFTP(Device *dev)
283 if (OpenConn != NULL) {