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