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://[host]/<package>
188 * or file://[devname[:fstype]]/<package>
191 install(char *pkgname)
193 static char buf[256];
194 struct fs_ops *proto;
195 struct preloaded_file *fp;
196 char *e, *s, *currdev;
199 int error, fd, i, local;
201 s = strstr(pkgname, "://");
215 if (i == 4 && !strncasecmp(pkgname, "tftp", i)) {
219 } else if (i == 4 && !strncasecmp(pkgname, "file", i)) {
220 currdev = getenv("currdev");
223 if (*s == '/') { /* file:/// */
228 } else { /* file://devname[:fstype]/ */
230 e = strchr(devname, '/');
233 devnamelen = e - devname;
234 s = e; /* consume devname */
236 if ((e = strchr(devname, ':')) != NULL) {
237 /* could be :fstype */
238 devnamelen = e - devname;
240 case '\0': /* just currdev */
243 proto = &dosfs_fsops;
248 extern struct fs_ops host_fsops;
259 if (proto == NULL && strncmp(devname, "disk", 4) == 0) {
260 proto = &dosfs_fsops;
267 if (devnamelen == 0) {
268 /* default is currdev which ends with ':' */
269 devnamelen = strlen(devname);
270 if (devname[devnamelen - 1] == ':')
278 pkgname = strchr(s, '/');
283 servip.s_addr = inet_addr(s);
284 if (servip.s_addr == htonl(INADDR_NONE))
287 setenv("serverip", inet_ntoa(servip), 1);
293 i = snprintf(buf, sizeof(buf), "%.*s:%s",
294 (int) devnamelen, devname, pkgname);
295 if (i >= (int) sizeof(buf)) {
296 command_errmsg = "package name too long";
299 setenv("install_package", buf, 1);
301 error = pkgfs_init(buf, proto);
303 command_errmsg = "cannot open package";
308 * Point of no return: unload anything that may have been
309 * loaded and prune the environment from harmful variables.
312 unsetenv("vfs.root.mountfrom");
315 * read the metatags file.
317 fd = open("/metatags", O_RDONLY);
319 error = read_metatags(fd);
322 command_errmsg = "cannot load metatags";
327 s = (inst_kernel == NULL) ? "/kernel" : inst_kernel;
328 error = mod_loadkld(s, 0, NULL);
330 command_errmsg = "cannot load kernel from package";
334 /* If there is a loader.rc in the package, execute it */
335 s = (inst_loader_rc == NULL) ? "/loader.rc" : inst_loader_rc;
336 fd = open(s, O_RDONLY);
339 error = interp_include(s);
340 if (error == CMD_ERROR)
345 while (inst_modules != NULL && inst_modules[i] != NULL) {
346 error = mod_loadkld(inst_modules[i], 0, NULL);
348 command_errmsg = "cannot load module(s) from package";
354 s = (inst_rootfs == NULL) ? "/install.iso" : inst_rootfs;
355 if (file_loadraw(s, "mfs_root", 1) == NULL) {
357 command_errmsg = "cannot load root file system";
363 fp = file_findfile(NULL, NULL);
365 file_formats[fp->f_loader]->l_exec(fp);
367 command_errmsg = "unable to start installation";
370 sprintf(buf, "%s (error %d)", command_errmsg, error);
373 exclusive_file_system = NULL;
374 command_errmsg = buf; /* buf is static. */
378 command_errmsg = "invalid URL";
383 command_install(int argc, char *argv[])
387 unsetenv("install_format");
391 if (argc == argidx) {
393 "usage: install [--format] <URL>";
396 if (!strcmp(argv[argidx], "--format")) {
397 setenv("install_format", "yes", 1);
404 return (install(argv[argidx]));