1 /*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, 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 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 #include <string.h> 29 #include <stand.h> 30 #include <bootstrap.h> 31 32 /* 33 * Concatenate the (argc) elements of (argv) into a single string, and return 34 * a copy of same. 35 */ 36 char * 37 unargv(int argc, char *argv[]) 38 { 39 size_t hlong; 40 int i; 41 char *cp; 42 43 for (i = 0, hlong = 0; i < argc; i++) 44 hlong += strlen(argv[i]) + 2; 45 46 if(hlong == 0) 47 return(NULL); 48 49 cp = malloc(hlong); 50 cp[0] = 0; 51 for (i = 0; i < argc; i++) { 52 strcat(cp, argv[i]); 53 if (i < (argc - 1)) 54 strcat(cp, " "); 55 } 56 57 return(cp); 58 } 59 60 /* 61 * Get the length of a string in kernel space 62 */ 63 size_t 64 strlenout(vm_offset_t src) 65 { 66 char c; 67 size_t len; 68 69 for (len = 0; ; len++) { 70 archsw.arch_copyout(src++, &c, 1); 71 if (c == 0) 72 break; 73 } 74 return(len); 75 } 76 77 /* 78 * Make a duplicate copy of a string in kernel space 79 */ 80 char * 81 strdupout(vm_offset_t str) 82 { 83 char *result, *cp; 84 85 result = malloc(strlenout(str) + 1); 86 for (cp = result; ;cp++) { 87 archsw.arch_copyout(str++, cp, 1); 88 if (*cp == 0) 89 break; 90 } 91 return(result); 92 } 93 94 /* Zero a region in kernel space. */ 95 void 96 kern_bzero(vm_offset_t dest, size_t len) 97 { 98 char buf[256]; 99 size_t chunk, resid; 100 101 bzero(buf, sizeof(buf)); 102 resid = len; 103 while (resid > 0) { 104 chunk = min(sizeof(buf), resid); 105 archsw.arch_copyin(buf, dest, chunk); 106 resid -= chunk; 107 dest += chunk; 108 } 109 } 110 111 /* 112 * Read the specified part of a file to kernel space. Unlike regular 113 * pread, the file pointer is advanced to the end of the read data, 114 * and it just returns 0 if successful. 115 */ 116 int 117 kern_pread(readin_handle_t fd, vm_offset_t dest, size_t len, off_t off) 118 { 119 120 if (VECTX_LSEEK(fd, off, SEEK_SET) == -1) { 121 #ifdef DEBUG 122 printf("\nlseek failed\n"); 123 #endif 124 return (-1); 125 } 126 if ((size_t)archsw.arch_readin(fd, dest, len) != len) { 127 #ifdef DEBUG 128 printf("\nreadin failed\n"); 129 #endif 130 return (-1); 131 } 132 return (0); 133 } 134 135 /* 136 * Read the specified part of a file to a malloced buffer. The file 137 * pointer is advanced to the end of the read data. 138 */ 139 /* coverity[ -tainted_data_return ] */ 140 void * 141 alloc_pread(readin_handle_t fd, off_t off, size_t len) 142 { 143 void *buf; 144 145 buf = malloc(len); 146 if (buf == NULL) { 147 #ifdef DEBUG 148 printf("\nmalloc(%d) failed\n", (int)len); 149 #endif 150 errno = ENOMEM; 151 return (NULL); 152 } 153 if (VECTX_LSEEK(fd, off, SEEK_SET) == -1) { 154 #ifdef DEBUG 155 printf("\nlseek failed\n"); 156 #endif 157 free(buf); 158 return (NULL); 159 } 160 if ((size_t)VECTX_READ(fd, buf, len) != len) { 161 #ifdef DEBUG 162 printf("\nread failed\n"); 163 #endif 164 free(buf); 165 return (NULL); 166 } 167 return (buf); 168 } 169 170 /* 171 * mount new rootfs and unmount old, set "currdev" environment variable. 172 */ 173 int mount_currdev(struct env_var *ev, int flags, const void *value) 174 { 175 int rv; 176 177 /* mount new rootfs */ 178 rv = mount(value, "/", 0, NULL); 179 if (rv == 0) { 180 /* 181 * Note we unmount any previously mounted fs only after 182 * successfully mounting the new because we do not want to 183 * end up with unmounted rootfs. 184 */ 185 if (ev->ev_value != NULL) 186 unmount(ev->ev_value, 0); 187 env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 188 } 189 return (rv); 190 } 191 192 /* 193 * Set currdev to suit the value being supplied in (value) 194 */ 195 int 196 gen_setcurrdev(struct env_var *ev, int flags, const void *value) 197 { 198 struct devdesc *ncurr; 199 int rv; 200 201 if ((rv = devparse(&ncurr, value, NULL)) != 0) 202 return (rv); 203 free(ncurr); 204 205 return (mount_currdev(ev, flags, value)); 206 } 207 208 /* 209 * Wrapper to set currdev and loaddev at the same time. 210 */ 211 void 212 set_currdev(const char *devname) 213 { 214 215 env_setenv("currdev", EV_VOLATILE, devname, gen_setcurrdev, 216 env_nounset); 217 /* 218 * Don't execute hook here; the loaddev hook makes it immutable 219 * once we've determined what the proper currdev is. 220 */ 221 env_setenv("loaddev", EV_VOLATILE | EV_NOHOOK, devname, env_noset, 222 env_nounset); 223 } 224