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 rootip;
43 extern struct in_addr servip;
45 extern int pkgfs_init(const char *, struct fs_ops *);
46 extern void pkgfs_cleanup(void);
48 COMMAND_SET(install, "install", "install software package", command_install);
50 static char *inst_kernel;
51 static char **inst_modules;
52 static char *inst_rootfs;
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);
161 if (inst_kernel != NULL) {
165 if (inst_modules != NULL) {
167 while (inst_modules[i] != NULL)
168 free(inst_modules[i++]);
172 if (inst_rootfs != NULL) {
181 * where: URL = (tftp|file)://[host]/<package>
184 install(char *pkgname)
186 static char buf[256];
187 struct fs_ops *proto;
188 struct preloaded_file *fp;
191 int error, fd, i, local;
193 s = strstr(pkgname, "://");
198 if (i == 4 && !strncasecmp(pkgname, "tftp", i)) {
202 } else if (i == 4 && !strncasecmp(pkgname, "file", i)) {
203 currdev = getenv("currdev");
204 if (currdev != NULL && strcmp(currdev, "pxe0:") == 0) {
209 proto = &dosfs_fsops;
223 pkgname = strchr(s, '/');
228 servip.s_addr = inet_addr(s);
229 if (servip.s_addr == htonl(INADDR_NONE))
232 setenv("serverip", inet_ntoa(servip), 1);
238 if (strlen(devname) + strlen(pkgname) + 2 > sizeof(buf)) {
239 command_errmsg = "package name too long";
242 sprintf(buf, "%s:%s", devname, pkgname);
243 setenv("install_package", buf, 1);
245 error = pkgfs_init(buf, proto);
247 command_errmsg = "cannot open package";
252 * Point of no return: unload anything that may have been
253 * loaded and prune the environment from harmful variables.
256 unsetenv("vfs.root.mountfrom");
259 * read the metatags file.
261 fd = open("/metatags", O_RDONLY);
263 error = read_metatags(fd);
266 command_errmsg = "cannot load metatags";
271 s = (inst_kernel == NULL) ? "/kernel" : inst_kernel;
272 error = mod_loadkld(s, 0, NULL);
274 command_errmsg = "cannot load kernel from package";
279 while (inst_modules != NULL && inst_modules[i] != NULL) {
280 error = mod_loadkld(inst_modules[i], 0, NULL);
282 command_errmsg = "cannot load module(s) from package";
288 s = (inst_rootfs == NULL) ? "/install.iso" : inst_rootfs;
289 if (file_loadraw(s, "mfs_root") == NULL) {
291 command_errmsg = "cannot load root file system";
297 fp = file_findfile(NULL, NULL);
299 file_formats[fp->f_loader]->l_exec(fp);
301 command_errmsg = "unable to start installation";
304 sprintf(buf, "%s (error %d)", command_errmsg, error);
307 exclusive_file_system = NULL;
308 command_errmsg = buf; /* buf is static. */
312 command_errmsg = "invalid URL";
317 command_install(int argc, char *argv[])
321 unsetenv("install_format");
325 if (argc == argidx) {
327 "usage: install [--format] <URL>";
330 if (!strcmp(argv[argidx], "--format")) {
331 setenv("install_format", "yes", 1);
338 return (install(argv[argidx]));