1269621Smarcel/*- 2269621Smarcel * Copyright (c) 2008-2014, Juniper Networks, Inc. 3269621Smarcel * All rights reserved. 4269621Smarcel * 5269621Smarcel * Redistribution and use in source and binary forms, with or without 6269621Smarcel * modification, are permitted provided that the following conditions 7269621Smarcel * are met: 8269621Smarcel * 1. Redistributions of source code must retain the above copyright 9269621Smarcel * notice, this list of conditions and the following disclaimer. 10269621Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11269621Smarcel * notice, this list of conditions and the following disclaimer in the 12269621Smarcel * documentation and/or other materials provided with the distribution. 13269621Smarcel * 14269621Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15269621Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16269621Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17269621Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18269621Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19269621Smarcel * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20269621Smarcel * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21269621Smarcel * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22269621Smarcel * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23269621Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24269621Smarcel * SUCH DAMAGE. 25269621Smarcel */ 26269621Smarcel 27269621Smarcel#include <sys/cdefs.h> 28269621Smarcel__FBSDID("$FreeBSD: stable/11/stand/common/install.c 329183 2018-02-12 20:51:28Z kevans $"); 29269621Smarcel 30269621Smarcel#include <sys/param.h> 31269621Smarcel#include <sys/socket.h> 32269621Smarcel#include <net/if.h> 33269621Smarcel#include <netinet/in.h> 34269621Smarcel#include <netinet/in_systm.h> 35269621Smarcel 36269621Smarcel#include <stand.h> 37269621Smarcel#include <net.h> 38269621Smarcel#include <string.h> 39269621Smarcel 40269621Smarcel#include "bootstrap.h" 41269621Smarcel 42269621Smarcelextern struct in_addr servip; 43269621Smarcel 44269621Smarcelextern int pkgfs_init(const char *, struct fs_ops *); 45269621Smarcelextern void pkgfs_cleanup(void); 46269621Smarcel 47269621SmarcelCOMMAND_SET(install, "install", "install software package", command_install); 48269621Smarcel 49269621Smarcelstatic char *inst_kernel; 50269621Smarcelstatic char **inst_modules; 51269621Smarcelstatic char *inst_rootfs; 52329011Skevansstatic char *inst_loader_rc; 53269621Smarcel 54269621Smarcelstatic int 55269621Smarcelsetpath(char **what, char *val) 56269621Smarcel{ 57269621Smarcel char *path; 58269621Smarcel size_t len; 59269621Smarcel int rel; 60269621Smarcel 61269621Smarcel len = strlen(val) + 1; 62269621Smarcel rel = (val[0] != '/') ? 1 : 0; 63269621Smarcel path = malloc(len + rel); 64269621Smarcel if (path == NULL) 65269621Smarcel return (ENOMEM); 66269621Smarcel path[0] = '/'; 67269621Smarcel strcpy(path + rel, val); 68269621Smarcel 69269621Smarcel *what = path; 70269621Smarcel return (0); 71269621Smarcel} 72269621Smarcel 73269621Smarcelstatic int 74269621Smarcelsetmultipath(char ***what, char *val) 75269621Smarcel{ 76269621Smarcel char *s, *v; 77269621Smarcel int count, error, idx; 78269621Smarcel 79269621Smarcel count = 0; 80269621Smarcel v = val; 81269621Smarcel do { 82269621Smarcel count++; 83269621Smarcel s = strchr(v, ','); 84269621Smarcel v = (s == NULL) ? NULL : s + 1; 85269621Smarcel } while (v != NULL); 86269621Smarcel 87269621Smarcel *what = calloc(count + 1, sizeof(char *)); 88269621Smarcel if (*what == NULL) 89269621Smarcel return (ENOMEM); 90269621Smarcel 91269621Smarcel for (idx = 0; idx < count; idx++) { 92269621Smarcel s = strchr(val, ','); 93269621Smarcel if (s != NULL) 94269621Smarcel *s++ = '\0'; 95269621Smarcel error = setpath(*what + idx, val); 96269621Smarcel if (error) 97269621Smarcel return (error); 98269621Smarcel val = s; 99269621Smarcel } 100269621Smarcel 101269621Smarcel return (0); 102269621Smarcel} 103269621Smarcel 104269621Smarcelstatic int 105269621Smarcelread_metatags(int fd) 106269621Smarcel{ 107269621Smarcel char buf[1024]; 108269621Smarcel char *p, *tag, *val; 109269621Smarcel ssize_t fsize; 110269621Smarcel int error; 111269621Smarcel 112269621Smarcel fsize = read(fd, buf, sizeof(buf)); 113269621Smarcel if (fsize == -1) 114269621Smarcel return (errno); 115269621Smarcel 116269621Smarcel /* 117269621Smarcel * Assume that if we read a whole buffer worth of data, we 118269621Smarcel * haven't read the entire file. In other words, the buffer 119269621Smarcel * size must always be larger than the file size. That way 120269621Smarcel * we can append a '\0' and use standard string operations. 121269621Smarcel * Return an error if this is not possible. 122269621Smarcel */ 123269621Smarcel if (fsize == sizeof(buf)) 124269621Smarcel return (ENOMEM); 125269621Smarcel 126269621Smarcel buf[fsize] = '\0'; 127269621Smarcel error = 0; 128269621Smarcel tag = buf; 129269621Smarcel while (!error && *tag != '\0') { 130269621Smarcel val = strchr(tag, '='); 131269621Smarcel if (val == NULL) { 132269621Smarcel error = EINVAL; 133269621Smarcel break; 134269621Smarcel } 135269621Smarcel *val++ = '\0'; 136269621Smarcel p = strchr(val, '\n'); 137269621Smarcel if (p == NULL) { 138269621Smarcel error = EINVAL; 139269621Smarcel break; 140269621Smarcel } 141269621Smarcel *p++ = '\0'; 142269621Smarcel 143269621Smarcel if (strcmp(tag, "KERNEL") == 0) 144269621Smarcel error = setpath(&inst_kernel, val); 145269621Smarcel else if (strcmp(tag, "MODULES") == 0) 146269621Smarcel error = setmultipath(&inst_modules, val); 147269621Smarcel else if (strcmp(tag, "ROOTFS") == 0) 148269621Smarcel error = setpath(&inst_rootfs, val); 149329011Skevans else if (strcmp(tag, "LOADER_RC") == 0) 150329011Skevans error = setpath(&inst_loader_rc, val); 151269621Smarcel 152269621Smarcel tag = p; 153269621Smarcel } 154269621Smarcel 155269621Smarcel return (error); 156269621Smarcel} 157269621Smarcel 158269621Smarcelstatic void 159269621Smarcelcleanup(void) 160269621Smarcel{ 161269621Smarcel u_int i; 162269621Smarcel 163269621Smarcel if (inst_kernel != NULL) { 164269621Smarcel free(inst_kernel); 165269621Smarcel inst_kernel = NULL; 166269621Smarcel } 167269621Smarcel if (inst_modules != NULL) { 168269621Smarcel i = 0; 169269621Smarcel while (inst_modules[i] != NULL) 170269621Smarcel free(inst_modules[i++]); 171269621Smarcel free(inst_modules); 172269621Smarcel inst_modules = NULL; 173269621Smarcel } 174269621Smarcel if (inst_rootfs != NULL) { 175269621Smarcel free(inst_rootfs); 176269621Smarcel inst_rootfs = NULL; 177269621Smarcel } 178329011Skevans if (inst_loader_rc != NULL) { 179329011Skevans free(inst_loader_rc); 180329011Skevans inst_loader_rc = NULL; 181329011Skevans } 182269621Smarcel pkgfs_cleanup(); 183269621Smarcel} 184269621Smarcel 185269621Smarcel/* 186269621Smarcel * usage: install URL 187269621Smarcel * where: URL = (tftp|file)://[host]/<package> 188269621Smarcel */ 189269621Smarcelstatic int 190269621Smarcelinstall(char *pkgname) 191269621Smarcel{ 192269621Smarcel static char buf[256]; 193269621Smarcel struct fs_ops *proto; 194269621Smarcel struct preloaded_file *fp; 195269621Smarcel char *s, *currdev; 196269621Smarcel const char *devname; 197269621Smarcel int error, fd, i, local; 198269621Smarcel 199269621Smarcel s = strstr(pkgname, "://"); 200269621Smarcel if (s == NULL) 201269621Smarcel goto invalid_url; 202269621Smarcel 203269621Smarcel i = s - pkgname; 204269621Smarcel if (i == 4 && !strncasecmp(pkgname, "tftp", i)) { 205269621Smarcel devname = "net0"; 206269621Smarcel proto = &tftp_fsops; 207269621Smarcel local = 0; 208269621Smarcel } else if (i == 4 && !strncasecmp(pkgname, "file", i)) { 209269621Smarcel currdev = getenv("currdev"); 210269621Smarcel if (currdev != NULL && strcmp(currdev, "pxe0:") == 0) { 211269621Smarcel devname = "pxe0"; 212269621Smarcel proto = NULL; 213269621Smarcel } else { 214269621Smarcel devname = "disk1"; 215269621Smarcel proto = &dosfs_fsops; 216269621Smarcel } 217269621Smarcel local = 1; 218269621Smarcel } else 219269621Smarcel goto invalid_url; 220269621Smarcel 221269621Smarcel s += 3; 222269621Smarcel if (*s == '\0') 223269621Smarcel goto invalid_url; 224269621Smarcel 225269621Smarcel if (*s != '/' ) { 226269621Smarcel if (local) 227269621Smarcel goto invalid_url; 228269621Smarcel 229269621Smarcel pkgname = strchr(s, '/'); 230269621Smarcel if (pkgname == NULL) 231269621Smarcel goto invalid_url; 232269621Smarcel 233269621Smarcel *pkgname = '\0'; 234269621Smarcel servip.s_addr = inet_addr(s); 235269621Smarcel if (servip.s_addr == htonl(INADDR_NONE)) 236269621Smarcel goto invalid_url; 237269621Smarcel 238269621Smarcel setenv("serverip", inet_ntoa(servip), 1); 239269621Smarcel 240269621Smarcel *pkgname = '/'; 241269621Smarcel } else 242269621Smarcel pkgname = s; 243269621Smarcel 244269621Smarcel if (strlen(devname) + strlen(pkgname) + 2 > sizeof(buf)) { 245269621Smarcel command_errmsg = "package name too long"; 246269621Smarcel return (CMD_ERROR); 247269621Smarcel } 248269621Smarcel sprintf(buf, "%s:%s", devname, pkgname); 249269621Smarcel setenv("install_package", buf, 1); 250269621Smarcel 251269621Smarcel error = pkgfs_init(buf, proto); 252269621Smarcel if (error) { 253269621Smarcel command_errmsg = "cannot open package"; 254269621Smarcel goto fail; 255269621Smarcel } 256269621Smarcel 257269621Smarcel /* 258269621Smarcel * Point of no return: unload anything that may have been 259269621Smarcel * loaded and prune the environment from harmful variables. 260269621Smarcel */ 261269621Smarcel unload(); 262269621Smarcel unsetenv("vfs.root.mountfrom"); 263269621Smarcel 264269621Smarcel /* 265269621Smarcel * read the metatags file. 266269621Smarcel */ 267269621Smarcel fd = open("/metatags", O_RDONLY); 268269621Smarcel if (fd != -1) { 269269621Smarcel error = read_metatags(fd); 270269621Smarcel close(fd); 271269621Smarcel if (error) { 272269621Smarcel command_errmsg = "cannot load metatags"; 273269621Smarcel goto fail; 274269621Smarcel } 275269621Smarcel } 276269621Smarcel 277269621Smarcel s = (inst_kernel == NULL) ? "/kernel" : inst_kernel; 278269621Smarcel error = mod_loadkld(s, 0, NULL); 279269621Smarcel if (error) { 280269621Smarcel command_errmsg = "cannot load kernel from package"; 281269621Smarcel goto fail; 282269621Smarcel } 283269621Smarcel 284329011Skevans /* If there is a loader.rc in the package, execute it */ 285329011Skevans s = (inst_loader_rc == NULL) ? "/loader.rc" : inst_loader_rc; 286329011Skevans fd = open(s, O_RDONLY); 287329011Skevans if (fd != -1) { 288329011Skevans close(fd); 289329183Skevans error = inter_include(s); 290329011Skevans if (error == CMD_ERROR) 291329011Skevans goto fail; 292329011Skevans } 293329011Skevans 294269621Smarcel i = 0; 295269621Smarcel while (inst_modules != NULL && inst_modules[i] != NULL) { 296269621Smarcel error = mod_loadkld(inst_modules[i], 0, NULL); 297269621Smarcel if (error) { 298269621Smarcel command_errmsg = "cannot load module(s) from package"; 299269621Smarcel goto fail; 300269621Smarcel } 301269621Smarcel i++; 302269621Smarcel } 303269621Smarcel 304269621Smarcel s = (inst_rootfs == NULL) ? "/install.iso" : inst_rootfs; 305329011Skevans if (file_loadraw(s, "mfs_root", 1) == NULL) { 306269621Smarcel error = errno; 307269621Smarcel command_errmsg = "cannot load root file system"; 308269621Smarcel goto fail; 309269621Smarcel } 310269621Smarcel 311269621Smarcel cleanup(); 312269621Smarcel 313269621Smarcel fp = file_findfile(NULL, NULL); 314269621Smarcel if (fp != NULL) 315269621Smarcel file_formats[fp->f_loader]->l_exec(fp); 316269621Smarcel error = CMD_ERROR; 317269621Smarcel command_errmsg = "unable to start installation"; 318269621Smarcel 319269621Smarcel fail: 320269621Smarcel sprintf(buf, "%s (error %d)", command_errmsg, error); 321269621Smarcel cleanup(); 322269621Smarcel unload(); 323269621Smarcel exclusive_file_system = NULL; 324269621Smarcel command_errmsg = buf; /* buf is static. */ 325269621Smarcel return (CMD_ERROR); 326269621Smarcel 327269621Smarcel invalid_url: 328269621Smarcel command_errmsg = "invalid URL"; 329269621Smarcel return (CMD_ERROR); 330269621Smarcel} 331269621Smarcel 332269621Smarcelstatic int 333269621Smarcelcommand_install(int argc, char *argv[]) 334269621Smarcel{ 335269621Smarcel int argidx; 336269621Smarcel 337269621Smarcel unsetenv("install_format"); 338269621Smarcel 339269621Smarcel argidx = 1; 340269621Smarcel while (1) { 341269621Smarcel if (argc == argidx) { 342269621Smarcel command_errmsg = 343269621Smarcel "usage: install [--format] <URL>"; 344269621Smarcel return (CMD_ERROR); 345269621Smarcel } 346269621Smarcel if (!strcmp(argv[argidx], "--format")) { 347269621Smarcel setenv("install_format", "yes", 1); 348269621Smarcel argidx++; 349269621Smarcel continue; 350269621Smarcel } 351269621Smarcel break; 352269621Smarcel } 353269621Smarcel 354269621Smarcel return (install(argv[argidx])); 355269621Smarcel} 356