1*0181461bSKeith M Wesolowski /* 2*0181461bSKeith M Wesolowski * This file and its contents are supplied under the terms of the 3*0181461bSKeith M Wesolowski * Common Development and Distribution License ("CDDL"), version 1.0. 4*0181461bSKeith M Wesolowski * You may only use this file in accordance with the terms of version 5*0181461bSKeith M Wesolowski * 1.0 of the CDDL. 6*0181461bSKeith M Wesolowski * 7*0181461bSKeith M Wesolowski * A full copy of the text of the CDDL should have accompanied this 8*0181461bSKeith M Wesolowski * source. A copy of the CDDL is also available via the Internet at 9*0181461bSKeith M Wesolowski * http://www.illumos.org/license/CDDL. 10*0181461bSKeith M Wesolowski */ 11*0181461bSKeith M Wesolowski 12*0181461bSKeith M Wesolowski /* 13*0181461bSKeith M Wesolowski * Copyright 2013 Joyent, Inc. All rights reserved. 14*0181461bSKeith M Wesolowski */ 15*0181461bSKeith M Wesolowski 16*0181461bSKeith M Wesolowski #include <sys/bootconf.h> 17*0181461bSKeith M Wesolowski #include <sys/types.h> 18*0181461bSKeith M Wesolowski #include <sys/param.h> 19*0181461bSKeith M Wesolowski #include <sys/vnode.h> 20*0181461bSKeith M Wesolowski #include <sys/fs/ufs_fsdir.h> 21*0181461bSKeith M Wesolowski #include <sys/fs/ufs_fs.h> 22*0181461bSKeith M Wesolowski #include <sys/fs/ufs_inode.h> 23*0181461bSKeith M Wesolowski #include <sys/sysmacros.h> 24*0181461bSKeith M Wesolowski #include <sys/bootvfs.h> 25*0181461bSKeith M Wesolowski #include <sys/bootinfo.h> 26*0181461bSKeith M Wesolowski #include <sys/filep.h> 27*0181461bSKeith M Wesolowski 28*0181461bSKeith M Wesolowski #ifdef _BOOT 29*0181461bSKeith M Wesolowski #include "../common/util.h" 30*0181461bSKeith M Wesolowski #else 31*0181461bSKeith M Wesolowski #include <sys/sunddi.h> 32*0181461bSKeith M Wesolowski #endif 33*0181461bSKeith M Wesolowski 34*0181461bSKeith M Wesolowski #define MAX_FILES MAX_BOOT_MODULES 35*0181461bSKeith M Wesolowski #define MAX_FDS 256 36*0181461bSKeith M Wesolowski 37*0181461bSKeith M Wesolowski extern void *bkmem_alloc(size_t); 38*0181461bSKeith M Wesolowski extern void bkmem_free(void *, size_t); 39*0181461bSKeith M Wesolowski 40*0181461bSKeith M Wesolowski /* 41*0181461bSKeith M Wesolowski * TODO: Replace these declarations with inclusion of the ordinary userland 42*0181461bSKeith M Wesolowski * bootfs headers once they're available. 43*0181461bSKeith M Wesolowski */ 44*0181461bSKeith M Wesolowski typedef struct bfile { 45*0181461bSKeith M Wesolowski char bf_name[MAXPATHLEN]; 46*0181461bSKeith M Wesolowski caddr_t bf_addr; 47*0181461bSKeith M Wesolowski size_t bf_size; 48*0181461bSKeith M Wesolowski struct bfile *bf_next; 49*0181461bSKeith M Wesolowski uint64_t bf_ino; 50*0181461bSKeith M Wesolowski } bfile_t; 51*0181461bSKeith M Wesolowski 52*0181461bSKeith M Wesolowski typedef struct bf_fd { 53*0181461bSKeith M Wesolowski bfile_t *fd_file; 54*0181461bSKeith M Wesolowski off_t fd_pos; 55*0181461bSKeith M Wesolowski } bf_fd_t; 56*0181461bSKeith M Wesolowski 57*0181461bSKeith M Wesolowski static bfile_t *head; 58*0181461bSKeith M Wesolowski static uint_t init_done; 59*0181461bSKeith M Wesolowski static bf_fd_t fds[MAX_FDS]; 60*0181461bSKeith M Wesolowski 61*0181461bSKeith M Wesolowski static char cpath[MAXPATHLEN]; /* For canonicalising filenames */ 62*0181461bSKeith M Wesolowski 63*0181461bSKeith M Wesolowski static void bbootfs_closeall(int); 64*0181461bSKeith M Wesolowski 65*0181461bSKeith M Wesolowski static void 66*0181461bSKeith M Wesolowski canonicalise(const char *fn, char *out) 67*0181461bSKeith M Wesolowski { 68*0181461bSKeith M Wesolowski const char *p; 69*0181461bSKeith M Wesolowski char *q, *s; 70*0181461bSKeith M Wesolowski char *last; 71*0181461bSKeith M Wesolowski char *oc; 72*0181461bSKeith M Wesolowski int is_slash = 0; 73*0181461bSKeith M Wesolowski static char scratch[MAXPATHLEN]; 74*0181461bSKeith M Wesolowski 75*0181461bSKeith M Wesolowski if (fn == NULL) { 76*0181461bSKeith M Wesolowski *out = '\0'; 77*0181461bSKeith M Wesolowski return; 78*0181461bSKeith M Wesolowski } 79*0181461bSKeith M Wesolowski 80*0181461bSKeith M Wesolowski /* 81*0181461bSKeith M Wesolowski * Remove leading slashes and condense all multiple slashes into one. 82*0181461bSKeith M Wesolowski */ 83*0181461bSKeith M Wesolowski p = fn; 84*0181461bSKeith M Wesolowski while (*p == '/') 85*0181461bSKeith M Wesolowski ++p; 86*0181461bSKeith M Wesolowski 87*0181461bSKeith M Wesolowski for (q = scratch; *p != '\0'; p++) { 88*0181461bSKeith M Wesolowski if (*p == '/' && !is_slash) { 89*0181461bSKeith M Wesolowski *q++ = '/'; 90*0181461bSKeith M Wesolowski is_slash = 1; 91*0181461bSKeith M Wesolowski } else if (*p != '/') { 92*0181461bSKeith M Wesolowski *q++ = *p; 93*0181461bSKeith M Wesolowski is_slash = 0; 94*0181461bSKeith M Wesolowski } 95*0181461bSKeith M Wesolowski } 96*0181461bSKeith M Wesolowski *q = '\0'; 97*0181461bSKeith M Wesolowski 98*0181461bSKeith M Wesolowski if (strncmp(scratch, "system/boot/", 12) == 0 || 99*0181461bSKeith M Wesolowski strcmp(scratch, "system/boot") == 0) { 100*0181461bSKeith M Wesolowski s = scratch + 12; 101*0181461bSKeith M Wesolowski } else { 102*0181461bSKeith M Wesolowski s = scratch; 103*0181461bSKeith M Wesolowski } 104*0181461bSKeith M Wesolowski 105*0181461bSKeith M Wesolowski for (last = strsep(&s, "/"), q = oc = out; last != NULL; 106*0181461bSKeith M Wesolowski last = strsep(&s, "/")) { 107*0181461bSKeith M Wesolowski if (strcmp(last, ".") == 0) 108*0181461bSKeith M Wesolowski continue; 109*0181461bSKeith M Wesolowski if (strcmp(last, "..") == 0) { 110*0181461bSKeith M Wesolowski for (oc = q; oc > out && *oc != '/'; oc--) 111*0181461bSKeith M Wesolowski ; 112*0181461bSKeith M Wesolowski q = oc; 113*0181461bSKeith M Wesolowski continue; 114*0181461bSKeith M Wesolowski } 115*0181461bSKeith M Wesolowski if (q > out) 116*0181461bSKeith M Wesolowski *q++ = '/'; 117*0181461bSKeith M Wesolowski q += snprintf(q, MAXPATHLEN - (q - out), "%s", last); 118*0181461bSKeith M Wesolowski } 119*0181461bSKeith M Wesolowski 120*0181461bSKeith M Wesolowski *q = '\0'; 121*0181461bSKeith M Wesolowski } 122*0181461bSKeith M Wesolowski 123*0181461bSKeith M Wesolowski /* ARGSUSED */ 124*0181461bSKeith M Wesolowski static int 125*0181461bSKeith M Wesolowski bbootfs_mountroot(char *str) 126*0181461bSKeith M Wesolowski { 127*0181461bSKeith M Wesolowski return (-1); 128*0181461bSKeith M Wesolowski } 129*0181461bSKeith M Wesolowski 130*0181461bSKeith M Wesolowski static int 131*0181461bSKeith M Wesolowski bbootfs_unmountroot(void) 132*0181461bSKeith M Wesolowski { 133*0181461bSKeith M Wesolowski return (-1); 134*0181461bSKeith M Wesolowski } 135*0181461bSKeith M Wesolowski 136*0181461bSKeith M Wesolowski static int 137*0181461bSKeith M Wesolowski bbootfs_init(void) 138*0181461bSKeith M Wesolowski { 139*0181461bSKeith M Wesolowski bfile_t *fp; 140*0181461bSKeith M Wesolowski char propname[32]; 141*0181461bSKeith M Wesolowski uint64_t propval; 142*0181461bSKeith M Wesolowski uint_t i; 143*0181461bSKeith M Wesolowski 144*0181461bSKeith M Wesolowski for (i = 0; i < MAX_FILES; i++) { 145*0181461bSKeith M Wesolowski (void) snprintf(propname, sizeof (propname), 146*0181461bSKeith M Wesolowski "module-name-%u", i); 147*0181461bSKeith M Wesolowski if (do_bsys_getproplen(NULL, propname) < 0) 148*0181461bSKeith M Wesolowski break; 149*0181461bSKeith M Wesolowski 150*0181461bSKeith M Wesolowski if ((fp = bkmem_alloc(sizeof (bfile_t))) == NULL) { 151*0181461bSKeith M Wesolowski bbootfs_closeall(1); 152*0181461bSKeith M Wesolowski return (-1); 153*0181461bSKeith M Wesolowski } 154*0181461bSKeith M Wesolowski 155*0181461bSKeith M Wesolowski (void) do_bsys_getprop(NULL, propname, cpath); 156*0181461bSKeith M Wesolowski canonicalise(cpath, fp->bf_name); 157*0181461bSKeith M Wesolowski 158*0181461bSKeith M Wesolowski (void) snprintf(propname, sizeof (propname), 159*0181461bSKeith M Wesolowski "module-addr-%u", i); 160*0181461bSKeith M Wesolowski if (do_bsys_getproplen(NULL, propname) != sizeof (uint64_t)) { 161*0181461bSKeith M Wesolowski bkmem_free(fp, sizeof (bfile_t)); 162*0181461bSKeith M Wesolowski continue; 163*0181461bSKeith M Wesolowski } 164*0181461bSKeith M Wesolowski (void) do_bsys_getprop(NULL, propname, &propval); 165*0181461bSKeith M Wesolowski fp->bf_addr = (void *)(uintptr_t)propval; 166*0181461bSKeith M Wesolowski 167*0181461bSKeith M Wesolowski (void) snprintf(propname, sizeof (propname), 168*0181461bSKeith M Wesolowski "module-size-%u", i); 169*0181461bSKeith M Wesolowski if (do_bsys_getproplen(NULL, propname) != sizeof (uint64_t)) { 170*0181461bSKeith M Wesolowski bkmem_free(fp, sizeof (bfile_t)); 171*0181461bSKeith M Wesolowski continue; 172*0181461bSKeith M Wesolowski } 173*0181461bSKeith M Wesolowski (void) do_bsys_getprop(NULL, propname, &propval); 174*0181461bSKeith M Wesolowski fp->bf_size = (size_t)propval; 175*0181461bSKeith M Wesolowski fp->bf_ino = i; 176*0181461bSKeith M Wesolowski 177*0181461bSKeith M Wesolowski fp->bf_next = head; 178*0181461bSKeith M Wesolowski head = fp; 179*0181461bSKeith M Wesolowski } 180*0181461bSKeith M Wesolowski 181*0181461bSKeith M Wesolowski return (0); 182*0181461bSKeith M Wesolowski } 183*0181461bSKeith M Wesolowski 184*0181461bSKeith M Wesolowski /*ARGSUSED*/ 185*0181461bSKeith M Wesolowski static int 186*0181461bSKeith M Wesolowski bbootfs_open(char *fn, int flags) 187*0181461bSKeith M Wesolowski { 188*0181461bSKeith M Wesolowski uint_t i; 189*0181461bSKeith M Wesolowski bfile_t *fp; 190*0181461bSKeith M Wesolowski 191*0181461bSKeith M Wesolowski if (!init_done) { 192*0181461bSKeith M Wesolowski if (bbootfs_init() != 0) 193*0181461bSKeith M Wesolowski return (-1); 194*0181461bSKeith M Wesolowski 195*0181461bSKeith M Wesolowski init_done = 1; 196*0181461bSKeith M Wesolowski } 197*0181461bSKeith M Wesolowski 198*0181461bSKeith M Wesolowski canonicalise(fn, cpath); 199*0181461bSKeith M Wesolowski 200*0181461bSKeith M Wesolowski for (fp = head; fp != NULL; fp = fp->bf_next) { 201*0181461bSKeith M Wesolowski if (strcmp(fp->bf_name, cpath) == 0) 202*0181461bSKeith M Wesolowski break; 203*0181461bSKeith M Wesolowski } 204*0181461bSKeith M Wesolowski 205*0181461bSKeith M Wesolowski if (fp == NULL) 206*0181461bSKeith M Wesolowski return (-1); 207*0181461bSKeith M Wesolowski 208*0181461bSKeith M Wesolowski for (i = 0; i < MAX_FDS; i++) { 209*0181461bSKeith M Wesolowski if (fds[i].fd_file == NULL) { 210*0181461bSKeith M Wesolowski fds[i].fd_file = fp; 211*0181461bSKeith M Wesolowski fds[i].fd_pos = 0; 212*0181461bSKeith M Wesolowski return (i); 213*0181461bSKeith M Wesolowski } 214*0181461bSKeith M Wesolowski } 215*0181461bSKeith M Wesolowski 216*0181461bSKeith M Wesolowski return (-1); 217*0181461bSKeith M Wesolowski } 218*0181461bSKeith M Wesolowski 219*0181461bSKeith M Wesolowski static int 220*0181461bSKeith M Wesolowski bbootfs_close(int fd) 221*0181461bSKeith M Wesolowski { 222*0181461bSKeith M Wesolowski if (fds[fd].fd_file == NULL) 223*0181461bSKeith M Wesolowski return (-1); 224*0181461bSKeith M Wesolowski 225*0181461bSKeith M Wesolowski fds[fd].fd_file = NULL; 226*0181461bSKeith M Wesolowski fds[fd].fd_pos = 0; 227*0181461bSKeith M Wesolowski 228*0181461bSKeith M Wesolowski return (0); 229*0181461bSKeith M Wesolowski } 230*0181461bSKeith M Wesolowski 231*0181461bSKeith M Wesolowski static ssize_t 232*0181461bSKeith M Wesolowski bbootfs_read(int fd, caddr_t buf, size_t size) 233*0181461bSKeith M Wesolowski { 234*0181461bSKeith M Wesolowski ssize_t len; 235*0181461bSKeith M Wesolowski bf_fd_t *fdp = &fds[fd]; 236*0181461bSKeith M Wesolowski 237*0181461bSKeith M Wesolowski if (fdp->fd_file == NULL) 238*0181461bSKeith M Wesolowski return (-1); 239*0181461bSKeith M Wesolowski 240*0181461bSKeith M Wesolowski if (fdp->fd_pos >= fdp->fd_file->bf_size) 241*0181461bSKeith M Wesolowski return (-1); 242*0181461bSKeith M Wesolowski 243*0181461bSKeith M Wesolowski if (fdp->fd_pos + size > fdp->fd_file->bf_size) 244*0181461bSKeith M Wesolowski len = fdp->fd_file->bf_size - fdp->fd_pos; 245*0181461bSKeith M Wesolowski else 246*0181461bSKeith M Wesolowski len = size; 247*0181461bSKeith M Wesolowski 248*0181461bSKeith M Wesolowski bcopy(fdp->fd_file->bf_addr + fdp->fd_pos, buf, len); 249*0181461bSKeith M Wesolowski 250*0181461bSKeith M Wesolowski fdp->fd_pos += len; 251*0181461bSKeith M Wesolowski 252*0181461bSKeith M Wesolowski return (len); 253*0181461bSKeith M Wesolowski } 254*0181461bSKeith M Wesolowski 255*0181461bSKeith M Wesolowski static off_t 256*0181461bSKeith M Wesolowski bbootfs_lseek(int fd, off_t addr, int whence) 257*0181461bSKeith M Wesolowski { 258*0181461bSKeith M Wesolowski bf_fd_t *fdp = &fds[fd]; 259*0181461bSKeith M Wesolowski 260*0181461bSKeith M Wesolowski if (fdp->fd_file == NULL) 261*0181461bSKeith M Wesolowski return (-1); 262*0181461bSKeith M Wesolowski 263*0181461bSKeith M Wesolowski switch (whence) { 264*0181461bSKeith M Wesolowski case SEEK_CUR: 265*0181461bSKeith M Wesolowski fdp->fd_pos += addr; 266*0181461bSKeith M Wesolowski break; 267*0181461bSKeith M Wesolowski case SEEK_SET: 268*0181461bSKeith M Wesolowski fdp->fd_pos = addr; 269*0181461bSKeith M Wesolowski break; 270*0181461bSKeith M Wesolowski case SEEK_END: 271*0181461bSKeith M Wesolowski fdp->fd_pos = fdp->fd_file->bf_size; 272*0181461bSKeith M Wesolowski break; 273*0181461bSKeith M Wesolowski default: 274*0181461bSKeith M Wesolowski return (-1); 275*0181461bSKeith M Wesolowski } 276*0181461bSKeith M Wesolowski 277*0181461bSKeith M Wesolowski return (0); 278*0181461bSKeith M Wesolowski } 279*0181461bSKeith M Wesolowski 280*0181461bSKeith M Wesolowski static int 281*0181461bSKeith M Wesolowski bbootfs_fstat(int fd, struct bootstat *bsp) 282*0181461bSKeith M Wesolowski { 283*0181461bSKeith M Wesolowski bf_fd_t *fdp = &fds[fd]; 284*0181461bSKeith M Wesolowski 285*0181461bSKeith M Wesolowski if (fdp->fd_file == NULL) 286*0181461bSKeith M Wesolowski return (-1); 287*0181461bSKeith M Wesolowski 288*0181461bSKeith M Wesolowski bsp->st_dev = 1; 289*0181461bSKeith M Wesolowski bsp->st_ino = fdp->fd_file->bf_ino; 290*0181461bSKeith M Wesolowski bsp->st_mode = 0444; 291*0181461bSKeith M Wesolowski bsp->st_nlink = 1; 292*0181461bSKeith M Wesolowski bsp->st_uid = bsp->st_gid = 0; 293*0181461bSKeith M Wesolowski bsp->st_rdev = 0; 294*0181461bSKeith M Wesolowski bsp->st_size = fdp->fd_file->bf_size; 295*0181461bSKeith M Wesolowski bsp->st_blksize = 1; 296*0181461bSKeith M Wesolowski bsp->st_blocks = fdp->fd_file->bf_size; 297*0181461bSKeith M Wesolowski (void) strcpy(bsp->st_fstype, "bootfs"); 298*0181461bSKeith M Wesolowski 299*0181461bSKeith M Wesolowski return (0); 300*0181461bSKeith M Wesolowski } 301*0181461bSKeith M Wesolowski 302*0181461bSKeith M Wesolowski /* ARGSUSED */ 303*0181461bSKeith M Wesolowski static void 304*0181461bSKeith M Wesolowski bbootfs_closeall(int flag) 305*0181461bSKeith M Wesolowski { 306*0181461bSKeith M Wesolowski bfile_t *fp; 307*0181461bSKeith M Wesolowski 308*0181461bSKeith M Wesolowski while (head != NULL) { 309*0181461bSKeith M Wesolowski fp = head; 310*0181461bSKeith M Wesolowski head = head->bf_next; 311*0181461bSKeith M Wesolowski 312*0181461bSKeith M Wesolowski bkmem_free(fp, sizeof (bfile_t)); 313*0181461bSKeith M Wesolowski } 314*0181461bSKeith M Wesolowski 315*0181461bSKeith M Wesolowski init_done = 0; 316*0181461bSKeith M Wesolowski } 317*0181461bSKeith M Wesolowski 318*0181461bSKeith M Wesolowski struct boot_fs_ops bbootfs_ops = { 319*0181461bSKeith M Wesolowski "bootfs", 320*0181461bSKeith M Wesolowski bbootfs_mountroot, 321*0181461bSKeith M Wesolowski bbootfs_unmountroot, 322*0181461bSKeith M Wesolowski bbootfs_open, 323*0181461bSKeith M Wesolowski bbootfs_close, 324*0181461bSKeith M Wesolowski bbootfs_read, 325*0181461bSKeith M Wesolowski bbootfs_lseek, 326*0181461bSKeith M Wesolowski bbootfs_fstat, 327*0181461bSKeith M Wesolowski bbootfs_closeall, 328*0181461bSKeith M Wesolowski NULL 329*0181461bSKeith M Wesolowski }; 330