xref: /freebsd/usr.sbin/bsdinstall/partedit/scripted.c (revision 9f23cbd6cae82fd77edfad7173432fa8dccd0a95)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2013 Nathan Whitehorn
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #include <sys/param.h>
32 
33 #include <ctype.h>
34 #include <libgeom.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include "partedit.h"
40 
41 static struct gprovider *
42 provider_for_name(struct gmesh *mesh, const char *name)
43 {
44 	struct gclass *classp;
45 	struct gprovider *pp = NULL;
46 	struct ggeom *gp;
47 
48 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
49 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
50 			if (LIST_EMPTY(&gp->lg_provider))
51 				continue;
52 
53 			LIST_FOREACH(pp, &gp->lg_provider, lg_provider)
54 				if (strcmp(pp->lg_name, name) == 0)
55 					break;
56 
57 			if (pp != NULL) break;
58 		}
59 
60 		if (pp != NULL) break;
61 	}
62 
63 	return (pp);
64 }
65 
66 static int
67 part_config(char *disk, const char *scheme, char *config)
68 {
69 	char *partition, *ap, *size = NULL, *type = NULL, *mount = NULL;
70 	struct gclass *classp;
71 	struct gmesh mesh;
72 	struct ggeom *gpart = NULL;
73 	int error;
74 
75 	if (scheme == NULL)
76 		scheme = default_scheme();
77 
78 	error = geom_gettree(&mesh);
79 	if (error != 0)
80 		return (-1);
81 	if (provider_for_name(&mesh, disk) == NULL) {
82 		fprintf(stderr, "GEOM provider %s not found\n", disk);
83 		geom_deletetree(&mesh);
84 		return (-1);
85 	}
86 
87 	/* Remove any existing partitioning and create new scheme */
88 	LIST_FOREACH(classp, &mesh.lg_class, lg_class)
89 		if (strcmp(classp->lg_name, "PART") == 0)
90 			break;
91 	if (classp != NULL) {
92 		LIST_FOREACH(gpart, &classp->lg_geom, lg_geom)
93 		if (strcmp(gpart->lg_name, disk) == 0)
94 			break;
95 	}
96 	if (gpart != NULL)
97 		gpart_destroy(gpart);
98 	gpart_partition(disk, scheme);
99 
100 	if (strcmp(scheme, "MBR") == 0) {
101 		struct gmesh submesh;
102 
103 		if (geom_gettree(&submesh) == 0) {
104 			gpart_create(provider_for_name(&submesh, disk),
105 			    "freebsd", NULL, NULL, &disk, 0);
106 			geom_deletetree(&submesh);
107 		}
108 	} else {
109 		disk = strdup(disk);
110 	}
111 
112 	geom_deletetree(&mesh);
113 	error = geom_gettree(&mesh);
114 	if (error != 0) {
115 		free(disk);
116 		return (-1);
117 	}
118 
119 	/* Create partitions */
120 	if (config == NULL) {
121 		wizard_makeparts(&mesh, disk, "ufs", 0);
122 		goto finished;
123 	}
124 
125 	while ((partition = strsep(&config, ",")) != NULL) {
126 		while ((ap = strsep(&partition, " \t\n")) != NULL) {
127 			if (*ap == '\0')
128 				continue;
129 			if (size == NULL)
130 				size = ap;
131 			else if (type == NULL)
132 				type = ap;
133 			else if (mount == NULL)
134 				mount = ap;
135 		}
136 		if (size == NULL)
137 			continue;
138 		if (strcmp(size, "auto") == 0)
139 			size = NULL;
140 		gpart_create(provider_for_name(&mesh, disk), type, size, mount,
141 		    NULL, 0);
142 		geom_deletetree(&mesh);
143 		error = geom_gettree(&mesh);
144 		if (error != 0) {
145 			free(disk);
146 			return (-1);
147 		}
148 		size = type = mount = NULL;
149 	}
150 
151 finished:
152 	geom_deletetree(&mesh);
153 	free(disk);
154 
155 	return (0);
156 }
157 
158 static int
159 parse_disk_config(char *input)
160 {
161 	char *ap;
162 	char *disk = NULL, *scheme = NULL, *partconfig = NULL;
163 
164 	while (input != NULL && *input != 0) {
165 		if (isspace(*input)) {
166 			input++;
167 			continue;
168 		}
169 
170 		switch(*input) {
171 		case '{':
172 			input++;
173 			partconfig = strchr(input, '}');
174 			if (partconfig == NULL) {
175 				fprintf(stderr, "Malformed partition setup "
176 				    "string: %s\n", input);
177 				return (1);
178 			}
179 			*partconfig = '\0';
180 			ap = partconfig+1;
181 			partconfig = input;
182 			input = ap;
183 			break;
184 		default:
185 			if (disk == NULL)
186 				disk = strsep(&input, " \t\n");
187 			else if (scheme == NULL)
188 				scheme = strsep(&input, " \t\n");
189 			else {
190 				fprintf(stderr, "Unknown directive: %s\n",
191 				    strsep(&input, " \t\n"));
192 				return (1);
193 			}
194 		}
195 	} while (input != NULL && *input != 0);
196 
197 	if (disk == NULL || strcmp(disk, "DEFAULT") == 0) {
198 		struct gmesh mesh;
199 
200 		if (geom_gettree(&mesh) == 0) {
201 			disk = boot_disk_select(&mesh);
202 			geom_deletetree(&mesh);
203 		}
204 	}
205 
206 	return (part_config(disk, scheme, partconfig));
207 }
208 
209 int
210 scripted_editor(int argc, const char **argv)
211 {
212 	FILE *fp;
213 	char *input, *token;
214 	size_t len;
215 	int i, error = 0;
216 
217 	fp = open_memstream(&input, &len);
218 	fputs(argv[1], fp);
219 	for (i = 2; i < argc; i++) {
220 		fprintf(fp, " %s", argv[i]);
221 	}
222 	fclose(fp);
223 
224 	while ((token = strsep(&input, ";")) != NULL) {
225 		error = parse_disk_config(token);
226 		if (error != 0) {
227 			free(input);
228 			return (error);
229 		}
230 	}
231 	free(input);
232 
233 	return (0);
234 }
235 
236