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 "pub/FreeBSD", "pub/FreeBSD/releases/"MACHINE,
54 "pub/FreeBSD/snapshots/"MACHINE, NULL };
56 /* Brings up attached network device, if any - takes FTP device as arg */
60 Device *netdev = (Device *)dev->private;
63 return DEVICE_INIT(netdev);
65 return TRUE; /* No net == happy net */
68 /* Brings down attached network device, if any - takes FTP device as arg */
72 Device *netdev = (Device *)dev->private;
75 DEVICE_SHUTDOWN(netdev);
79 mediaInitFTP(Device *dev)
81 int i, code, af, fdir;
82 char *cp, *rel, *hostname, *dir;
83 char *user, *login_name, password[80];
93 /* If we can't initialize the network, bag it! */
98 cp = variable_get(VAR_FTP_PATH);
100 if (DITEM_STATUS(mediaSetFTP(NULL)) == DITEM_FAILURE || (cp = variable_get(VAR_FTP_PATH)) == NULL) {
101 msgConfirm("Unable to get proper FTP path. FTP media not initialized.");
107 hostname = variable_get(VAR_FTP_HOST);
108 dir = variable_get(VAR_FTP_DIR);
109 if (!hostname || !dir) {
110 msgConfirm("Missing FTP host or directory specification. FTP media not initialized,");
114 user = variable_get(VAR_FTP_USER);
115 login_name = (!user || !*user) ? "anonymous" : user;
117 if (variable_get(VAR_FTP_PASS))
118 SAFE_STRCPY(password, variable_get(VAR_FTP_PASS));
119 else if (RunningAsInit)
120 sprintf(password, "installer@%s", variable_get(VAR_HOSTNAME));
125 pw = getpwuid(getuid());
126 user = pw ? pw->pw_name : "ftp";
127 sprintf(password, "%s@%s", user, variable_get(VAR_HOSTNAME));
129 af = variable_cmp(VAR_IPV6_ENABLE, "YES") ? AF_INET : AF_UNSPEC;
130 msgNotify("Logging in to %s@%s..", login_name, hostname);
131 if ((OpenConn = ftpLoginAf(hostname, af, login_name, password, FtpPort, isDebug(), &code)) == NULL) {
132 msgConfirm("Couldn't open FTP connection to %s:\n %s.", hostname, ftpErrString(code));
136 ftpPassive(OpenConn, !strcmp(variable_get(VAR_FTP_STATE), "passive"));
138 if (dir && *dir != '\0') {
139 if ((i = ftpChdir(OpenConn, dir)) != 0) {
141 msgConfirm("No such directory ftp://%s/%s\n"
142 "please check your URL and try again.", hostname, dir);
144 msgConfirm("FTP chdir to ftp://%s/%s returned error status:\n %s.", hostname, dir, ftpErrString(i));
150 * Now that we've verified that the path we're given is ok, let's try to
151 * be a bit intelligent in locating the release we are looking for. First
152 * off, if the release is specified as "__RELEASE" or "any", then just
153 * assume that the current directory is the one we want and give up.
155 rel = variable_get(VAR_RELNAME);
156 if (strcmp(rel, "__RELEASE") && strcmp(rel, "any")) {
158 * Ok, since we have a release variable, let's walk through the list
159 * of directories looking for a release directory. The first one to
160 * match wins. For each case, we chdir to ftp_dirs[fdir] first. If
161 * that fails, we skip to the next one. Otherwise, we try to chdir to
162 * rel. If it succeeds we break out. If it fails, then we go back to
163 * the base directory and try again. Lots of chdirs, but oh well. :)
165 for (fdir = 0; ftp_dirs[fdir]; fdir++) {
166 /* Avoid sending CWD . commands which confuse some ftp servers */
167 if (strcmp(ftp_dirs[fdir], ".") &&
168 (ftpChdir(OpenConn, (char *)ftp_dirs[fdir]) != 0))
170 if (ftpChdir(OpenConn, rel) == 0) {
174 else /* reset to "root" dir for a fresh try */
175 ftpChdir(OpenConn, "/");
179 * If we get here, then all of the directories we tried failed, so
180 * print out the error message and ask the user if they want to try
183 if (!msgYesNo("Warning: Can't find the `%s' distribution on this\n"
184 "FTP server. You may need to visit a different server for\n"
185 "the release you are trying to fetch or go to the Options\n"
186 "menu and to set the release name to explicitly match what's\n"
187 "available on %s (or set to \"any\").\n\n"
188 "Would you like to select another FTP server?",
190 variable_unset(VAR_FTP_PATH);
191 if (DITEM_STATUS(mediaSetFTP(NULL)) != DITEM_FAILURE)
201 if (OpenConn != NULL) {
206 variable_unset(VAR_FTP_PATH);
211 mediaGetFTP(Device *dev, char *file, Boolean probe)
215 char *try, buf[PATH_MAX];
218 msgDebug("No FTP connection open, can't get file %s\n", file);
223 while ((fp = ftpGet(OpenConn, try, 0)) == NULL) {
224 int ftperr = ftpErrno(OpenConn);
226 /* If a hard fail, try to "bounce" the ftp server to clear it */
228 if (ftperr != 421) /* Timeout? */
229 variable_unset(VAR_FTP_PATH);
230 /* If we can't re-initialize, just forget it */
231 DEVICE_SHUTDOWN(dev);
232 if (!DEVICE_INIT(dev)) {
238 variable_unset(VAR_FTP_PATH);
245 /* Try some alternatives */
246 switch (nretries++) {
248 sprintf(buf, "releases/%s", file);
253 sprintf(buf, "%s/%s", variable_get(VAR_RELNAME), file);
258 sprintf(buf, "%s/releases/%s", variable_get(VAR_RELNAME), file);
272 mediaShutdownFTP(Device *dev)
277 if (OpenConn != NULL) {