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 #include <sys/param.h>
29 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <netinet/in_systm.h>
38 #include "bootstrap.h"
40 extern struct in_addr servip;
42 extern int pkgfs_init(const char *, struct fs_ops *);
43 extern void pkgfs_cleanup(void);
45 COMMAND_SET(install, "install", "install software package", command_install);
47 static char *inst_kernel;
48 static char **inst_modules;
49 static char *inst_rootfs;
50 static char *inst_loader_rc;
53 setpath(char **what, char *val)
59 len = strlen(val) + 1;
60 rel = (val[0] != '/') ? 1 : 0;
61 path = malloc(len + rel);
65 strcpy(path + rel, val);
72 setmultipath(char ***what, char *val)
75 int count, error, idx;
82 v = (s == NULL) ? NULL : s + 1;
85 *what = calloc(count + 1, sizeof(char *));
89 for (idx = 0; idx < count; idx++) {
93 error = setpath(*what + idx, val);
103 read_metatags(int fd)
110 fsize = read(fd, buf, sizeof(buf));
115 * Assume that if we read a whole buffer worth of data, we
116 * haven't read the entire file. In other words, the buffer
117 * size must always be larger than the file size. That way
118 * we can append a '\0' and use standard string operations.
119 * Return an error if this is not possible.
121 if (fsize == sizeof(buf))
127 while (!error && *tag != '\0') {
128 val = strchr(tag, '=');
134 p = strchr(val, '\n');
141 if (strcmp(tag, "KERNEL") == 0)
142 error = setpath(&inst_kernel, val);
143 else if (strcmp(tag, "MODULES") == 0)
144 error = setmultipath(&inst_modules, val);
145 else if (strcmp(tag, "ROOTFS") == 0)
146 error = setpath(&inst_rootfs, val);
147 else if (strcmp(tag, "LOADER_RC") == 0)
148 error = setpath(&inst_loader_rc, 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) {
176 if (inst_loader_rc != NULL) {
177 free(inst_loader_rc);
178 inst_loader_rc = NULL;
185 * where: URL = tftp://[host]/<package>
186 * or file://[devname[:fstype]]/<package>
189 install(char *pkgname)
191 static char buf[256];
192 struct fs_ops *proto;
193 struct preloaded_file *fp;
194 char *e, *s, *currdev;
197 int error, fd, i, local;
199 s = strstr(pkgname, "://");
213 if (i == 4 && !strncasecmp(pkgname, "tftp", i)) {
217 } else if (i == 4 && !strncasecmp(pkgname, "file", i)) {
218 currdev = getenv("currdev");
221 if (*s == '/') { /* file:/// */
226 } else { /* file://devname[:fstype]/ */
228 e = strchr(devname, '/');
231 devnamelen = e - devname;
232 s = e; /* consume devname */
234 if ((e = strchr(devname, ':')) != NULL) {
235 /* could be :fstype */
236 devnamelen = e - devname;
238 case '\0': /* just currdev */
241 proto = &dosfs_fsops;
246 extern struct fs_ops host_fsops;
257 if (proto == NULL && strncmp(devname, "disk", 4) == 0) {
258 proto = &dosfs_fsops;
265 if (devnamelen == 0) {
266 /* default is currdev which ends with ':' */
267 devnamelen = strlen(devname);
268 if (devname[devnamelen - 1] == ':')
276 pkgname = strchr(s, '/');
281 servip.s_addr = inet_addr(s);
282 if (servip.s_addr == htonl(INADDR_NONE))
285 setenv("serverip", inet_ntoa(servip), 1);
291 i = snprintf(buf, sizeof(buf), "%.*s:%s",
292 (int) devnamelen, devname, pkgname);
293 if (i >= (int) sizeof(buf)) {
294 command_errmsg = "package name too long";
297 setenv("install_package", buf, 1);
299 error = pkgfs_init(buf, proto);
301 command_errmsg = "cannot open package";
306 * Point of no return: unload anything that may have been
307 * loaded and prune the environment from harmful variables.
310 unsetenv("vfs.root.mountfrom");
313 * read the metatags file.
315 fd = open("/metatags", O_RDONLY);
317 error = read_metatags(fd);
320 command_errmsg = "cannot load metatags";
325 s = (inst_kernel == NULL) ? "/kernel" : inst_kernel;
326 error = mod_loadkld(s, 0, NULL);
328 command_errmsg = "cannot load kernel from package";
332 /* If there is a loader.rc in the package, execute it */
333 s = (inst_loader_rc == NULL) ? "/loader.rc" : inst_loader_rc;
334 fd = open(s, O_RDONLY);
337 error = interp_include(s);
338 if (error == CMD_ERROR)
343 while (inst_modules != NULL && inst_modules[i] != NULL) {
344 error = mod_loadkld(inst_modules[i], 0, NULL);
346 command_errmsg = "cannot load module(s) from package";
352 s = (inst_rootfs == NULL) ? "/install.iso" : inst_rootfs;
353 if (file_loadraw(s, "mfs_root", 1) == NULL) {
355 command_errmsg = "cannot load root file system";
361 fp = file_findfile(NULL, NULL);
363 file_formats[fp->f_loader]->l_exec(fp);
365 command_errmsg = "unable to start installation";
368 sprintf(buf, "%s (error %d)", command_errmsg, error);
371 exclusive_file_system = NULL;
372 command_errmsg = buf; /* buf is static. */
376 command_errmsg = "invalid URL";
381 command_install(int argc, char *argv[])
385 unsetenv("install_format");
389 if (argc == argidx) {
391 "usage: install [--format] <URL>";
394 if (!strcmp(argv[argidx], "--format")) {
395 setenv("install_format", "yes", 1);
402 return (install(argv[argidx]));