1*ca987d46SWarner Losh /*- 2*ca987d46SWarner Losh * Copyright (c) 2008-2014, Juniper Networks, Inc. 3*ca987d46SWarner Losh * All rights reserved. 4*ca987d46SWarner Losh * 5*ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 6*ca987d46SWarner Losh * modification, are permitted provided that the following conditions 7*ca987d46SWarner Losh * are met: 8*ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 9*ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 10*ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 11*ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 12*ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 13*ca987d46SWarner Losh * 14*ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15*ca987d46SWarner Losh * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16*ca987d46SWarner Losh * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17*ca987d46SWarner Losh * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18*ca987d46SWarner Losh * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19*ca987d46SWarner Losh * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20*ca987d46SWarner Losh * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21*ca987d46SWarner Losh * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22*ca987d46SWarner Losh * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*ca987d46SWarner Losh * SUCH DAMAGE. 25*ca987d46SWarner Losh */ 26*ca987d46SWarner Losh 27*ca987d46SWarner Losh #include <sys/cdefs.h> 28*ca987d46SWarner Losh __FBSDID("$FreeBSD$"); 29*ca987d46SWarner Losh 30*ca987d46SWarner Losh #include <sys/param.h> 31*ca987d46SWarner Losh #include <sys/socket.h> 32*ca987d46SWarner Losh #include <net/if.h> 33*ca987d46SWarner Losh #include <netinet/in.h> 34*ca987d46SWarner Losh #include <netinet/in_systm.h> 35*ca987d46SWarner Losh 36*ca987d46SWarner Losh #include <stand.h> 37*ca987d46SWarner Losh #include <net.h> 38*ca987d46SWarner Losh #include <string.h> 39*ca987d46SWarner Losh 40*ca987d46SWarner Losh #include "bootstrap.h" 41*ca987d46SWarner Losh 42*ca987d46SWarner Losh extern struct in_addr servip; 43*ca987d46SWarner Losh 44*ca987d46SWarner Losh extern int pkgfs_init(const char *, struct fs_ops *); 45*ca987d46SWarner Losh extern void pkgfs_cleanup(void); 46*ca987d46SWarner Losh 47*ca987d46SWarner Losh COMMAND_SET(install, "install", "install software package", command_install); 48*ca987d46SWarner Losh 49*ca987d46SWarner Losh static char *inst_kernel; 50*ca987d46SWarner Losh static char **inst_modules; 51*ca987d46SWarner Losh static char *inst_rootfs; 52*ca987d46SWarner Losh static char *inst_loader_rc; 53*ca987d46SWarner Losh 54*ca987d46SWarner Losh static int 55*ca987d46SWarner Losh setpath(char **what, char *val) 56*ca987d46SWarner Losh { 57*ca987d46SWarner Losh char *path; 58*ca987d46SWarner Losh size_t len; 59*ca987d46SWarner Losh int rel; 60*ca987d46SWarner Losh 61*ca987d46SWarner Losh len = strlen(val) + 1; 62*ca987d46SWarner Losh rel = (val[0] != '/') ? 1 : 0; 63*ca987d46SWarner Losh path = malloc(len + rel); 64*ca987d46SWarner Losh if (path == NULL) 65*ca987d46SWarner Losh return (ENOMEM); 66*ca987d46SWarner Losh path[0] = '/'; 67*ca987d46SWarner Losh strcpy(path + rel, val); 68*ca987d46SWarner Losh 69*ca987d46SWarner Losh *what = path; 70*ca987d46SWarner Losh return (0); 71*ca987d46SWarner Losh } 72*ca987d46SWarner Losh 73*ca987d46SWarner Losh static int 74*ca987d46SWarner Losh setmultipath(char ***what, char *val) 75*ca987d46SWarner Losh { 76*ca987d46SWarner Losh char *s, *v; 77*ca987d46SWarner Losh int count, error, idx; 78*ca987d46SWarner Losh 79*ca987d46SWarner Losh count = 0; 80*ca987d46SWarner Losh v = val; 81*ca987d46SWarner Losh do { 82*ca987d46SWarner Losh count++; 83*ca987d46SWarner Losh s = strchr(v, ','); 84*ca987d46SWarner Losh v = (s == NULL) ? NULL : s + 1; 85*ca987d46SWarner Losh } while (v != NULL); 86*ca987d46SWarner Losh 87*ca987d46SWarner Losh *what = calloc(count + 1, sizeof(char *)); 88*ca987d46SWarner Losh if (*what == NULL) 89*ca987d46SWarner Losh return (ENOMEM); 90*ca987d46SWarner Losh 91*ca987d46SWarner Losh for (idx = 0; idx < count; idx++) { 92*ca987d46SWarner Losh s = strchr(val, ','); 93*ca987d46SWarner Losh if (s != NULL) 94*ca987d46SWarner Losh *s++ = '\0'; 95*ca987d46SWarner Losh error = setpath(*what + idx, val); 96*ca987d46SWarner Losh if (error) 97*ca987d46SWarner Losh return (error); 98*ca987d46SWarner Losh val = s; 99*ca987d46SWarner Losh } 100*ca987d46SWarner Losh 101*ca987d46SWarner Losh return (0); 102*ca987d46SWarner Losh } 103*ca987d46SWarner Losh 104*ca987d46SWarner Losh static int 105*ca987d46SWarner Losh read_metatags(int fd) 106*ca987d46SWarner Losh { 107*ca987d46SWarner Losh char buf[1024]; 108*ca987d46SWarner Losh char *p, *tag, *val; 109*ca987d46SWarner Losh ssize_t fsize; 110*ca987d46SWarner Losh int error; 111*ca987d46SWarner Losh 112*ca987d46SWarner Losh fsize = read(fd, buf, sizeof(buf)); 113*ca987d46SWarner Losh if (fsize == -1) 114*ca987d46SWarner Losh return (errno); 115*ca987d46SWarner Losh 116*ca987d46SWarner Losh /* 117*ca987d46SWarner Losh * Assume that if we read a whole buffer worth of data, we 118*ca987d46SWarner Losh * haven't read the entire file. In other words, the buffer 119*ca987d46SWarner Losh * size must always be larger than the file size. That way 120*ca987d46SWarner Losh * we can append a '\0' and use standard string operations. 121*ca987d46SWarner Losh * Return an error if this is not possible. 122*ca987d46SWarner Losh */ 123*ca987d46SWarner Losh if (fsize == sizeof(buf)) 124*ca987d46SWarner Losh return (ENOMEM); 125*ca987d46SWarner Losh 126*ca987d46SWarner Losh buf[fsize] = '\0'; 127*ca987d46SWarner Losh error = 0; 128*ca987d46SWarner Losh tag = buf; 129*ca987d46SWarner Losh while (!error && *tag != '\0') { 130*ca987d46SWarner Losh val = strchr(tag, '='); 131*ca987d46SWarner Losh if (val == NULL) { 132*ca987d46SWarner Losh error = EINVAL; 133*ca987d46SWarner Losh break; 134*ca987d46SWarner Losh } 135*ca987d46SWarner Losh *val++ = '\0'; 136*ca987d46SWarner Losh p = strchr(val, '\n'); 137*ca987d46SWarner Losh if (p == NULL) { 138*ca987d46SWarner Losh error = EINVAL; 139*ca987d46SWarner Losh break; 140*ca987d46SWarner Losh } 141*ca987d46SWarner Losh *p++ = '\0'; 142*ca987d46SWarner Losh 143*ca987d46SWarner Losh if (strcmp(tag, "KERNEL") == 0) 144*ca987d46SWarner Losh error = setpath(&inst_kernel, val); 145*ca987d46SWarner Losh else if (strcmp(tag, "MODULES") == 0) 146*ca987d46SWarner Losh error = setmultipath(&inst_modules, val); 147*ca987d46SWarner Losh else if (strcmp(tag, "ROOTFS") == 0) 148*ca987d46SWarner Losh error = setpath(&inst_rootfs, val); 149*ca987d46SWarner Losh else if (strcmp(tag, "LOADER_RC") == 0) 150*ca987d46SWarner Losh error = setpath(&inst_loader_rc, val); 151*ca987d46SWarner Losh 152*ca987d46SWarner Losh tag = p; 153*ca987d46SWarner Losh } 154*ca987d46SWarner Losh 155*ca987d46SWarner Losh return (error); 156*ca987d46SWarner Losh } 157*ca987d46SWarner Losh 158*ca987d46SWarner Losh static void 159*ca987d46SWarner Losh cleanup(void) 160*ca987d46SWarner Losh { 161*ca987d46SWarner Losh u_int i; 162*ca987d46SWarner Losh 163*ca987d46SWarner Losh if (inst_kernel != NULL) { 164*ca987d46SWarner Losh free(inst_kernel); 165*ca987d46SWarner Losh inst_kernel = NULL; 166*ca987d46SWarner Losh } 167*ca987d46SWarner Losh if (inst_modules != NULL) { 168*ca987d46SWarner Losh i = 0; 169*ca987d46SWarner Losh while (inst_modules[i] != NULL) 170*ca987d46SWarner Losh free(inst_modules[i++]); 171*ca987d46SWarner Losh free(inst_modules); 172*ca987d46SWarner Losh inst_modules = NULL; 173*ca987d46SWarner Losh } 174*ca987d46SWarner Losh if (inst_rootfs != NULL) { 175*ca987d46SWarner Losh free(inst_rootfs); 176*ca987d46SWarner Losh inst_rootfs = NULL; 177*ca987d46SWarner Losh } 178*ca987d46SWarner Losh if (inst_loader_rc != NULL) { 179*ca987d46SWarner Losh free(inst_loader_rc); 180*ca987d46SWarner Losh inst_loader_rc = NULL; 181*ca987d46SWarner Losh } 182*ca987d46SWarner Losh pkgfs_cleanup(); 183*ca987d46SWarner Losh } 184*ca987d46SWarner Losh 185*ca987d46SWarner Losh /* 186*ca987d46SWarner Losh * usage: install URL 187*ca987d46SWarner Losh * where: URL = (tftp|file)://[host]/<package> 188*ca987d46SWarner Losh */ 189*ca987d46SWarner Losh static int 190*ca987d46SWarner Losh install(char *pkgname) 191*ca987d46SWarner Losh { 192*ca987d46SWarner Losh static char buf[256]; 193*ca987d46SWarner Losh struct fs_ops *proto; 194*ca987d46SWarner Losh struct preloaded_file *fp; 195*ca987d46SWarner Losh char *s, *currdev; 196*ca987d46SWarner Losh const char *devname; 197*ca987d46SWarner Losh int error, fd, i, local; 198*ca987d46SWarner Losh 199*ca987d46SWarner Losh s = strstr(pkgname, "://"); 200*ca987d46SWarner Losh if (s == NULL) 201*ca987d46SWarner Losh goto invalid_url; 202*ca987d46SWarner Losh 203*ca987d46SWarner Losh i = s - pkgname; 204*ca987d46SWarner Losh if (i == 4 && !strncasecmp(pkgname, "tftp", i)) { 205*ca987d46SWarner Losh devname = "net0"; 206*ca987d46SWarner Losh proto = &tftp_fsops; 207*ca987d46SWarner Losh local = 0; 208*ca987d46SWarner Losh } else if (i == 4 && !strncasecmp(pkgname, "file", i)) { 209*ca987d46SWarner Losh currdev = getenv("currdev"); 210*ca987d46SWarner Losh if (currdev != NULL && strcmp(currdev, "pxe0:") == 0) { 211*ca987d46SWarner Losh devname = "pxe0"; 212*ca987d46SWarner Losh proto = NULL; 213*ca987d46SWarner Losh } else { 214*ca987d46SWarner Losh devname = "disk1"; 215*ca987d46SWarner Losh proto = &dosfs_fsops; 216*ca987d46SWarner Losh } 217*ca987d46SWarner Losh local = 1; 218*ca987d46SWarner Losh } else 219*ca987d46SWarner Losh goto invalid_url; 220*ca987d46SWarner Losh 221*ca987d46SWarner Losh s += 3; 222*ca987d46SWarner Losh if (*s == '\0') 223*ca987d46SWarner Losh goto invalid_url; 224*ca987d46SWarner Losh 225*ca987d46SWarner Losh if (*s != '/' ) { 226*ca987d46SWarner Losh if (local) 227*ca987d46SWarner Losh goto invalid_url; 228*ca987d46SWarner Losh 229*ca987d46SWarner Losh pkgname = strchr(s, '/'); 230*ca987d46SWarner Losh if (pkgname == NULL) 231*ca987d46SWarner Losh goto invalid_url; 232*ca987d46SWarner Losh 233*ca987d46SWarner Losh *pkgname = '\0'; 234*ca987d46SWarner Losh servip.s_addr = inet_addr(s); 235*ca987d46SWarner Losh if (servip.s_addr == htonl(INADDR_NONE)) 236*ca987d46SWarner Losh goto invalid_url; 237*ca987d46SWarner Losh 238*ca987d46SWarner Losh setenv("serverip", inet_ntoa(servip), 1); 239*ca987d46SWarner Losh 240*ca987d46SWarner Losh *pkgname = '/'; 241*ca987d46SWarner Losh } else 242*ca987d46SWarner Losh pkgname = s; 243*ca987d46SWarner Losh 244*ca987d46SWarner Losh if (strlen(devname) + strlen(pkgname) + 2 > sizeof(buf)) { 245*ca987d46SWarner Losh command_errmsg = "package name too long"; 246*ca987d46SWarner Losh return (CMD_ERROR); 247*ca987d46SWarner Losh } 248*ca987d46SWarner Losh sprintf(buf, "%s:%s", devname, pkgname); 249*ca987d46SWarner Losh setenv("install_package", buf, 1); 250*ca987d46SWarner Losh 251*ca987d46SWarner Losh error = pkgfs_init(buf, proto); 252*ca987d46SWarner Losh if (error) { 253*ca987d46SWarner Losh command_errmsg = "cannot open package"; 254*ca987d46SWarner Losh goto fail; 255*ca987d46SWarner Losh } 256*ca987d46SWarner Losh 257*ca987d46SWarner Losh /* 258*ca987d46SWarner Losh * Point of no return: unload anything that may have been 259*ca987d46SWarner Losh * loaded and prune the environment from harmful variables. 260*ca987d46SWarner Losh */ 261*ca987d46SWarner Losh unload(); 262*ca987d46SWarner Losh unsetenv("vfs.root.mountfrom"); 263*ca987d46SWarner Losh 264*ca987d46SWarner Losh /* 265*ca987d46SWarner Losh * read the metatags file. 266*ca987d46SWarner Losh */ 267*ca987d46SWarner Losh fd = open("/metatags", O_RDONLY); 268*ca987d46SWarner Losh if (fd != -1) { 269*ca987d46SWarner Losh error = read_metatags(fd); 270*ca987d46SWarner Losh close(fd); 271*ca987d46SWarner Losh if (error) { 272*ca987d46SWarner Losh command_errmsg = "cannot load metatags"; 273*ca987d46SWarner Losh goto fail; 274*ca987d46SWarner Losh } 275*ca987d46SWarner Losh } 276*ca987d46SWarner Losh 277*ca987d46SWarner Losh s = (inst_kernel == NULL) ? "/kernel" : inst_kernel; 278*ca987d46SWarner Losh error = mod_loadkld(s, 0, NULL); 279*ca987d46SWarner Losh if (error) { 280*ca987d46SWarner Losh command_errmsg = "cannot load kernel from package"; 281*ca987d46SWarner Losh goto fail; 282*ca987d46SWarner Losh } 283*ca987d46SWarner Losh 284*ca987d46SWarner Losh /* If there is a loader.rc in the package, execute it */ 285*ca987d46SWarner Losh s = (inst_loader_rc == NULL) ? "/loader.rc" : inst_loader_rc; 286*ca987d46SWarner Losh fd = open(s, O_RDONLY); 287*ca987d46SWarner Losh if (fd != -1) { 288*ca987d46SWarner Losh close(fd); 289*ca987d46SWarner Losh error = include(s); 290*ca987d46SWarner Losh if (error == CMD_ERROR) 291*ca987d46SWarner Losh goto fail; 292*ca987d46SWarner Losh } 293*ca987d46SWarner Losh 294*ca987d46SWarner Losh i = 0; 295*ca987d46SWarner Losh while (inst_modules != NULL && inst_modules[i] != NULL) { 296*ca987d46SWarner Losh error = mod_loadkld(inst_modules[i], 0, NULL); 297*ca987d46SWarner Losh if (error) { 298*ca987d46SWarner Losh command_errmsg = "cannot load module(s) from package"; 299*ca987d46SWarner Losh goto fail; 300*ca987d46SWarner Losh } 301*ca987d46SWarner Losh i++; 302*ca987d46SWarner Losh } 303*ca987d46SWarner Losh 304*ca987d46SWarner Losh s = (inst_rootfs == NULL) ? "/install.iso" : inst_rootfs; 305*ca987d46SWarner Losh if (file_loadraw(s, "mfs_root", 1) == NULL) { 306*ca987d46SWarner Losh error = errno; 307*ca987d46SWarner Losh command_errmsg = "cannot load root file system"; 308*ca987d46SWarner Losh goto fail; 309*ca987d46SWarner Losh } 310*ca987d46SWarner Losh 311*ca987d46SWarner Losh cleanup(); 312*ca987d46SWarner Losh 313*ca987d46SWarner Losh fp = file_findfile(NULL, NULL); 314*ca987d46SWarner Losh if (fp != NULL) 315*ca987d46SWarner Losh file_formats[fp->f_loader]->l_exec(fp); 316*ca987d46SWarner Losh error = CMD_ERROR; 317*ca987d46SWarner Losh command_errmsg = "unable to start installation"; 318*ca987d46SWarner Losh 319*ca987d46SWarner Losh fail: 320*ca987d46SWarner Losh sprintf(buf, "%s (error %d)", command_errmsg, error); 321*ca987d46SWarner Losh cleanup(); 322*ca987d46SWarner Losh unload(); 323*ca987d46SWarner Losh exclusive_file_system = NULL; 324*ca987d46SWarner Losh command_errmsg = buf; /* buf is static. */ 325*ca987d46SWarner Losh return (CMD_ERROR); 326*ca987d46SWarner Losh 327*ca987d46SWarner Losh invalid_url: 328*ca987d46SWarner Losh command_errmsg = "invalid URL"; 329*ca987d46SWarner Losh return (CMD_ERROR); 330*ca987d46SWarner Losh } 331*ca987d46SWarner Losh 332*ca987d46SWarner Losh static int 333*ca987d46SWarner Losh command_install(int argc, char *argv[]) 334*ca987d46SWarner Losh { 335*ca987d46SWarner Losh int argidx; 336*ca987d46SWarner Losh 337*ca987d46SWarner Losh unsetenv("install_format"); 338*ca987d46SWarner Losh 339*ca987d46SWarner Losh argidx = 1; 340*ca987d46SWarner Losh while (1) { 341*ca987d46SWarner Losh if (argc == argidx) { 342*ca987d46SWarner Losh command_errmsg = 343*ca987d46SWarner Losh "usage: install [--format] <URL>"; 344*ca987d46SWarner Losh return (CMD_ERROR); 345*ca987d46SWarner Losh } 346*ca987d46SWarner Losh if (!strcmp(argv[argidx], "--format")) { 347*ca987d46SWarner Losh setenv("install_format", "yes", 1); 348*ca987d46SWarner Losh argidx++; 349*ca987d46SWarner Losh continue; 350*ca987d46SWarner Losh } 351*ca987d46SWarner Losh break; 352*ca987d46SWarner Losh } 353*ca987d46SWarner Losh 354*ca987d46SWarner Losh return (install(argv[argidx])); 355*ca987d46SWarner Losh } 356