2 * Copyright (c) 2008-2014, Juniper Networks, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 * 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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <netinet/in_systm.h>
40 #include "bootstrap.h"
42 extern struct in_addr servip;
44 extern int pkgfs_init(const char *, struct fs_ops *);
45 extern void pkgfs_cleanup(void);
47 COMMAND_SET(install, "install", "install software package", command_install);
49 static char *inst_kernel;
50 static char **inst_modules;
51 static char *inst_rootfs;
52 static char *inst_loader_rc;
55 setpath(char **what, char *val)
61 len = strlen(val) + 1;
62 rel = (val[0] != '/') ? 1 : 0;
63 path = malloc(len + rel);
67 strcpy(path + rel, val);
74 setmultipath(char ***what, char *val)
77 int count, error, idx;
84 v = (s == NULL) ? NULL : s + 1;
87 *what = calloc(count + 1, sizeof(char *));
91 for (idx = 0; idx < count; idx++) {
95 error = setpath(*what + idx, val);
105 read_metatags(int fd)
112 fsize = read(fd, buf, sizeof(buf));
117 * Assume that if we read a whole buffer worth of data, we
118 * haven't read the entire file. In other words, the buffer
119 * size must always be larger than the file size. That way
120 * we can append a '\0' and use standard string operations.
121 * Return an error if this is not possible.
123 if (fsize == sizeof(buf))
129 while (!error && *tag != '\0') {
130 val = strchr(tag, '=');
136 p = strchr(val, '\n');
143 if (strcmp(tag, "KERNEL") == 0)
144 error = setpath(&inst_kernel, val);
145 else if (strcmp(tag, "MODULES") == 0)
146 error = setmultipath(&inst_modules, val);
147 else if (strcmp(tag, "ROOTFS") == 0)
148 error = setpath(&inst_rootfs, val);
149 else if (strcmp(tag, "LOADER_RC") == 0)
150 error = setpath(&inst_loader_rc, val);
163 if (inst_kernel != NULL) {
167 if (inst_modules != NULL) {
169 while (inst_modules[i] != NULL)
170 free(inst_modules[i++]);
174 if (inst_rootfs != NULL) {
178 if (inst_loader_rc != NULL) {
179 free(inst_loader_rc);
180 inst_loader_rc = NULL;
187 * where: URL = (tftp|file)://[host]/<package>
190 install(char *pkgname)
192 static char buf[256];
193 struct fs_ops *proto;
194 struct preloaded_file *fp;
197 int error, fd, i, local;
199 s = strstr(pkgname, "://");
204 if (i == 4 && !strncasecmp(pkgname, "tftp", i)) {
208 } else if (i == 4 && !strncasecmp(pkgname, "file", i)) {
209 currdev = getenv("currdev");
210 if (currdev != NULL && strcmp(currdev, "pxe0:") == 0) {
215 proto = &dosfs_fsops;
229 pkgname = strchr(s, '/');
234 servip.s_addr = inet_addr(s);
235 if (servip.s_addr == htonl(INADDR_NONE))
238 setenv("serverip", inet_ntoa(servip), 1);
244 if (strlen(devname) + strlen(pkgname) + 2 > sizeof(buf)) {
245 command_errmsg = "package name too long";
248 sprintf(buf, "%s:%s", devname, pkgname);
249 setenv("install_package", buf, 1);
251 error = pkgfs_init(buf, proto);
253 command_errmsg = "cannot open package";
258 * Point of no return: unload anything that may have been
259 * loaded and prune the environment from harmful variables.
262 unsetenv("vfs.root.mountfrom");
265 * read the metatags file.
267 fd = open("/metatags", O_RDONLY);
269 error = read_metatags(fd);
272 command_errmsg = "cannot load metatags";
277 s = (inst_kernel == NULL) ? "/kernel" : inst_kernel;
278 error = mod_loadkld(s, 0, NULL);
280 command_errmsg = "cannot load kernel from package";
284 /* If there is a loader.rc in the package, execute it */
285 s = (inst_loader_rc == NULL) ? "/loader.rc" : inst_loader_rc;
286 fd = open(s, O_RDONLY);
290 if (error == CMD_ERROR)
295 while (inst_modules != NULL && inst_modules[i] != NULL) {
296 error = mod_loadkld(inst_modules[i], 0, NULL);
298 command_errmsg = "cannot load module(s) from package";
304 s = (inst_rootfs == NULL) ? "/install.iso" : inst_rootfs;
305 if (file_loadraw(s, "mfs_root", 1) == NULL) {
307 command_errmsg = "cannot load root file system";
313 fp = file_findfile(NULL, NULL);
315 file_formats[fp->f_loader]->l_exec(fp);
317 command_errmsg = "unable to start installation";
320 sprintf(buf, "%s (error %d)", command_errmsg, error);
323 exclusive_file_system = NULL;
324 command_errmsg = buf; /* buf is static. */
328 command_errmsg = "invalid URL";
333 command_install(int argc, char *argv[])
337 unsetenv("install_format");
341 if (argc == argidx) {
343 "usage: install [--format] <URL>";
346 if (!strcmp(argv[argidx], "--format")) {
347 setenv("install_format", "yes", 1);
354 return (install(argv[argidx]));