xref: /freebsd/stand/common/install.c (revision 7c43148a974877188a930e4078a164f83da8e652)
1ca987d46SWarner Losh /*-
2ca987d46SWarner Losh  * Copyright (c) 2008-2014, Juniper Networks, Inc.
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 ``AS IS'' AND ANY EXPRESS OR
15ca987d46SWarner Losh  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16ca987d46SWarner Losh  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17ca987d46SWarner Losh  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18ca987d46SWarner Losh  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19ca987d46SWarner Losh  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20ca987d46SWarner Losh  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21ca987d46SWarner Losh  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22ca987d46SWarner Losh  * 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/param.h>
28ca987d46SWarner Losh #include <sys/socket.h>
29ca987d46SWarner Losh #include <net/if.h>
30ca987d46SWarner Losh #include <netinet/in.h>
31ca987d46SWarner Losh #include <netinet/in_systm.h>
32ca987d46SWarner Losh 
33ca987d46SWarner Losh #include <stand.h>
34ca987d46SWarner Losh #include <net.h>
35ca987d46SWarner Losh #include <string.h>
36ca987d46SWarner Losh 
37ca987d46SWarner Losh #include "bootstrap.h"
38ca987d46SWarner Losh 
39ca987d46SWarner Losh extern struct in_addr servip;
40ca987d46SWarner Losh 
41ca987d46SWarner Losh extern int pkgfs_init(const char *, struct fs_ops *);
42ca987d46SWarner Losh extern void pkgfs_cleanup(void);
43ca987d46SWarner Losh 
44ca987d46SWarner Losh COMMAND_SET(install, "install", "install software package", command_install);
45ca987d46SWarner Losh 
46ca987d46SWarner Losh static char *inst_kernel;
47ca987d46SWarner Losh static char **inst_modules;
48ca987d46SWarner Losh static char *inst_rootfs;
49ca987d46SWarner Losh static char *inst_loader_rc;
50ca987d46SWarner Losh 
51ca987d46SWarner Losh static int
setpath(char ** what,char * val)52ca987d46SWarner Losh setpath(char **what, char *val)
53ca987d46SWarner Losh {
54ca987d46SWarner Losh 	char *path;
55ca987d46SWarner Losh 	size_t len;
56ca987d46SWarner Losh 	int rel;
57ca987d46SWarner Losh 
58ca987d46SWarner Losh 	len = strlen(val) + 1;
59ca987d46SWarner Losh 	rel = (val[0] != '/') ? 1 : 0;
60ca987d46SWarner Losh 	path = malloc(len + rel);
61ca987d46SWarner Losh 	if (path == NULL)
62ca987d46SWarner Losh 		return (ENOMEM);
63ca987d46SWarner Losh 	path[0] = '/';
64ca987d46SWarner Losh 	strcpy(path + rel, val);
65ca987d46SWarner Losh 
66ca987d46SWarner Losh 	*what = path;
67ca987d46SWarner Losh 	return (0);
68ca987d46SWarner Losh }
69ca987d46SWarner Losh 
70ca987d46SWarner Losh static int
setmultipath(char *** what,char * val)71ca987d46SWarner Losh setmultipath(char ***what, char *val)
72ca987d46SWarner Losh {
73ca987d46SWarner Losh 	char *s, *v;
74ca987d46SWarner Losh 	int count, error, idx;
75ca987d46SWarner Losh 
76ca987d46SWarner Losh 	count = 0;
77ca987d46SWarner Losh 	v = val;
78ca987d46SWarner Losh 	do {
79ca987d46SWarner Losh 		count++;
80ca987d46SWarner Losh 		s = strchr(v, ',');
81ca987d46SWarner Losh 		v = (s == NULL) ? NULL : s + 1;
82ca987d46SWarner Losh 	} while (v != NULL);
83ca987d46SWarner Losh 
84ca987d46SWarner Losh 	*what = calloc(count + 1, sizeof(char *));
85ca987d46SWarner Losh 	if (*what == NULL)
86ca987d46SWarner Losh 		return (ENOMEM);
87ca987d46SWarner Losh 
88ca987d46SWarner Losh 	for (idx = 0; idx < count; idx++) {
89ca987d46SWarner Losh 		s = strchr(val, ',');
90ca987d46SWarner Losh 		if (s != NULL)
91ca987d46SWarner Losh 			*s++ = '\0';
92ca987d46SWarner Losh 		error = setpath(*what + idx, val);
93ca987d46SWarner Losh 		if (error)
94ca987d46SWarner Losh 			return (error);
95ca987d46SWarner Losh 		val = s;
96ca987d46SWarner Losh 	}
97ca987d46SWarner Losh 
98ca987d46SWarner Losh 	return (0);
99ca987d46SWarner Losh }
100ca987d46SWarner Losh 
101ca987d46SWarner Losh static int
read_metatags(int fd)102ca987d46SWarner Losh read_metatags(int fd)
103ca987d46SWarner Losh {
104ca987d46SWarner Losh 	char buf[1024];
105ca987d46SWarner Losh 	char *p, *tag, *val;
106ca987d46SWarner Losh 	ssize_t fsize;
107ca987d46SWarner Losh 	int error;
108ca987d46SWarner Losh 
109ca987d46SWarner Losh 	fsize = read(fd, buf, sizeof(buf));
110ca987d46SWarner Losh 	if (fsize == -1)
111ca987d46SWarner Losh 		return (errno);
112ca987d46SWarner Losh 
113ca987d46SWarner Losh 	/*
114ca987d46SWarner Losh 	 * Assume that if we read a whole buffer worth of data, we
115ca987d46SWarner Losh 	 * haven't read the entire file. In other words, the buffer
116ca987d46SWarner Losh 	 * size must always be larger than the file size. That way
117ca987d46SWarner Losh 	 * we can append a '\0' and use standard string operations.
118ca987d46SWarner Losh 	 * Return an error if this is not possible.
119ca987d46SWarner Losh 	 */
120ca987d46SWarner Losh 	if (fsize == sizeof(buf))
121ca987d46SWarner Losh 		return (ENOMEM);
122ca987d46SWarner Losh 
123ca987d46SWarner Losh 	buf[fsize] = '\0';
124ca987d46SWarner Losh 	error = 0;
125ca987d46SWarner Losh 	tag = buf;
126ca987d46SWarner Losh 	while (!error && *tag != '\0') {
127ca987d46SWarner Losh 		val = strchr(tag, '=');
128ca987d46SWarner Losh 		if (val == NULL) {
129ca987d46SWarner Losh 			error = EINVAL;
130ca987d46SWarner Losh 			break;
131ca987d46SWarner Losh 		}
132ca987d46SWarner Losh 		*val++ = '\0';
133ca987d46SWarner Losh 		p = strchr(val, '\n');
134ca987d46SWarner Losh 		if (p == NULL) {
135ca987d46SWarner Losh 			error = EINVAL;
136ca987d46SWarner Losh 			break;
137ca987d46SWarner Losh 		}
138ca987d46SWarner Losh 		*p++ = '\0';
139ca987d46SWarner Losh 
140ca987d46SWarner Losh 		if (strcmp(tag, "KERNEL") == 0)
141ca987d46SWarner Losh 			error = setpath(&inst_kernel, val);
142ca987d46SWarner Losh 		else if (strcmp(tag, "MODULES") == 0)
143ca987d46SWarner Losh 			error = setmultipath(&inst_modules, val);
144ca987d46SWarner Losh 		else if (strcmp(tag, "ROOTFS") == 0)
145ca987d46SWarner Losh 			error = setpath(&inst_rootfs, val);
146ca987d46SWarner Losh 		else if (strcmp(tag, "LOADER_RC") == 0)
147ca987d46SWarner Losh 			error = setpath(&inst_loader_rc, val);
148ca987d46SWarner Losh 
149ca987d46SWarner Losh 		tag = p;
150ca987d46SWarner Losh 	}
151ca987d46SWarner Losh 
152ca987d46SWarner Losh 	return (error);
153ca987d46SWarner Losh }
154ca987d46SWarner Losh 
155ca987d46SWarner Losh static void
cleanup(void)156ca987d46SWarner Losh cleanup(void)
157ca987d46SWarner Losh {
158ca987d46SWarner Losh 	u_int i;
159ca987d46SWarner Losh 
160ca987d46SWarner Losh 	if (inst_kernel != NULL) {
161ca987d46SWarner Losh 		free(inst_kernel);
162ca987d46SWarner Losh 		inst_kernel = NULL;
163ca987d46SWarner Losh 	}
164ca987d46SWarner Losh 	if (inst_modules != NULL) {
165ca987d46SWarner Losh 		i = 0;
166ca987d46SWarner Losh 		while (inst_modules[i] != NULL)
167ca987d46SWarner Losh 			free(inst_modules[i++]);
168ca987d46SWarner Losh 		free(inst_modules);
169ca987d46SWarner Losh 		inst_modules = NULL;
170ca987d46SWarner Losh 	}
171ca987d46SWarner Losh 	if (inst_rootfs != NULL) {
172ca987d46SWarner Losh 		free(inst_rootfs);
173ca987d46SWarner Losh 		inst_rootfs = NULL;
174ca987d46SWarner Losh 	}
175ca987d46SWarner Losh 	if (inst_loader_rc != NULL) {
176ca987d46SWarner Losh 		free(inst_loader_rc);
177ca987d46SWarner Losh 		inst_loader_rc = NULL;
178ca987d46SWarner Losh 	}
179ca987d46SWarner Losh 	pkgfs_cleanup();
180ca987d46SWarner Losh }
181ca987d46SWarner Losh 
182ca987d46SWarner Losh /*
183ca987d46SWarner Losh  * usage: install URL
184eff7aa69SSimon J. Gerraty  * where: URL = tftp://[host]/<package>
185eff7aa69SSimon J. Gerraty  *	or	file://[devname[:fstype]]/<package>
186ca987d46SWarner Losh  */
187ca987d46SWarner Losh static int
install(char * pkgname)188ca987d46SWarner Losh install(char *pkgname)
189ca987d46SWarner Losh {
190ca987d46SWarner Losh 	static char buf[256];
191ca987d46SWarner Losh 	struct fs_ops *proto;
192ca987d46SWarner Losh 	struct preloaded_file *fp;
193eff7aa69SSimon J. Gerraty 	char *e, *s, *currdev;
194eff7aa69SSimon J. Gerraty 	char *devname;
195eff7aa69SSimon J. Gerraty 	size_t devnamelen;
196ca987d46SWarner Losh 	int error, fd, i, local;
197ca987d46SWarner Losh 
198ca987d46SWarner Losh 	s = strstr(pkgname, "://");
199ca987d46SWarner Losh 	if (s == NULL)
200ca987d46SWarner Losh 		goto invalid_url;
201ca987d46SWarner Losh 
202ca987d46SWarner Losh 	i = s - pkgname;
203eff7aa69SSimon J. Gerraty 	s += 3;
204eff7aa69SSimon J. Gerraty 	if (*s == '\0')
205eff7aa69SSimon J. Gerraty 		goto invalid_url;
206eff7aa69SSimon J. Gerraty 
207eff7aa69SSimon J. Gerraty 	devname = NULL;
208eff7aa69SSimon J. Gerraty 	devnamelen = 0;
209005ff484SSimon J. Gerraty 	proto = NULL;
210005ff484SSimon J. Gerraty 	local = 0;
211eff7aa69SSimon J. Gerraty 
212ca987d46SWarner Losh 	if (i == 4 && !strncasecmp(pkgname, "tftp", i)) {
213ca987d46SWarner Losh 		devname = "net0";
214eff7aa69SSimon J. Gerraty 		devnamelen = 4;
215ca987d46SWarner Losh 		proto = &tftp_fsops;
216ca987d46SWarner Losh 	} else if (i == 4 && !strncasecmp(pkgname, "file", i)) {
217ca987d46SWarner Losh 		currdev = getenv("currdev");
218eff7aa69SSimon J. Gerraty 		local = 1;
219eff7aa69SSimon J. Gerraty 
220eff7aa69SSimon J. Gerraty 		if (*s == '/') {	/* file:/// */
221eff7aa69SSimon J. Gerraty 			if (devname == NULL)
222eff7aa69SSimon J. Gerraty 				devname = currdev;
223eff7aa69SSimon J. Gerraty 			if (devname == NULL)
224eff7aa69SSimon J. Gerraty 				devname = "disk1";
225eff7aa69SSimon J. Gerraty 		} else {		/* file://devname[:fstype]/ */
226eff7aa69SSimon J. Gerraty 			devname = s;
227eff7aa69SSimon J. Gerraty 			e = strchr(devname, '/');
228eff7aa69SSimon J. Gerraty 			if (!e)
229eff7aa69SSimon J. Gerraty 				goto invalid_url;
230eff7aa69SSimon J. Gerraty 			devnamelen = e - devname;
231eff7aa69SSimon J. Gerraty 			s = e;		/* consume devname */
232eff7aa69SSimon J. Gerraty 		}
233eff7aa69SSimon J. Gerraty 		if ((e = strchr(devname, ':')) != NULL) {
234eff7aa69SSimon J. Gerraty 			/* could be :fstype */
235eff7aa69SSimon J. Gerraty 			devnamelen = e - devname;
236eff7aa69SSimon J. Gerraty 			switch (e[1]) {
237eff7aa69SSimon J. Gerraty 			case '\0':	/* just currdev */
238eff7aa69SSimon J. Gerraty 				break;
239eff7aa69SSimon J. Gerraty 			case 'd':
240eff7aa69SSimon J. Gerraty 				proto = &dosfs_fsops;
241eff7aa69SSimon J. Gerraty 				break;
24253f151f9SSimon J. Gerraty #ifdef HOSTPROG
243eff7aa69SSimon J. Gerraty 			case 'h':
244eff7aa69SSimon J. Gerraty 				{
24553f151f9SSimon J. Gerraty 					extern struct fs_ops host_fsops;
24653f151f9SSimon J. Gerraty 
24753f151f9SSimon J. Gerraty 					proto = &host_fsops;
248eff7aa69SSimon J. Gerraty 				}
249eff7aa69SSimon J. Gerraty 				break;
25053f151f9SSimon J. Gerraty #endif
251eff7aa69SSimon J. Gerraty 			case 'u':
252eff7aa69SSimon J. Gerraty 				proto = &ufs_fsops;
253eff7aa69SSimon J. Gerraty 				break;
254eff7aa69SSimon J. Gerraty 			}
255eff7aa69SSimon J. Gerraty 		}
256eff7aa69SSimon J. Gerraty 		if (proto == NULL && strncmp(devname, "disk", 4) == 0) {
257ca987d46SWarner Losh 			proto = &dosfs_fsops;
258ca987d46SWarner Losh 		}
259eff7aa69SSimon J. Gerraty 	}
260eff7aa69SSimon J. Gerraty 
261eff7aa69SSimon J. Gerraty 	if (devname == NULL)
262ca987d46SWarner Losh 		goto invalid_url;
263ca987d46SWarner Losh 
264eff7aa69SSimon J. Gerraty 	if (devnamelen == 0) {
265eff7aa69SSimon J. Gerraty 		/* default is currdev which ends with ':' */
266eff7aa69SSimon J. Gerraty 		devnamelen = strlen(devname);
267eff7aa69SSimon J. Gerraty 		if (devname[devnamelen - 1] == ':')
268eff7aa69SSimon J. Gerraty 			devnamelen--;
269eff7aa69SSimon J. Gerraty 	}
270ca987d46SWarner Losh 
271ca987d46SWarner Losh 	if (*s != '/' ) {
272ca987d46SWarner Losh 		if (local)
273ca987d46SWarner Losh 			goto invalid_url;
274ca987d46SWarner Losh 
275ca987d46SWarner Losh 		pkgname = strchr(s, '/');
276ca987d46SWarner Losh 		if (pkgname == NULL)
277ca987d46SWarner Losh 			goto invalid_url;
278ca987d46SWarner Losh 
279ca987d46SWarner Losh 		*pkgname = '\0';
280ca987d46SWarner Losh 		servip.s_addr = inet_addr(s);
281ca987d46SWarner Losh 		if (servip.s_addr == htonl(INADDR_NONE))
282ca987d46SWarner Losh 			goto invalid_url;
283ca987d46SWarner Losh 
284ca987d46SWarner Losh 		setenv("serverip", inet_ntoa(servip), 1);
285ca987d46SWarner Losh 
286ca987d46SWarner Losh 		*pkgname = '/';
287ca987d46SWarner Losh 	} else
288ca987d46SWarner Losh 		pkgname = s;
289ca987d46SWarner Losh 
290eff7aa69SSimon J. Gerraty 	i = snprintf(buf, sizeof(buf), "%.*s:%s",
291eff7aa69SSimon J. Gerraty 	    (int) devnamelen, devname, pkgname);
292eff7aa69SSimon J. Gerraty 	if (i >= (int) sizeof(buf)) {
293ca987d46SWarner Losh 		command_errmsg = "package name too long";
294ca987d46SWarner Losh 		return (CMD_ERROR);
295ca987d46SWarner Losh 	}
296ca987d46SWarner Losh 	setenv("install_package", buf, 1);
297ca987d46SWarner Losh 
298ca987d46SWarner Losh 	error = pkgfs_init(buf, proto);
299ca987d46SWarner Losh 	if (error) {
300ca987d46SWarner Losh 		command_errmsg = "cannot open package";
301ca987d46SWarner Losh 		goto fail;
302ca987d46SWarner Losh 	}
303ca987d46SWarner Losh 
304ca987d46SWarner Losh 	/*
305ca987d46SWarner Losh 	 * Point of no return: unload anything that may have been
306ca987d46SWarner Losh 	 * loaded and prune the environment from harmful variables.
307ca987d46SWarner Losh 	 */
308ca987d46SWarner Losh 	unload();
309ca987d46SWarner Losh 	unsetenv("vfs.root.mountfrom");
310ca987d46SWarner Losh 
311ca987d46SWarner Losh 	/*
312ca987d46SWarner Losh 	 * read the metatags file.
313ca987d46SWarner Losh 	 */
314ca987d46SWarner Losh 	fd = open("/metatags", O_RDONLY);
315ca987d46SWarner Losh 	if (fd != -1) {
316ca987d46SWarner Losh 		error = read_metatags(fd);
317ca987d46SWarner Losh 		close(fd);
318ca987d46SWarner Losh 		if (error) {
319ca987d46SWarner Losh 			command_errmsg = "cannot load metatags";
320ca987d46SWarner Losh 			goto fail;
321ca987d46SWarner Losh 		}
322ca987d46SWarner Losh 	}
323ca987d46SWarner Losh 
324ca987d46SWarner Losh 	s = (inst_kernel == NULL) ? "/kernel" : inst_kernel;
325ca987d46SWarner Losh 	error = mod_loadkld(s, 0, NULL);
326ca987d46SWarner Losh 	if (error) {
327ca987d46SWarner Losh 		command_errmsg = "cannot load kernel from package";
328ca987d46SWarner Losh 		goto fail;
329ca987d46SWarner Losh 	}
330ca987d46SWarner Losh 
331ca987d46SWarner Losh 	/* If there is a loader.rc in the package, execute it */
332ca987d46SWarner Losh 	s = (inst_loader_rc == NULL) ? "/loader.rc" : inst_loader_rc;
333ca987d46SWarner Losh 	fd = open(s, O_RDONLY);
334ca987d46SWarner Losh 	if (fd != -1) {
335ca987d46SWarner Losh 		close(fd);
336*fafe230dSStephen J. Kiernan 		error = interp_include(s);
337ca987d46SWarner Losh 		if (error == CMD_ERROR)
338ca987d46SWarner Losh 			goto fail;
339ca987d46SWarner Losh 	}
340ca987d46SWarner Losh 
341ca987d46SWarner Losh 	i = 0;
342ca987d46SWarner Losh 	while (inst_modules != NULL && inst_modules[i] != NULL) {
343ca987d46SWarner Losh 		error = mod_loadkld(inst_modules[i], 0, NULL);
344ca987d46SWarner Losh 		if (error) {
345ca987d46SWarner Losh 			command_errmsg = "cannot load module(s) from package";
346ca987d46SWarner Losh 			goto fail;
347ca987d46SWarner Losh 		}
348ca987d46SWarner Losh 		i++;
349ca987d46SWarner Losh 	}
350ca987d46SWarner Losh 
351ca987d46SWarner Losh 	s = (inst_rootfs == NULL) ? "/install.iso" : inst_rootfs;
352ca987d46SWarner Losh 	if (file_loadraw(s, "mfs_root", 1) == NULL) {
353ca987d46SWarner Losh 		error = errno;
354ca987d46SWarner Losh 		command_errmsg = "cannot load root file system";
355ca987d46SWarner Losh 		goto fail;
356ca987d46SWarner Losh 	}
357ca987d46SWarner Losh 
358ca987d46SWarner Losh 	cleanup();
359ca987d46SWarner Losh 
360ca987d46SWarner Losh 	fp = file_findfile(NULL, NULL);
361ca987d46SWarner Losh 	if (fp != NULL)
362ca987d46SWarner Losh 		file_formats[fp->f_loader]->l_exec(fp);
363ca987d46SWarner Losh 	error = CMD_ERROR;
364ca987d46SWarner Losh 	command_errmsg = "unable to start installation";
365ca987d46SWarner Losh 
366ca987d46SWarner Losh  fail:
367ca987d46SWarner Losh 	sprintf(buf, "%s (error %d)", command_errmsg, error);
368ca987d46SWarner Losh 	cleanup();
369ca987d46SWarner Losh 	unload();
370ca987d46SWarner Losh 	exclusive_file_system = NULL;
371ca987d46SWarner Losh 	command_errmsg = buf;	/* buf is static. */
372ca987d46SWarner Losh 	return (CMD_ERROR);
373ca987d46SWarner Losh 
374ca987d46SWarner Losh  invalid_url:
375ca987d46SWarner Losh 	command_errmsg = "invalid URL";
376ca987d46SWarner Losh 	return (CMD_ERROR);
377ca987d46SWarner Losh }
378ca987d46SWarner Losh 
379ca987d46SWarner Losh static int
command_install(int argc,char * argv[])380ca987d46SWarner Losh command_install(int argc, char *argv[])
381ca987d46SWarner Losh {
382ca987d46SWarner Losh 	int argidx;
383ca987d46SWarner Losh 
384ca987d46SWarner Losh 	unsetenv("install_format");
385ca987d46SWarner Losh 
386ca987d46SWarner Losh 	argidx = 1;
387ca987d46SWarner Losh 	while (1) {
388ca987d46SWarner Losh 		if (argc == argidx) {
389ca987d46SWarner Losh 			command_errmsg =
390ca987d46SWarner Losh 			    "usage: install [--format] <URL>";
391ca987d46SWarner Losh 			return (CMD_ERROR);
392ca987d46SWarner Losh 		}
393ca987d46SWarner Losh 		if (!strcmp(argv[argidx], "--format")) {
394ca987d46SWarner Losh 			setenv("install_format", "yes", 1);
395ca987d46SWarner Losh 			argidx++;
396ca987d46SWarner Losh 			continue;
397ca987d46SWarner Losh 		}
398ca987d46SWarner Losh 		break;
399ca987d46SWarner Losh 	}
400ca987d46SWarner Losh 
401ca987d46SWarner Losh 	return (install(argv[argidx]));
402ca987d46SWarner Losh }
403