/*-1* Copyright (c) 1998 Michael Smith <[email protected]>2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#include <string.h>27#include <stand.h>28#include <bootstrap.h>2930/*31* Concatenate the (argc) elements of (argv) into a single string, and return32* a copy of same.33*/34char *35unargv(int argc, char *argv[])36{37size_t hlong;38int i;39char *cp;4041for (i = 0, hlong = 0; i < argc; i++)42hlong += strlen(argv[i]) + 2;4344if(hlong == 0)45return(NULL);4647cp = malloc(hlong);48cp[0] = 0;49for (i = 0; i < argc; i++) {50strcat(cp, argv[i]);51if (i < (argc - 1))52strcat(cp, " ");53}5455return(cp);56}5758/*59* Get the length of a string in kernel space60*/61size_t62strlenout(vm_offset_t src)63{64char c;65size_t len;6667for (len = 0; ; len++) {68archsw.arch_copyout(src++, &c, 1);69if (c == 0)70break;71}72return(len);73}7475/*76* Make a duplicate copy of a string in kernel space77*/78char *79strdupout(vm_offset_t str)80{81char *result, *cp;8283result = malloc(strlenout(str) + 1);84for (cp = result; ;cp++) {85archsw.arch_copyout(str++, cp, 1);86if (*cp == 0)87break;88}89return(result);90}9192/* Zero a region in kernel space. */93void94kern_bzero(vm_offset_t dest, size_t len)95{96char buf[256];97size_t chunk, resid;9899bzero(buf, sizeof(buf));100resid = len;101while (resid > 0) {102chunk = min(sizeof(buf), resid);103archsw.arch_copyin(buf, dest, chunk);104resid -= chunk;105dest += chunk;106}107}108109/*110* Read the specified part of a file to kernel space. Unlike regular111* pread, the file pointer is advanced to the end of the read data,112* and it just returns 0 if successful.113*/114int115kern_pread(readin_handle_t fd, vm_offset_t dest, size_t len, off_t off)116{117118if (VECTX_LSEEK(fd, off, SEEK_SET) == -1) {119#ifdef DEBUG120printf("\nlseek failed\n");121#endif122return (-1);123}124if ((size_t)archsw.arch_readin(fd, dest, len) != len) {125#ifdef DEBUG126printf("\nreadin failed\n");127#endif128return (-1);129}130return (0);131}132133/*134* Read the specified part of a file to a malloced buffer. The file135* pointer is advanced to the end of the read data.136*/137/* coverity[ -tainted_data_return ] */138void *139alloc_pread(readin_handle_t fd, off_t off, size_t len)140{141void *buf;142143buf = malloc(len);144if (buf == NULL) {145#ifdef DEBUG146printf("\nmalloc(%d) failed\n", (int)len);147#endif148errno = ENOMEM;149return (NULL);150}151if (VECTX_LSEEK(fd, off, SEEK_SET) == -1) {152#ifdef DEBUG153printf("\nlseek failed\n");154#endif155free(buf);156return (NULL);157}158if ((size_t)VECTX_READ(fd, buf, len) != len) {159#ifdef DEBUG160printf("\nread failed\n");161#endif162free(buf);163return (NULL);164}165return (buf);166}167168/*169* mount new rootfs and unmount old, set "currdev" environment variable.170*/171int mount_currdev(struct env_var *ev, int flags, const void *value)172{173int rv;174175/* mount new rootfs */176rv = mount(value, "/", 0, NULL);177if (rv == 0) {178/*179* Note we unmount any previously mounted fs only after180* successfully mounting the new because we do not want to181* end up with unmounted rootfs.182*/183if (ev->ev_value != NULL)184unmount(ev->ev_value, 0);185env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);186}187return (rv);188}189190/*191* Set currdev to suit the value being supplied in (value)192*/193int194gen_setcurrdev(struct env_var *ev, int flags, const void *value)195{196struct devdesc *ncurr;197int rv;198199if ((rv = devparse(&ncurr, value, NULL)) != 0)200return (rv);201free(ncurr);202203return (mount_currdev(ev, flags, value));204}205206/*207* Wrapper to set currdev and loaddev at the same time.208*/209void210set_currdev(const char *devname)211{212213env_setenv("currdev", EV_VOLATILE, devname, gen_setcurrdev,214env_nounset);215/*216* Don't execute hook here; the loaddev hook makes it immutable217* once we've determined what the proper currdev is.218*/219env_setenv("loaddev", EV_VOLATILE | EV_NOHOOK, devname, env_noset,220env_nounset);221}222223#ifndef LOADER_NET_SUPPORT224/*225* This api is normally provided by dev_net.c226* This stub keeps libsa happy when LOADER_NET_SUPPORT227* is not enabled.228*/229bool230is_tftp(void)231{232return false;233}234#endif235236237