1 |
|
|
/* $OpenBSD: editor.c,v 1.300 2015/12/10 17:26:59 mmcc Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 1997-2000 Todd C. Miller <Todd.Miller@courtesan.com> |
5 |
|
|
* |
6 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
7 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
8 |
|
|
* copyright notice and this permission notice appear in all copies. |
9 |
|
|
* |
10 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 |
|
|
*/ |
18 |
|
|
|
19 |
|
|
#include <sys/param.h> /* MAXBSIZE DEV_BSIZE */ |
20 |
|
|
#include <sys/types.h> |
21 |
|
|
#include <sys/signal.h> |
22 |
|
|
#include <sys/stat.h> |
23 |
|
|
#include <sys/ioctl.h> |
24 |
|
|
#include <sys/dkio.h> |
25 |
|
|
#include <sys/sysctl.h> |
26 |
|
|
#define DKTYPENAMES |
27 |
|
|
#include <sys/disklabel.h> |
28 |
|
|
|
29 |
|
|
#include <ufs/ffs/fs.h> |
30 |
|
|
|
31 |
|
|
#include <ctype.h> |
32 |
|
|
#include <err.h> |
33 |
|
|
#include <errno.h> |
34 |
|
|
#include <string.h> |
35 |
|
|
#include <libgen.h> |
36 |
|
|
#include <stdio.h> |
37 |
|
|
#include <stdlib.h> |
38 |
|
|
#include <unistd.h> |
39 |
|
|
#include <limits.h> |
40 |
|
|
|
41 |
|
|
#include "extern.h" |
42 |
|
|
#include "pathnames.h" |
43 |
|
|
|
44 |
|
|
#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) |
45 |
|
|
|
46 |
|
|
/* flags for getuint64() */ |
47 |
|
|
#define DO_CONVERSIONS 0x00000001 |
48 |
|
|
#define DO_ROUNDING 0x00000002 |
49 |
|
|
|
50 |
|
|
/* structure to describe a portion of a disk */ |
51 |
|
|
struct diskchunk { |
52 |
|
|
u_int64_t start; |
53 |
|
|
u_int64_t stop; |
54 |
|
|
}; |
55 |
|
|
|
56 |
|
|
/* used when sorting mountpoints in mpsave() */ |
57 |
|
|
struct mountinfo { |
58 |
|
|
char *mountpoint; |
59 |
|
|
int partno; |
60 |
|
|
}; |
61 |
|
|
|
62 |
|
|
/* used when allocating all space according to recommendations */ |
63 |
|
|
|
64 |
|
|
struct space_allocation { |
65 |
|
|
u_int64_t minsz; /* starts as blocks, xlated to sectors. */ |
66 |
|
|
u_int64_t maxsz; /* starts as blocks, xlated to sectors. */ |
67 |
|
|
int rate; /* % of extra space to use */ |
68 |
|
|
char *mp; |
69 |
|
|
}; |
70 |
|
|
|
71 |
|
|
/* entries for swap and var are changed by editor_allocspace() */ |
72 |
|
|
struct space_allocation alloc_big[] = { |
73 |
|
|
{ MEG(80), GIG(1), 5, "/" }, |
74 |
|
|
{ MEG(80), MEG(256), 10, "swap" }, |
75 |
|
|
{ MEG(120), GIG(4), 8, "/tmp" }, |
76 |
|
|
{ MEG(80), GIG(4), 13, "/var" }, |
77 |
|
|
{ MEG(900), GIG(2), 5, "/usr" }, |
78 |
|
|
{ MEG(512), GIG(1), 3, "/usr/X11R6" }, |
79 |
|
|
{ GIG(2), GIG(10), 10, "/usr/local" }, |
80 |
|
|
{ GIG(1), GIG(2), 2, "/usr/src" }, |
81 |
|
|
#ifdef STATICLINKING |
82 |
|
|
{ MEG(2600), GIG(3), 4, "/usr/obj" }, |
83 |
|
|
#else |
84 |
|
|
{ MEG(1300), GIG(2), 4, "/usr/obj" }, |
85 |
|
|
#endif |
86 |
|
|
{ GIG(1), GIG(300), 40, "/home" } |
87 |
|
|
/* Anything beyond this leave for the user to decide */ |
88 |
|
|
}; |
89 |
|
|
|
90 |
|
|
struct space_allocation alloc_medium[] = { |
91 |
|
|
{ MEG(800), GIG(2), 5, "/" }, |
92 |
|
|
{ MEG(80), MEG(256), 10, "swap" }, |
93 |
|
|
{ MEG(900), GIG(3), 78, "/usr" }, |
94 |
|
|
{ MEG(256), GIG(2), 7, "/home" } |
95 |
|
|
}; |
96 |
|
|
|
97 |
|
|
struct space_allocation alloc_small[] = { |
98 |
|
|
{ MEG(700), GIG(4), 95, "/" }, |
99 |
|
|
{ MEG(1), MEG(256), 5, "swap" } |
100 |
|
|
}; |
101 |
|
|
|
102 |
|
|
struct space_allocation alloc_stupid[] = { |
103 |
|
|
{ MEG(1), MEG(2048), 100, "/" } |
104 |
|
|
}; |
105 |
|
|
|
106 |
|
|
#ifndef nitems |
107 |
|
|
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) |
108 |
|
|
#endif |
109 |
|
|
|
110 |
|
|
struct alloc_table { |
111 |
|
|
struct space_allocation *table; |
112 |
|
|
int sz; |
113 |
|
|
}; |
114 |
|
|
|
115 |
|
|
struct alloc_table alloc_table_default[] = { |
116 |
|
|
{ alloc_big, nitems(alloc_big) }, |
117 |
|
|
{ alloc_medium, nitems(alloc_medium) }, |
118 |
|
|
{ alloc_small, nitems(alloc_small) }, |
119 |
|
|
{ alloc_stupid, nitems(alloc_stupid) } |
120 |
|
|
}; |
121 |
|
|
struct alloc_table *alloc_table = alloc_table_default; |
122 |
|
|
int alloc_table_nitems = 4; |
123 |
|
|
|
124 |
|
|
void edit_parms(struct disklabel *); |
125 |
|
|
void editor_resize(struct disklabel *, char *); |
126 |
|
|
void editor_add(struct disklabel *, char *); |
127 |
|
|
void editor_change(struct disklabel *, char *); |
128 |
|
|
u_int64_t editor_countfree(struct disklabel *); |
129 |
|
|
void editor_delete(struct disklabel *, char *); |
130 |
|
|
void editor_help(void); |
131 |
|
|
void editor_modify(struct disklabel *, char *); |
132 |
|
|
void editor_name(struct disklabel *, char *); |
133 |
|
|
char *getstring(const char *, const char *, const char *); |
134 |
|
|
u_int64_t getuint64(struct disklabel *, char *, char *, u_int64_t, u_int64_t, |
135 |
|
|
u_int64_t, int); |
136 |
|
|
int has_overlap(struct disklabel *); |
137 |
|
|
int partition_cmp(const void *, const void *); |
138 |
|
|
struct partition **sort_partitions(struct disklabel *); |
139 |
|
|
void getdisktype(struct disklabel *, char *, char *); |
140 |
|
|
void find_bounds(struct disklabel *); |
141 |
|
|
void set_bounds(struct disklabel *); |
142 |
|
|
void set_duid(struct disklabel *); |
143 |
|
|
struct diskchunk *free_chunks(struct disklabel *); |
144 |
|
|
int micmp(const void *, const void *); |
145 |
|
|
int mpequal(char **, char **); |
146 |
|
|
int get_bsize(struct disklabel *, int); |
147 |
|
|
int get_fsize(struct disklabel *, int); |
148 |
|
|
int get_fstype(struct disklabel *, int); |
149 |
|
|
int get_mp(struct disklabel *, int); |
150 |
|
|
int get_offset(struct disklabel *, int); |
151 |
|
|
int get_size(struct disklabel *, int); |
152 |
|
|
void get_geometry(int, struct disklabel **); |
153 |
|
|
void set_geometry(struct disklabel *, struct disklabel *, struct disklabel *, |
154 |
|
|
char *); |
155 |
|
|
void zero_partitions(struct disklabel *); |
156 |
|
|
u_int64_t max_partition_size(struct disklabel *, int); |
157 |
|
|
void display_edit(struct disklabel *, char, u_int64_t); |
158 |
|
|
void psize(u_int64_t sz, char unit, struct disklabel *lp); |
159 |
|
|
char *get_token(char **, size_t *); |
160 |
|
|
int apply_unit(double, u_char, u_int64_t *); |
161 |
|
|
int parse_sizespec(const char *, double *, char **); |
162 |
|
|
int parse_sizerange(char *, u_int64_t *, u_int64_t *); |
163 |
|
|
int parse_pct(char *, int *); |
164 |
|
|
|
165 |
|
|
static u_int64_t starting_sector; |
166 |
|
|
static u_int64_t ending_sector; |
167 |
|
|
static int expert; |
168 |
|
|
static int overlap; |
169 |
|
|
|
170 |
|
|
/* |
171 |
|
|
* Simple partition editor. |
172 |
|
|
*/ |
173 |
|
|
int |
174 |
|
|
editor(int f) |
175 |
|
|
{ |
176 |
|
|
struct disklabel origlabel, lastlabel, tmplabel, newlab = lab; |
177 |
|
|
struct disklabel *disk_geop = NULL; |
178 |
|
|
struct partition *pp; |
179 |
|
|
FILE *fp; |
180 |
|
|
char buf[BUFSIZ], *cmd, *arg; |
181 |
|
|
char **omountpoints = NULL; |
182 |
|
|
char **origmountpoints = NULL, **tmpmountpoints = NULL; |
183 |
|
|
int i, error = 0; |
184 |
|
|
|
185 |
|
|
/* Alloc and init mount point info */ |
186 |
|
|
if (!(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || |
187 |
|
|
!(origmountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || |
188 |
|
|
!(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *)))) |
189 |
|
|
errx(4, "out of memory"); |
190 |
|
|
|
191 |
|
|
/* Don't allow disk type of "unknown" */ |
192 |
|
|
getdisktype(&newlab, "You need to specify a type for this disk.", |
193 |
|
|
specname); |
194 |
|
|
|
195 |
|
|
/* Get the on-disk geometries if possible */ |
196 |
|
|
get_geometry(f, &disk_geop); |
197 |
|
|
|
198 |
|
|
/* How big is the OpenBSD portion of the disk? */ |
199 |
|
|
find_bounds(&newlab); |
200 |
|
|
|
201 |
|
|
/* Make sure there is no partition overlap. */ |
202 |
|
|
if (has_overlap(&newlab)) |
203 |
|
|
errx(1, "can't run when there is partition overlap."); |
204 |
|
|
|
205 |
|
|
/* If we don't have a 'c' partition, create one. */ |
206 |
|
|
pp = &newlab.d_partitions[RAW_PART]; |
207 |
|
|
if (newlab.d_npartitions < 3 || DL_GETPSIZE(pp) == 0) { |
208 |
|
|
puts("No 'c' partition found, adding one that spans the disk."); |
209 |
|
|
if (newlab.d_npartitions < 3) |
210 |
|
|
newlab.d_npartitions = 3; |
211 |
|
|
DL_SETPOFFSET(pp, 0); |
212 |
|
|
DL_SETPSIZE(pp, DL_GETDSIZE(&newlab)); |
213 |
|
|
pp->p_fstype = FS_UNUSED; |
214 |
|
|
pp->p_fragblock = pp->p_cpg = 0; |
215 |
|
|
} |
216 |
|
|
|
217 |
|
|
#ifdef SUN_CYLCHECK |
218 |
|
|
if ((newlab.d_flags & D_VENDOR) && !aflag) { |
219 |
|
|
puts("This platform requires that partition offsets/sizes " |
220 |
|
|
"be on cylinder boundaries.\n" |
221 |
|
|
"Partition offsets/sizes will be rounded to the " |
222 |
|
|
"nearest cylinder automatically."); |
223 |
|
|
} |
224 |
|
|
#endif |
225 |
|
|
|
226 |
|
|
/* Set d_bbsize and d_sbsize as necessary */ |
227 |
|
|
if (newlab.d_bbsize == 0) |
228 |
|
|
newlab.d_bbsize = BBSIZE; |
229 |
|
|
if (newlab.d_sbsize == 0) |
230 |
|
|
newlab.d_sbsize = SBSIZE; |
231 |
|
|
|
232 |
|
|
/* Save the (U|u)ndo labels and mountpoints. */ |
233 |
|
|
mpcopy(origmountpoints, mountpoints); |
234 |
|
|
origlabel = newlab; |
235 |
|
|
lastlabel = newlab; |
236 |
|
|
|
237 |
|
|
puts("Label editor (enter '?' for help at any prompt)"); |
238 |
|
|
for (;;) { |
239 |
|
|
fputs("> ", stdout); |
240 |
|
|
if (fgets(buf, sizeof(buf), stdin) == NULL) { |
241 |
|
|
putchar('\n'); |
242 |
|
|
buf[0] = 'q'; |
243 |
|
|
buf[1] = '\0'; |
244 |
|
|
} |
245 |
|
|
if ((cmd = strtok(buf, " \t\r\n")) == NULL) |
246 |
|
|
continue; |
247 |
|
|
arg = strtok(NULL, " \t\r\n"); |
248 |
|
|
|
249 |
|
|
if ((*cmd != 'u') && (*cmd != 'U')) { |
250 |
|
|
/* |
251 |
|
|
* Save undo info in case the command tries to make |
252 |
|
|
* changes but decides not to. |
253 |
|
|
*/ |
254 |
|
|
tmplabel = lastlabel; |
255 |
|
|
lastlabel = newlab; |
256 |
|
|
mpcopy(tmpmountpoints, omountpoints); |
257 |
|
|
mpcopy(omountpoints, mountpoints); |
258 |
|
|
} |
259 |
|
|
|
260 |
|
|
switch (*cmd) { |
261 |
|
|
case '?': |
262 |
|
|
case 'h': |
263 |
|
|
editor_help(); |
264 |
|
|
break; |
265 |
|
|
|
266 |
|
|
case 'A': |
267 |
|
|
if (ioctl(f, DIOCGPDINFO, &newlab) == 0) { |
268 |
|
|
++aflag; |
269 |
|
|
editor_allocspace(&newlab); |
270 |
|
|
--aflag; |
271 |
|
|
} else |
272 |
|
|
newlab = lastlabel; |
273 |
|
|
break; |
274 |
|
|
case 'a': |
275 |
|
|
editor_add(&newlab, arg); |
276 |
|
|
break; |
277 |
|
|
|
278 |
|
|
case 'b': |
279 |
|
|
set_bounds(&newlab); |
280 |
|
|
break; |
281 |
|
|
|
282 |
|
|
case 'c': |
283 |
|
|
editor_change(&newlab, arg); |
284 |
|
|
break; |
285 |
|
|
|
286 |
|
|
case 'D': |
287 |
|
|
if (ioctl(f, DIOCGPDINFO, &newlab) == 0) { |
288 |
|
|
dflag = 1; |
289 |
|
|
for (i=0; i<MAXPARTITIONS; i++) { |
290 |
|
|
free(mountpoints[i]); |
291 |
|
|
mountpoints[i] = NULL; |
292 |
|
|
} |
293 |
|
|
} else |
294 |
|
|
warn("unable to get default partition table"); |
295 |
|
|
break; |
296 |
|
|
|
297 |
|
|
case 'd': |
298 |
|
|
editor_delete(&newlab, arg); |
299 |
|
|
break; |
300 |
|
|
|
301 |
|
|
case 'e': |
302 |
|
|
edit_parms(&newlab); |
303 |
|
|
break; |
304 |
|
|
|
305 |
|
|
case 'g': |
306 |
|
|
set_geometry(&newlab, disk_geop, &lab, arg); |
307 |
|
|
break; |
308 |
|
|
|
309 |
|
|
case 'i': |
310 |
|
|
set_duid(&newlab); |
311 |
|
|
break; |
312 |
|
|
|
313 |
|
|
case 'm': |
314 |
|
|
editor_modify(&newlab, arg); |
315 |
|
|
break; |
316 |
|
|
|
317 |
|
|
case 'n': |
318 |
|
|
if (!fstabfile) { |
319 |
|
|
fputs("This option is not valid when run " |
320 |
|
|
"without the -f flag.\n", stderr); |
321 |
|
|
break; |
322 |
|
|
} |
323 |
|
|
editor_name(&newlab, arg); |
324 |
|
|
break; |
325 |
|
|
|
326 |
|
|
case 'p': |
327 |
|
|
display_edit(&newlab, arg ? *arg : 0, |
328 |
|
|
editor_countfree(&newlab)); |
329 |
|
|
break; |
330 |
|
|
|
331 |
|
|
case 'l': |
332 |
|
|
display(stdout, &newlab, arg ? *arg : 0, 0); |
333 |
|
|
break; |
334 |
|
|
|
335 |
|
|
case 'M': { |
336 |
|
|
sig_t opipe = signal(SIGPIPE, SIG_IGN); |
337 |
|
|
char *pager, *comm = NULL; |
338 |
|
|
extern const u_char manpage[]; |
339 |
|
|
extern const int manpage_sz; |
340 |
|
|
|
341 |
|
|
if ((pager = getenv("PAGER")) == NULL || *pager == '\0') |
342 |
|
|
pager = _PATH_LESS; |
343 |
|
|
|
344 |
|
|
if (asprintf(&comm, "gunzip -qc|%s", pager) != -1 && |
345 |
|
|
(fp = popen(comm, "w")) != NULL) { |
346 |
|
|
(void) fwrite(manpage, manpage_sz, 1, fp); |
347 |
|
|
pclose(fp); |
348 |
|
|
} else |
349 |
|
|
warn("unable to execute %s", pager); |
350 |
|
|
|
351 |
|
|
free(comm); |
352 |
|
|
(void)signal(SIGPIPE, opipe); |
353 |
|
|
break; |
354 |
|
|
} |
355 |
|
|
|
356 |
|
|
case 'q': |
357 |
|
|
if (donothing) { |
358 |
|
|
puts("In no change mode, not writing label."); |
359 |
|
|
goto done; |
360 |
|
|
} |
361 |
|
|
|
362 |
|
|
/* |
363 |
|
|
* If we haven't changed the original label, and it |
364 |
|
|
* wasn't a default label or an auto-allocated label, |
365 |
|
|
* there is no need to do anything before exiting. Note |
366 |
|
|
* that 'w' will reset dflag and aflag to allow 'q' to |
367 |
|
|
* exit without further questions. |
368 |
|
|
*/ |
369 |
|
|
if (!dflag && !aflag && |
370 |
|
|
memcmp(&lab, &newlab, sizeof(newlab)) == 0) { |
371 |
|
|
puts("No label changes."); |
372 |
|
|
/* Save mountpoint info. */ |
373 |
|
|
mpsave(&newlab); |
374 |
|
|
goto done; |
375 |
|
|
} |
376 |
|
|
do { |
377 |
|
|
arg = getstring("Write new label?", |
378 |
|
|
"Write the modified label to disk?", |
379 |
|
|
"y"); |
380 |
|
|
} while (arg && tolower((unsigned char)*arg) != 'y' && |
381 |
|
|
tolower((unsigned char)*arg) != 'n'); |
382 |
|
|
if (arg && tolower((unsigned char)*arg) == 'y') { |
383 |
|
|
if (writelabel(f, &newlab) == 0) { |
384 |
|
|
newlab = lab; /* lab now has UID info */ |
385 |
|
|
goto done; |
386 |
|
|
} |
387 |
|
|
warnx("unable to write label"); |
388 |
|
|
} |
389 |
|
|
error = 1; |
390 |
|
|
goto done; |
391 |
|
|
/* NOTREACHED */ |
392 |
|
|
break; |
393 |
|
|
|
394 |
|
|
case 'R': |
395 |
|
|
if (aflag && !overlap) |
396 |
|
|
editor_resize(&newlab, arg); |
397 |
|
|
else |
398 |
|
|
fputs("Resize only implemented for auto " |
399 |
|
|
"allocated labels\n", stderr); |
400 |
|
|
break; |
401 |
|
|
|
402 |
|
|
case 'r': { |
403 |
|
|
struct diskchunk *chunks; |
404 |
|
|
int i; |
405 |
|
|
/* Display free space. */ |
406 |
|
|
chunks = free_chunks(&newlab); |
407 |
|
|
for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; |
408 |
|
|
i++) |
409 |
|
|
fprintf(stderr, "Free sectors: %16llu - %16llu " |
410 |
|
|
"(%16llu)\n", |
411 |
|
|
chunks[i].start, chunks[i].stop - 1, |
412 |
|
|
chunks[i].stop - chunks[i].start); |
413 |
|
|
fprintf(stderr, "Total free sectors: %llu.\n", |
414 |
|
|
editor_countfree(&newlab)); |
415 |
|
|
break; |
416 |
|
|
} |
417 |
|
|
|
418 |
|
|
case 's': |
419 |
|
|
if (arg == NULL) { |
420 |
|
|
arg = getstring("Filename", |
421 |
|
|
"Name of the file to save label into.", |
422 |
|
|
NULL); |
423 |
|
|
if (arg == NULL || *arg == '\0') |
424 |
|
|
break; |
425 |
|
|
} |
426 |
|
|
if ((fp = fopen(arg, "w")) == NULL) { |
427 |
|
|
warn("cannot open %s", arg); |
428 |
|
|
} else { |
429 |
|
|
display(fp, &newlab, 0, 1); |
430 |
|
|
(void)fclose(fp); |
431 |
|
|
} |
432 |
|
|
break; |
433 |
|
|
|
434 |
|
|
case 'U': |
435 |
|
|
/* |
436 |
|
|
* If we allow 'U' repeatedly, information would be |
437 |
|
|
* lost. This way multiple 'U's followed by 'u' will |
438 |
|
|
* undo the 'U's. |
439 |
|
|
*/ |
440 |
|
|
if (memcmp(&newlab, &origlabel, sizeof(newlab)) || |
441 |
|
|
!mpequal(mountpoints, origmountpoints)) { |
442 |
|
|
tmplabel = newlab; |
443 |
|
|
newlab = origlabel; |
444 |
|
|
lastlabel = tmplabel; |
445 |
|
|
mpcopy(tmpmountpoints, mountpoints); |
446 |
|
|
mpcopy(mountpoints, origmountpoints); |
447 |
|
|
mpcopy(omountpoints, tmpmountpoints); |
448 |
|
|
} |
449 |
|
|
puts("Original label and mount points restored."); |
450 |
|
|
break; |
451 |
|
|
|
452 |
|
|
case 'u': |
453 |
|
|
tmplabel = newlab; |
454 |
|
|
newlab = lastlabel; |
455 |
|
|
lastlabel = tmplabel; |
456 |
|
|
mpcopy(tmpmountpoints, mountpoints); |
457 |
|
|
mpcopy(mountpoints, omountpoints); |
458 |
|
|
mpcopy(omountpoints, tmpmountpoints); |
459 |
|
|
puts("Last change undone."); |
460 |
|
|
break; |
461 |
|
|
|
462 |
|
|
case 'w': |
463 |
|
|
if (donothing) { |
464 |
|
|
puts("In no change mode, not writing label."); |
465 |
|
|
break; |
466 |
|
|
} |
467 |
|
|
|
468 |
|
|
/* Write label to disk. */ |
469 |
|
|
if (writelabel(f, &newlab) != 0) |
470 |
|
|
warnx("unable to write label"); |
471 |
|
|
else { |
472 |
|
|
dflag = aflag = 0; |
473 |
|
|
newlab = lab; /* lab now has UID info */ |
474 |
|
|
} |
475 |
|
|
break; |
476 |
|
|
|
477 |
|
|
case 'X': |
478 |
|
|
expert = !expert; |
479 |
|
|
printf("%s expert mode\n", expert ? "Entering" : |
480 |
|
|
"Exiting"); |
481 |
|
|
break; |
482 |
|
|
|
483 |
|
|
case 'x': |
484 |
|
|
goto done; |
485 |
|
|
break; |
486 |
|
|
|
487 |
|
|
case 'z': |
488 |
|
|
zero_partitions(&newlab); |
489 |
|
|
break; |
490 |
|
|
|
491 |
|
|
case '\n': |
492 |
|
|
break; |
493 |
|
|
|
494 |
|
|
default: |
495 |
|
|
printf("Unknown option: %c ('?' for help)\n", *cmd); |
496 |
|
|
break; |
497 |
|
|
} |
498 |
|
|
|
499 |
|
|
/* |
500 |
|
|
* If no changes were made to label or mountpoints, then |
501 |
|
|
* restore undo info. |
502 |
|
|
*/ |
503 |
|
|
if (memcmp(&newlab, &lastlabel, sizeof(newlab)) == 0 && |
504 |
|
|
(mpequal(mountpoints, omountpoints))) { |
505 |
|
|
lastlabel = tmplabel; |
506 |
|
|
mpcopy(omountpoints, tmpmountpoints); |
507 |
|
|
} |
508 |
|
|
} |
509 |
|
|
done: |
510 |
|
|
mpfree(omountpoints); |
511 |
|
|
mpfree(origmountpoints); |
512 |
|
|
mpfree(tmpmountpoints); |
513 |
|
|
free(disk_geop); |
514 |
|
|
return(error); |
515 |
|
|
} |
516 |
|
|
|
517 |
|
|
/* |
518 |
|
|
* Allocate all disk space according to standard recommendations for a |
519 |
|
|
* root disk. |
520 |
|
|
*/ |
521 |
|
|
void |
522 |
|
|
editor_allocspace(struct disklabel *lp_org) |
523 |
|
|
{ |
524 |
|
|
struct disklabel *lp, label; |
525 |
|
|
struct space_allocation *alloc; |
526 |
|
|
struct space_allocation *ap; |
527 |
|
|
struct partition *pp; |
528 |
|
|
struct diskchunk *chunks; |
529 |
|
|
u_int64_t chunkstart, chunksize, cylsecs, secs, totsecs, xtrasecs; |
530 |
|
|
char **partmp; |
531 |
|
|
int i, j, lastalloc, index = 0, fragsize, partno; |
532 |
|
|
extern int64_t physmem; |
533 |
|
|
|
534 |
|
|
/* How big is the OpenBSD portion of the disk? */ |
535 |
|
|
find_bounds(lp_org); |
536 |
|
|
|
537 |
|
|
overlap = 0; |
538 |
|
|
for (i = 0; i < MAXPARTITIONS; i++) { |
539 |
|
|
u_int64_t psz, pstart, pend; |
540 |
|
|
|
541 |
|
|
pp = &lp_org->d_partitions[i]; |
542 |
|
|
psz = DL_GETPSIZE(pp); |
543 |
|
|
pstart = DL_GETPOFFSET(pp); |
544 |
|
|
pend = pstart + psz; |
545 |
|
|
if (i != RAW_PART && psz != 0 && |
546 |
|
|
((pstart >= starting_sector && pstart <= ending_sector) || |
547 |
|
|
(pend > starting_sector && pend < ending_sector))) { |
548 |
|
|
overlap = 1; |
549 |
|
|
break; |
550 |
|
|
} |
551 |
|
|
} |
552 |
|
|
|
553 |
|
|
cylsecs = lp_org->d_secpercyl; |
554 |
|
|
again: |
555 |
|
|
lp = &label; |
556 |
|
|
for (i=0; i<MAXPARTITIONS; i++) { |
557 |
|
|
free(mountpoints[i]); |
558 |
|
|
mountpoints[i] = NULL; |
559 |
|
|
} |
560 |
|
|
memcpy(lp, lp_org, sizeof(struct disklabel)); |
561 |
|
|
lp->d_npartitions = MAXPARTITIONS; |
562 |
|
|
lastalloc = alloc_table[index].sz; |
563 |
|
|
alloc = reallocarray(NULL, lastalloc, sizeof(struct space_allocation)); |
564 |
|
|
if (alloc == NULL) |
565 |
|
|
errx(4, "out of memory"); |
566 |
|
|
memcpy(alloc, alloc_table[index].table, |
567 |
|
|
lastalloc * sizeof(struct space_allocation)); |
568 |
|
|
|
569 |
|
|
/* bump max swap based on phys mem, little physmem gets 2x swap */ |
570 |
|
|
if (index == 0 && alloc_table == alloc_table_default) { |
571 |
|
|
if (physmem / DEV_BSIZE < MEG(256)) |
572 |
|
|
alloc[1].minsz = alloc[1].maxsz = 2 * (physmem / DEV_BSIZE); |
573 |
|
|
else |
574 |
|
|
alloc[1].maxsz += (physmem / DEV_BSIZE); |
575 |
|
|
/* bump max /var to make room for 2 crash dumps */ |
576 |
|
|
alloc[3].maxsz += 2 * (physmem / DEV_BSIZE); |
577 |
|
|
} |
578 |
|
|
|
579 |
|
|
xtrasecs = totsecs = editor_countfree(lp); |
580 |
|
|
|
581 |
|
|
for (i = 0; i < lastalloc; i++) { |
582 |
|
|
alloc[i].minsz = DL_BLKTOSEC(lp, alloc[i].minsz); |
583 |
|
|
alloc[i].maxsz = DL_BLKTOSEC(lp, alloc[i].maxsz); |
584 |
|
|
if (xtrasecs > alloc[i].minsz) |
585 |
|
|
xtrasecs -= alloc[i].minsz; |
586 |
|
|
else |
587 |
|
|
xtrasecs = 0; |
588 |
|
|
} |
589 |
|
|
|
590 |
|
|
for (i = 0; i < lastalloc; i++) { |
591 |
|
|
/* Find next available partition. */ |
592 |
|
|
for (j = 0; j < MAXPARTITIONS; j++) |
593 |
|
|
if (DL_GETPSIZE(&lp->d_partitions[j]) == 0) |
594 |
|
|
break; |
595 |
|
|
if (j == MAXPARTITIONS) { |
596 |
|
|
/* It did not work out, try next strategy */ |
597 |
|
|
free(alloc); |
598 |
|
|
if (++index < alloc_table_nitems) |
599 |
|
|
goto again; |
600 |
|
|
else |
601 |
|
|
return; |
602 |
|
|
} |
603 |
|
|
partno = j; |
604 |
|
|
pp = &lp->d_partitions[j]; |
605 |
|
|
partmp = &mountpoints[j]; |
606 |
|
|
ap = &alloc[i]; |
607 |
|
|
|
608 |
|
|
/* Figure out the size of the partition. */ |
609 |
|
|
if (i == lastalloc - 1) { |
610 |
|
|
if (totsecs > ap->maxsz) |
611 |
|
|
secs = ap->maxsz; |
612 |
|
|
else |
613 |
|
|
secs = totsecs; |
614 |
|
|
#ifdef SUN_CYLCHECK |
615 |
|
|
goto cylinderalign; |
616 |
|
|
#endif |
617 |
|
|
} else { |
618 |
|
|
secs = ap->minsz; |
619 |
|
|
if (xtrasecs > 0) |
620 |
|
|
secs += (xtrasecs / 100) * ap->rate; |
621 |
|
|
if (secs > ap->maxsz) |
622 |
|
|
secs = ap->maxsz; |
623 |
|
|
#ifdef SUN_CYLCHECK |
624 |
|
|
cylinderalign: |
625 |
|
|
secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs; |
626 |
|
|
#endif |
627 |
|
|
totsecs -= secs; |
628 |
|
|
#ifdef SUN_CYLCHECK |
629 |
|
|
while (totsecs < 0) { |
630 |
|
|
secs -= cylsecs; |
631 |
|
|
totsecs += cylsecs; |
632 |
|
|
} |
633 |
|
|
#endif |
634 |
|
|
} |
635 |
|
|
|
636 |
|
|
/* Find largest chunk of free space. */ |
637 |
|
|
chunks = free_chunks(lp); |
638 |
|
|
chunkstart = 0; |
639 |
|
|
chunksize = 0; |
640 |
|
|
for (j = 0; chunks[j].start != 0 || chunks[j].stop != 0; j++) |
641 |
|
|
if ((chunks[j].stop - chunks[j].start) > chunksize) { |
642 |
|
|
chunkstart = chunks[j].start; |
643 |
|
|
chunksize = chunks[j].stop - chunks[j].start; |
644 |
|
|
} |
645 |
|
|
#ifdef SUN_CYLCHECK |
646 |
|
|
if (lp->d_flags & D_VENDOR) { |
647 |
|
|
/* Align chunk to cylinder boundaries. */ |
648 |
|
|
chunksize -= chunksize % cylsecs; |
649 |
|
|
chunkstart = ((chunkstart + cylsecs - 1) / cylsecs) * |
650 |
|
|
cylsecs; |
651 |
|
|
} |
652 |
|
|
#endif |
653 |
|
|
/* See if partition can fit into chunk. */ |
654 |
|
|
if (secs > chunksize) { |
655 |
|
|
totsecs += secs - chunksize; |
656 |
|
|
secs = chunksize; |
657 |
|
|
} |
658 |
|
|
if (secs < ap->minsz) { |
659 |
|
|
/* It did not work out, try next strategy */ |
660 |
|
|
free(alloc); |
661 |
|
|
if (++index < alloc_table_nitems) |
662 |
|
|
goto again; |
663 |
|
|
else |
664 |
|
|
return; |
665 |
|
|
} |
666 |
|
|
|
667 |
|
|
/* Everything seems ok so configure the partition. */ |
668 |
|
|
DL_SETPSIZE(pp, secs); |
669 |
|
|
DL_SETPOFFSET(pp, chunkstart); |
670 |
|
|
fragsize = (lp->d_secsize == DEV_BSIZE) ? 2048 : |
671 |
|
|
lp->d_secsize; |
672 |
|
|
if (secs * lp->d_secsize > 128ULL * 1024 * 1024 * 1024) |
673 |
|
|
fragsize *= 2; |
674 |
|
|
if (secs * lp->d_secsize > 512ULL * 1024 * 1024 * 1024) |
675 |
|
|
fragsize *= 2; |
676 |
|
|
#if defined (__sparc__) && !defined(__sparc64__) |
677 |
|
|
/* can't boot from > 8k boot blocks */ |
678 |
|
|
pp->p_fragblock = |
679 |
|
|
DISKLABELV1_FFS_FRAGBLOCK(i == 0 ? 1024 : fragsize, 8); |
680 |
|
|
#else |
681 |
|
|
pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8); |
682 |
|
|
#endif |
683 |
|
|
pp->p_cpg = 1; |
684 |
|
|
if (ap->mp[0] != '/') |
685 |
|
|
pp->p_fstype = FS_SWAP; |
686 |
|
|
else { |
687 |
|
|
pp->p_fstype = FS_BSDFFS; |
688 |
|
|
get_bsize(lp, partno); |
689 |
|
|
free(*partmp); |
690 |
|
|
if ((*partmp = strdup(ap->mp)) == NULL) |
691 |
|
|
errx(4, "out of memory"); |
692 |
|
|
} |
693 |
|
|
} |
694 |
|
|
|
695 |
|
|
free(alloc); |
696 |
|
|
memcpy(lp_org, lp, sizeof(struct disklabel)); |
697 |
|
|
} |
698 |
|
|
|
699 |
|
|
/* |
700 |
|
|
* Resize a partition, moving all subsequent partitions |
701 |
|
|
*/ |
702 |
|
|
void |
703 |
|
|
editor_resize(struct disklabel *lp, char *p) |
704 |
|
|
{ |
705 |
|
|
struct disklabel label; |
706 |
|
|
struct partition *pp, *prev; |
707 |
|
|
u_int64_t secs, sz, off; |
708 |
|
|
#ifdef SUN_CYLCHECK |
709 |
|
|
u_int64_t cylsecs; |
710 |
|
|
#endif |
711 |
|
|
int partno, i; |
712 |
|
|
|
713 |
|
|
label = *lp; |
714 |
|
|
|
715 |
|
|
/* Change which partition? */ |
716 |
|
|
if (p == NULL) { |
717 |
|
|
p = getstring("partition to resize", |
718 |
|
|
"The letter of the partition to name, a - p.", NULL); |
719 |
|
|
} |
720 |
|
|
if (p == NULL) { |
721 |
|
|
fputs("Command aborted\n", stderr); |
722 |
|
|
return; |
723 |
|
|
} |
724 |
|
|
partno = p[0] - 'a'; |
725 |
|
|
if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { |
726 |
|
|
fprintf(stderr, "Partition must be between 'a' and '%c' " |
727 |
|
|
"(excluding 'c').\n", 'a' + lp->d_npartitions - 1); |
728 |
|
|
return; |
729 |
|
|
} |
730 |
|
|
|
731 |
|
|
pp = &label.d_partitions[partno]; |
732 |
|
|
sz = DL_GETPSIZE(pp); |
733 |
|
|
if (sz == 0) { |
734 |
|
|
fputs("No such partition\n", stderr); |
735 |
|
|
return; |
736 |
|
|
} |
737 |
|
|
if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) { |
738 |
|
|
fputs("Cannot resize spoofed partition\n", stderr); |
739 |
|
|
return; |
740 |
|
|
} |
741 |
|
|
secs = getuint64(lp, "[+|-]new size (with unit)", |
742 |
|
|
"new size or amount to grow (+) or shrink (-) partition including unit", |
743 |
|
|
sz, editor_countfree(lp), 0, DO_CONVERSIONS); |
744 |
|
|
|
745 |
|
|
if (secs <= 0) { |
746 |
|
|
fputs("Command aborted\n", stderr); |
747 |
|
|
return; |
748 |
|
|
} |
749 |
|
|
|
750 |
|
|
#ifdef SUN_CYLCHECK |
751 |
|
|
cylsecs = lp->d_secpercyl; |
752 |
|
|
if (secs > 0) |
753 |
|
|
secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs; |
754 |
|
|
else |
755 |
|
|
secs = ((secs - cylsecs + 1) / cylsecs) * cylsecs; |
756 |
|
|
#endif |
757 |
|
|
if (DL_GETPOFFSET(pp) + secs > ending_sector) { |
758 |
|
|
fputs("Amount too big\n", stderr); |
759 |
|
|
return; |
760 |
|
|
} |
761 |
|
|
|
762 |
|
|
DL_SETPSIZE(pp, secs); |
763 |
|
|
get_bsize(&label, partno); |
764 |
|
|
|
765 |
|
|
/* |
766 |
|
|
* Pack partitions above the resized partition, leaving unused |
767 |
|
|
* partions alone. |
768 |
|
|
*/ |
769 |
|
|
prev = pp; |
770 |
|
|
for (i = partno + 1; i < MAXPARTITIONS; i++) { |
771 |
|
|
if (i == RAW_PART) |
772 |
|
|
continue; |
773 |
|
|
pp = &label.d_partitions[i]; |
774 |
|
|
if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) |
775 |
|
|
continue; |
776 |
|
|
sz = DL_GETPSIZE(pp); |
777 |
|
|
if (sz == 0) |
778 |
|
|
continue; |
779 |
|
|
|
780 |
|
|
off = DL_GETPOFFSET(prev) + DL_GETPSIZE(prev); |
781 |
|
|
|
782 |
|
|
if (off < ending_sector) { |
783 |
|
|
DL_SETPOFFSET(pp, off); |
784 |
|
|
if (off + DL_GETPSIZE(pp) > ending_sector) { |
785 |
|
|
DL_SETPSIZE(pp, ending_sector - off); |
786 |
|
|
fprintf(stderr, |
787 |
|
|
"Partition %c shrunk to make room\n", |
788 |
|
|
i + 'a'); |
789 |
|
|
} |
790 |
|
|
} else { |
791 |
|
|
fputs("No room left for all partitions\n", stderr); |
792 |
|
|
return; |
793 |
|
|
} |
794 |
|
|
get_bsize(&label, i); |
795 |
|
|
prev = pp; |
796 |
|
|
} |
797 |
|
|
*lp = label; |
798 |
|
|
} |
799 |
|
|
|
800 |
|
|
/* |
801 |
|
|
* Add a new partition. |
802 |
|
|
*/ |
803 |
|
|
void |
804 |
|
|
editor_add(struct disklabel *lp, char *p) |
805 |
|
|
{ |
806 |
|
|
struct partition *pp; |
807 |
|
|
struct diskchunk *chunks; |
808 |
|
|
char buf[2]; |
809 |
|
|
int i, partno, fragsize; |
810 |
|
|
u_int64_t freesectors, new_offset, new_size; |
811 |
|
|
|
812 |
|
|
freesectors = editor_countfree(lp); |
813 |
|
|
|
814 |
|
|
/* XXX - prompt user to steal space from another partition instead */ |
815 |
|
|
#ifdef SUN_CYLCHECK |
816 |
|
|
if ((lp->d_flags & D_VENDOR) && freesectors < lp->d_secpercyl) { |
817 |
|
|
fputs("No space left, you need to shrink a partition " |
818 |
|
|
"(need at least one full cylinder)\n", |
819 |
|
|
stderr); |
820 |
|
|
return; |
821 |
|
|
} |
822 |
|
|
#endif |
823 |
|
|
if (freesectors == 0) { |
824 |
|
|
fputs("No space left, you need to shrink a partition\n", |
825 |
|
|
stderr); |
826 |
|
|
return; |
827 |
|
|
} |
828 |
|
|
|
829 |
|
|
if (p == NULL) { |
830 |
|
|
/* |
831 |
|
|
* Use the first unused partition that is not 'c' as the |
832 |
|
|
* default partition in the prompt string. |
833 |
|
|
*/ |
834 |
|
|
pp = &lp->d_partitions[0]; |
835 |
|
|
buf[0] = buf[1] = '\0'; |
836 |
|
|
for (partno = 0; partno < MAXPARTITIONS; partno++, pp++) { |
837 |
|
|
if (DL_GETPSIZE(pp) == 0 && partno != RAW_PART) { |
838 |
|
|
buf[0] = partno + 'a'; |
839 |
|
|
p = &buf[0]; |
840 |
|
|
break; |
841 |
|
|
} |
842 |
|
|
} |
843 |
|
|
p = getstring("partition", |
844 |
|
|
"The letter of the new partition, a - p.", p); |
845 |
|
|
} |
846 |
|
|
if (p == NULL) { |
847 |
|
|
fputs("Command aborted\n", stderr); |
848 |
|
|
return; |
849 |
|
|
} |
850 |
|
|
partno = p[0] - 'a'; |
851 |
|
|
if (partno < 0 || partno == RAW_PART || partno >= MAXPARTITIONS) { |
852 |
|
|
fprintf(stderr, "Partition must be between 'a' and '%c' " |
853 |
|
|
"(excluding 'c').\n", 'a' + MAXPARTITIONS - 1); |
854 |
|
|
return; |
855 |
|
|
} |
856 |
|
|
pp = &lp->d_partitions[partno]; |
857 |
|
|
|
858 |
|
|
if (pp->p_fstype != FS_UNUSED && DL_GETPSIZE(pp) != 0) { |
859 |
|
|
fprintf(stderr, "Partition '%c' exists. Delete it first.\n", |
860 |
|
|
p[0]); |
861 |
|
|
return; |
862 |
|
|
} |
863 |
|
|
|
864 |
|
|
/* |
865 |
|
|
* Increase d_npartitions if necessary. Ensure all new partitions are |
866 |
|
|
* zero'ed to avoid inadvertent overlaps. |
867 |
|
|
*/ |
868 |
|
|
for(; lp->d_npartitions <= partno; lp->d_npartitions++) |
869 |
|
|
memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp)); |
870 |
|
|
|
871 |
|
|
/* Make sure selected partition is zero'd too. */ |
872 |
|
|
memset(pp, 0, sizeof(*pp)); |
873 |
|
|
chunks = free_chunks(lp); |
874 |
|
|
|
875 |
|
|
/* |
876 |
|
|
* Since we know there's free space, there must be at least one |
877 |
|
|
* chunk. So find the largest chunk and assume we want to add the |
878 |
|
|
* partition in that free space. |
879 |
|
|
*/ |
880 |
|
|
new_size = new_offset = 0; |
881 |
|
|
for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { |
882 |
|
|
if (chunks[i].stop - chunks[i].start > new_size) { |
883 |
|
|
new_size = chunks[i].stop - chunks[i].start; |
884 |
|
|
new_offset = chunks[i].start; |
885 |
|
|
} |
886 |
|
|
} |
887 |
|
|
DL_SETPSIZE(pp, new_size); |
888 |
|
|
DL_SETPOFFSET(pp, new_offset); |
889 |
|
|
pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS; |
890 |
|
|
pp->p_cpg = 1; |
891 |
|
|
|
892 |
|
|
if (get_offset(lp, partno) == 0 && |
893 |
|
|
get_size(lp, partno) == 0) { |
894 |
|
|
fragsize = (lp->d_secsize == DEV_BSIZE) ? 2048 : |
895 |
|
|
lp->d_secsize; |
896 |
|
|
new_size = DL_GETPSIZE(pp) * lp->d_secsize; |
897 |
|
|
if (new_size > 128ULL * 1024 * 1024 * 1024) |
898 |
|
|
fragsize *= 2; |
899 |
|
|
if (new_size > 512ULL * 1024 * 1024 * 1024) |
900 |
|
|
fragsize *= 2; |
901 |
|
|
if (fragsize > MAXBSIZE / 8) |
902 |
|
|
fragsize = MAXBSIZE / 8; |
903 |
|
|
#if defined (__sparc__) && !defined(__sparc64__) |
904 |
|
|
/* can't boot from > 8k boot blocks */ |
905 |
|
|
pp->p_fragblock = |
906 |
|
|
DISKLABELV1_FFS_FRAGBLOCK(partno == 0 ? 1024 : fragsize, 8); |
907 |
|
|
#else |
908 |
|
|
pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8); |
909 |
|
|
#endif |
910 |
|
|
if (get_fstype(lp, partno) == 0 && |
911 |
|
|
get_mp(lp, partno) == 0 && |
912 |
|
|
get_fsize(lp, partno) == 0 && |
913 |
|
|
get_bsize(lp, partno) == 0) |
914 |
|
|
return; |
915 |
|
|
} |
916 |
|
|
/* Bailed out at some point, so effectively delete the partition. */ |
917 |
|
|
memset(pp, 0, sizeof(*pp)); |
918 |
|
|
} |
919 |
|
|
|
920 |
|
|
/* |
921 |
|
|
* Set the mountpoint of an existing partition ('name'). |
922 |
|
|
*/ |
923 |
|
|
void |
924 |
|
|
editor_name(struct disklabel *lp, char *p) |
925 |
|
|
{ |
926 |
|
|
struct partition *pp; |
927 |
|
|
int partno; |
928 |
|
|
|
929 |
|
|
/* Change which partition? */ |
930 |
|
|
if (p == NULL) { |
931 |
|
|
p = getstring("partition to name", |
932 |
|
|
"The letter of the partition to name, a - p.", NULL); |
933 |
|
|
} |
934 |
|
|
if (p == NULL) { |
935 |
|
|
fputs("Command aborted\n", stderr); |
936 |
|
|
return; |
937 |
|
|
} |
938 |
|
|
partno = p[0] - 'a'; |
939 |
|
|
if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { |
940 |
|
|
fprintf(stderr, "Partition must be between 'a' and '%c' " |
941 |
|
|
"(excluding 'c').\n", 'a' + lp->d_npartitions - 1); |
942 |
|
|
return; |
943 |
|
|
} |
944 |
|
|
pp = &lp->d_partitions[partno]; |
945 |
|
|
|
946 |
|
|
if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { |
947 |
|
|
fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); |
948 |
|
|
return; |
949 |
|
|
} |
950 |
|
|
|
951 |
|
|
/* Not all fstypes can be named */ |
952 |
|
|
if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_SWAP || |
953 |
|
|
pp->p_fstype == FS_BOOT || pp->p_fstype == FS_OTHER || |
954 |
|
|
pp->p_fstype == FS_RAID) { |
955 |
|
|
fprintf(stderr, "You cannot name a filesystem of type %s.\n", |
956 |
|
|
fstypenames[lp->d_partitions[partno].p_fstype]); |
957 |
|
|
return; |
958 |
|
|
} |
959 |
|
|
|
960 |
|
|
get_mp(lp, partno); |
961 |
|
|
} |
962 |
|
|
|
963 |
|
|
/* |
964 |
|
|
* Change an existing partition. |
965 |
|
|
*/ |
966 |
|
|
void |
967 |
|
|
editor_modify(struct disklabel *lp, char *p) |
968 |
|
|
{ |
969 |
|
|
struct partition origpart, *pp; |
970 |
|
|
int partno; |
971 |
|
|
|
972 |
|
|
/* Change which partition? */ |
973 |
|
|
if (p == NULL) { |
974 |
|
|
p = getstring("partition to modify", |
975 |
|
|
"The letter of the partition to modify, a - p.", NULL); |
976 |
|
|
} |
977 |
|
|
if (p == NULL) { |
978 |
|
|
fputs("Command aborted\n", stderr); |
979 |
|
|
return; |
980 |
|
|
} |
981 |
|
|
partno = p[0] - 'a'; |
982 |
|
|
if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { |
983 |
|
|
fprintf(stderr, "Partition must be between 'a' and '%c' " |
984 |
|
|
"(excluding 'c').\n", 'a' + lp->d_npartitions - 1); |
985 |
|
|
return; |
986 |
|
|
} |
987 |
|
|
pp = &lp->d_partitions[partno]; |
988 |
|
|
|
989 |
|
|
if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { |
990 |
|
|
fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); |
991 |
|
|
return; |
992 |
|
|
} |
993 |
|
|
|
994 |
|
|
origpart = *pp; |
995 |
|
|
|
996 |
|
|
if (get_offset(lp, partno) == 0 && |
997 |
|
|
get_size(lp, partno) == 0 && |
998 |
|
|
get_fstype(lp, partno) == 0 && |
999 |
|
|
get_mp(lp, partno) == 0 && |
1000 |
|
|
get_fsize(lp, partno) == 0 && |
1001 |
|
|
get_bsize(lp, partno) == 0) |
1002 |
|
|
return; |
1003 |
|
|
|
1004 |
|
|
/* Bailed out at some point, so undo any changes. */ |
1005 |
|
|
*pp = origpart; |
1006 |
|
|
} |
1007 |
|
|
|
1008 |
|
|
/* |
1009 |
|
|
* Delete an existing partition. |
1010 |
|
|
*/ |
1011 |
|
|
void |
1012 |
|
|
editor_delete(struct disklabel *lp, char *p) |
1013 |
|
|
{ |
1014 |
|
|
struct partition *pp; |
1015 |
|
|
int partno; |
1016 |
|
|
|
1017 |
|
|
if (p == NULL) { |
1018 |
|
|
p = getstring("partition to delete", |
1019 |
|
|
"The letter of the partition to delete, a - p, or '*'.", |
1020 |
|
|
NULL); |
1021 |
|
|
} |
1022 |
|
|
if (p == NULL) { |
1023 |
|
|
fputs("Command aborted\n", stderr); |
1024 |
|
|
return; |
1025 |
|
|
} |
1026 |
|
|
if (p[0] == '*') { |
1027 |
|
|
zero_partitions(lp); |
1028 |
|
|
return; |
1029 |
|
|
} |
1030 |
|
|
partno = p[0] - 'a'; |
1031 |
|
|
if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { |
1032 |
|
|
fprintf(stderr, "Partition must be between 'a' and '%c' " |
1033 |
|
|
"(excluding 'c').\n", 'a' + lp->d_npartitions - 1); |
1034 |
|
|
return; |
1035 |
|
|
} |
1036 |
|
|
pp = &lp->d_partitions[partno]; |
1037 |
|
|
|
1038 |
|
|
if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { |
1039 |
|
|
fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); |
1040 |
|
|
return; |
1041 |
|
|
} |
1042 |
|
|
|
1043 |
|
|
/* Really delete it (as opposed to just setting to "unused") */ |
1044 |
|
|
memset(pp, 0, sizeof(*pp)); |
1045 |
|
|
free(mountpoints[partno]); |
1046 |
|
|
mountpoints[partno] = NULL; |
1047 |
|
|
} |
1048 |
|
|
|
1049 |
|
|
/* |
1050 |
|
|
* Change the size of an existing partition. |
1051 |
|
|
*/ |
1052 |
|
|
void |
1053 |
|
|
editor_change(struct disklabel *lp, char *p) |
1054 |
|
|
{ |
1055 |
|
|
struct partition *pp; |
1056 |
|
|
int partno; |
1057 |
|
|
|
1058 |
|
|
if (p == NULL) { |
1059 |
|
|
p = getstring("partition to change size", |
1060 |
|
|
"The letter of the partition to change size, a - p.", NULL); |
1061 |
|
|
} |
1062 |
|
|
if (p == NULL) { |
1063 |
|
|
fputs("Command aborted\n", stderr); |
1064 |
|
|
return; |
1065 |
|
|
} |
1066 |
|
|
partno = p[0] - 'a'; |
1067 |
|
|
if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { |
1068 |
|
|
fprintf(stderr, "Partition must be between 'a' and '%c' " |
1069 |
|
|
"(excluding 'c').\n", 'a' + lp->d_npartitions - 1); |
1070 |
|
|
return; |
1071 |
|
|
} |
1072 |
|
|
pp = &lp->d_partitions[partno]; |
1073 |
|
|
|
1074 |
|
|
if (DL_GETPSIZE(pp) == 0) { |
1075 |
|
|
fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); |
1076 |
|
|
return; |
1077 |
|
|
} |
1078 |
|
|
|
1079 |
|
|
printf("Partition %c is currently %llu sectors in size, and can have " |
1080 |
|
|
"a maximum\nsize of %llu sectors.\n", |
1081 |
|
|
p[0], DL_GETPSIZE(pp), max_partition_size(lp, partno)); |
1082 |
|
|
|
1083 |
|
|
/* Get new size */ |
1084 |
|
|
get_size(lp, partno); |
1085 |
|
|
} |
1086 |
|
|
|
1087 |
|
|
/* |
1088 |
|
|
* Sort the partitions based on starting offset. |
1089 |
|
|
* This assumes there can be no overlap. |
1090 |
|
|
*/ |
1091 |
|
|
int |
1092 |
|
|
partition_cmp(const void *e1, const void *e2) |
1093 |
|
|
{ |
1094 |
|
|
struct partition *p1 = *(struct partition **)e1; |
1095 |
|
|
struct partition *p2 = *(struct partition **)e2; |
1096 |
|
|
u_int64_t o1 = DL_GETPOFFSET(p1); |
1097 |
|
|
u_int64_t o2 = DL_GETPOFFSET(p2); |
1098 |
|
|
|
1099 |
|
|
if (o1 < o2) |
1100 |
|
|
return -1; |
1101 |
|
|
else if (o1 > o2) |
1102 |
|
|
return 1; |
1103 |
|
|
else |
1104 |
|
|
return 0; |
1105 |
|
|
} |
1106 |
|
|
|
1107 |
|
|
char * |
1108 |
|
|
getstring(const char *prompt, const char *helpstring, const char *oval) |
1109 |
|
|
{ |
1110 |
|
|
static char buf[BUFSIZ]; |
1111 |
|
|
int n; |
1112 |
|
|
|
1113 |
|
|
buf[0] = '\0'; |
1114 |
|
|
do { |
1115 |
|
|
printf("%s: [%s] ", prompt, oval ? oval : ""); |
1116 |
|
|
if (fgets(buf, sizeof(buf), stdin) == NULL) { |
1117 |
|
|
buf[0] = '\0'; |
1118 |
|
|
if (feof(stdin)) { |
1119 |
|
|
clearerr(stdin); |
1120 |
|
|
putchar('\n'); |
1121 |
|
|
return(NULL); |
1122 |
|
|
} |
1123 |
|
|
} |
1124 |
|
|
n = strlen(buf); |
1125 |
|
|
if (n > 0 && buf[n-1] == '\n') |
1126 |
|
|
buf[--n] = '\0'; |
1127 |
|
|
if (buf[0] == '?') |
1128 |
|
|
puts(helpstring); |
1129 |
|
|
else if (oval != NULL && buf[0] == '\0') |
1130 |
|
|
strlcpy(buf, oval, sizeof(buf)); |
1131 |
|
|
} while (buf[0] == '?'); |
1132 |
|
|
|
1133 |
|
|
return(&buf[0]); |
1134 |
|
|
} |
1135 |
|
|
|
1136 |
|
|
/* |
1137 |
|
|
* Returns ULLONG_MAX on error |
1138 |
|
|
* Usually only called by helper functions. |
1139 |
|
|
*/ |
1140 |
|
|
u_int64_t |
1141 |
|
|
getuint64(struct disklabel *lp, char *prompt, char *helpstring, |
1142 |
|
|
u_int64_t oval, u_int64_t maxval, u_int64_t offset, int flags) |
1143 |
|
|
{ |
1144 |
|
|
char buf[BUFSIZ], *endptr, *p, operator = '\0'; |
1145 |
|
|
u_int64_t rval = oval; |
1146 |
|
|
int64_t mult = 1; |
1147 |
|
|
size_t n; |
1148 |
|
|
double d, percent = 1.0; |
1149 |
|
|
|
1150 |
|
|
/* We only care about the remainder */ |
1151 |
|
|
offset = offset % lp->d_secpercyl; |
1152 |
|
|
|
1153 |
|
|
buf[0] = '\0'; |
1154 |
|
|
do { |
1155 |
|
|
printf("%s: [%llu] ", prompt, oval); |
1156 |
|
|
if (fgets(buf, sizeof(buf), stdin) == NULL) { |
1157 |
|
|
buf[0] = '\0'; |
1158 |
|
|
if (feof(stdin)) { |
1159 |
|
|
clearerr(stdin); |
1160 |
|
|
putchar('\n'); |
1161 |
|
|
return(ULLONG_MAX - 1); |
1162 |
|
|
} |
1163 |
|
|
} |
1164 |
|
|
n = strlen(buf); |
1165 |
|
|
if (n > 0 && buf[n-1] == '\n') |
1166 |
|
|
buf[--n] = '\0'; |
1167 |
|
|
if (buf[0] == '?') |
1168 |
|
|
puts(helpstring); |
1169 |
|
|
} while (buf[0] == '?'); |
1170 |
|
|
|
1171 |
|
|
if (buf[0] == '*' && buf[1] == '\0') { |
1172 |
|
|
rval = maxval; |
1173 |
|
|
} else { |
1174 |
|
|
/* deal with units */ |
1175 |
|
|
if (buf[0] != '\0' && n > 0) { |
1176 |
|
|
if ((flags & DO_CONVERSIONS)) { |
1177 |
|
|
switch (tolower((unsigned char)buf[n-1])) { |
1178 |
|
|
|
1179 |
|
|
case 'c': |
1180 |
|
|
mult = lp->d_secpercyl; |
1181 |
|
|
buf[--n] = '\0'; |
1182 |
|
|
break; |
1183 |
|
|
case 'b': |
1184 |
|
|
mult = -(int64_t)lp->d_secsize; |
1185 |
|
|
buf[--n] = '\0'; |
1186 |
|
|
break; |
1187 |
|
|
case 'k': |
1188 |
|
|
if (lp->d_secsize > 1024) |
1189 |
|
|
mult = -(int64_t)lp->d_secsize / |
1190 |
|
|
1024LL; |
1191 |
|
|
else |
1192 |
|
|
mult = 1024LL / lp->d_secsize; |
1193 |
|
|
buf[--n] = '\0'; |
1194 |
|
|
break; |
1195 |
|
|
case 'm': |
1196 |
|
|
mult = (1024LL * 1024) / lp->d_secsize; |
1197 |
|
|
buf[--n] = '\0'; |
1198 |
|
|
break; |
1199 |
|
|
case 'g': |
1200 |
|
|
mult = (1024LL * 1024 * 1024) / |
1201 |
|
|
lp->d_secsize; |
1202 |
|
|
buf[--n] = '\0'; |
1203 |
|
|
break; |
1204 |
|
|
case 't': |
1205 |
|
|
mult = (1024LL * 1024 * 1024 * 1024) / |
1206 |
|
|
lp->d_secsize; |
1207 |
|
|
buf[--n] = '\0'; |
1208 |
|
|
break; |
1209 |
|
|
case '%': |
1210 |
|
|
buf[--n] = '\0'; |
1211 |
|
|
p = &buf[0]; |
1212 |
|
|
if (*p == '+' || *p == '-') |
1213 |
|
|
operator = *p++; |
1214 |
|
|
percent = strtod(p, NULL) / 100.0; |
1215 |
|
|
snprintf(buf, sizeof(buf), "%llu", |
1216 |
|
|
DL_GETDSIZE(lp)); |
1217 |
|
|
break; |
1218 |
|
|
case '&': |
1219 |
|
|
buf[--n] = '\0'; |
1220 |
|
|
p = &buf[0]; |
1221 |
|
|
if (*p == '+' || *p == '-') |
1222 |
|
|
operator = *p++; |
1223 |
|
|
percent = strtod(p, NULL) / 100.0; |
1224 |
|
|
snprintf(buf, sizeof(buf), "%lld", |
1225 |
|
|
maxval); |
1226 |
|
|
break; |
1227 |
|
|
} |
1228 |
|
|
} |
1229 |
|
|
|
1230 |
|
|
/* Did they give us an operator? */ |
1231 |
|
|
p = &buf[0]; |
1232 |
|
|
if (*p == '+' || *p == '-') |
1233 |
|
|
operator = *p++; |
1234 |
|
|
|
1235 |
|
|
endptr = p; |
1236 |
|
|
errno = 0; |
1237 |
|
|
d = strtod(p, &endptr); |
1238 |
|
|
if (errno == ERANGE) |
1239 |
|
|
rval = ULLONG_MAX; /* too big/small */ |
1240 |
|
|
else if (*endptr != '\0') { |
1241 |
|
|
errno = EINVAL; /* non-numbers in str */ |
1242 |
|
|
rval = ULLONG_MAX; |
1243 |
|
|
} else { |
1244 |
|
|
/* XXX - should check for overflow */ |
1245 |
|
|
if (mult > 0) |
1246 |
|
|
rval = d * mult * percent; |
1247 |
|
|
else |
1248 |
|
|
/* Negative mult means divide (fancy) */ |
1249 |
|
|
rval = d / (-mult) * percent; |
1250 |
|
|
|
1251 |
|
|
/* Apply the operator */ |
1252 |
|
|
if (operator == '+') |
1253 |
|
|
rval += oval; |
1254 |
|
|
else if (operator == '-') |
1255 |
|
|
rval = oval - rval; |
1256 |
|
|
} |
1257 |
|
|
} |
1258 |
|
|
} |
1259 |
|
|
if ((flags & DO_ROUNDING) && rval != ULLONG_MAX) { |
1260 |
|
|
/* Round to nearest cylinder unless given in sectors */ |
1261 |
|
|
if ( |
1262 |
|
|
#ifdef SUN_CYLCHECK |
1263 |
|
|
((lp->d_flags & D_VENDOR) || mult != 1) && |
1264 |
|
|
#else |
1265 |
|
|
mult != 1 && |
1266 |
|
|
#endif |
1267 |
|
|
(rval + offset) % lp->d_secpercyl != 0) { |
1268 |
|
|
u_int64_t cyls; |
1269 |
|
|
|
1270 |
|
|
/* Round to higher cylinder but no more than maxval */ |
1271 |
|
|
cyls = (rval / lp->d_secpercyl) + 1; |
1272 |
|
|
if ((cyls * lp->d_secpercyl) - offset > maxval) |
1273 |
|
|
cyls--; |
1274 |
|
|
rval = (cyls * lp->d_secpercyl) - offset; |
1275 |
|
|
if (!aflag) |
1276 |
|
|
printf("Rounding size to cylinder (%d sectors)" |
1277 |
|
|
": %llu\n", lp->d_secpercyl, rval); |
1278 |
|
|
} |
1279 |
|
|
} |
1280 |
|
|
|
1281 |
|
|
return(rval); |
1282 |
|
|
} |
1283 |
|
|
|
1284 |
|
|
/* |
1285 |
|
|
* Check for partition overlap in lp and prompt the user to resolve the overlap |
1286 |
|
|
* if any is found. Returns 1 if unable to resolve, else 0. |
1287 |
|
|
*/ |
1288 |
|
|
int |
1289 |
|
|
has_overlap(struct disklabel *lp) |
1290 |
|
|
{ |
1291 |
|
|
struct partition **spp; |
1292 |
|
|
int c, i, j; |
1293 |
|
|
char buf[BUFSIZ]; |
1294 |
|
|
|
1295 |
|
|
/* Get a sorted list of the in-use partitions. */ |
1296 |
|
|
spp = sort_partitions(lp); |
1297 |
|
|
|
1298 |
|
|
/* If there are less than two partitions in use, there is no overlap. */ |
1299 |
|
|
if (spp[1] == NULL) |
1300 |
|
|
return(0); |
1301 |
|
|
|
1302 |
|
|
/* Now that we have things sorted by starting sector check overlap */ |
1303 |
|
|
for (i = 0; spp[i] != NULL; i++) { |
1304 |
|
|
for (j = i + 1; spp[j] != NULL; j++) { |
1305 |
|
|
/* `if last_sec_in_part + 1 > first_sec_in_next_part' */ |
1306 |
|
|
if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) > |
1307 |
|
|
DL_GETPOFFSET(spp[j])) { |
1308 |
|
|
/* Overlap! Convert to real part numbers. */ |
1309 |
|
|
i = ((char *)spp[i] - (char *)lp->d_partitions) |
1310 |
|
|
/ sizeof(**spp); |
1311 |
|
|
j = ((char *)spp[j] - (char *)lp->d_partitions) |
1312 |
|
|
/ sizeof(**spp); |
1313 |
|
|
printf("\nError, partitions %c and %c overlap:" |
1314 |
|
|
"\n", 'a' + i, 'a' + j); |
1315 |
|
|
printf("# %16.16s %16.16s fstype " |
1316 |
|
|
"[fsize bsize cpg]\n", "size", "offset"); |
1317 |
|
|
display_partition(stdout, lp, i, 0); |
1318 |
|
|
display_partition(stdout, lp, j, 0); |
1319 |
|
|
|
1320 |
|
|
/* Get partition to disable or ^D */ |
1321 |
|
|
do { |
1322 |
|
|
printf("Disable which one? " |
1323 |
|
|
"(^D to abort) [%c %c] ", |
1324 |
|
|
'a' + i, 'a' + j); |
1325 |
|
|
buf[0] = '\0'; |
1326 |
|
|
if (!fgets(buf, sizeof(buf), stdin)) { |
1327 |
|
|
putchar('\n'); |
1328 |
|
|
return(1); /* ^D */ |
1329 |
|
|
} |
1330 |
|
|
c = buf[0] - 'a'; |
1331 |
|
|
} while (buf[1] != '\n' && buf[1] != '\0' && |
1332 |
|
|
c != i && c != j); |
1333 |
|
|
|
1334 |
|
|
/* Mark the selected one as unused */ |
1335 |
|
|
lp->d_partitions[c].p_fstype = FS_UNUSED; |
1336 |
|
|
return (has_overlap(lp)); |
1337 |
|
|
} |
1338 |
|
|
} |
1339 |
|
|
} |
1340 |
|
|
|
1341 |
|
|
return(0); |
1342 |
|
|
} |
1343 |
|
|
|
1344 |
|
|
void |
1345 |
|
|
edit_parms(struct disklabel *lp) |
1346 |
|
|
{ |
1347 |
|
|
char *p; |
1348 |
|
|
u_int64_t freesectors, ui; |
1349 |
|
|
struct disklabel oldlabel = *lp; |
1350 |
|
|
|
1351 |
|
|
printf("Changing device parameters for %s:\n", specname); |
1352 |
|
|
|
1353 |
|
|
/* disk type */ |
1354 |
|
|
for (;;) { |
1355 |
|
|
p = getstring("disk type", |
1356 |
|
|
"What kind of disk is this? Usually SCSI, ESDI, ST506, or " |
1357 |
|
|
"floppy (use ESDI for IDE).", dktypenames[lp->d_type]); |
1358 |
|
|
if (p == NULL) { |
1359 |
|
|
fputs("Command aborted\n", stderr); |
1360 |
|
|
return; |
1361 |
|
|
} |
1362 |
|
|
if (strcasecmp(p, "IDE") == 0) |
1363 |
|
|
ui = DTYPE_ESDI; |
1364 |
|
|
else |
1365 |
|
|
for (ui = 1; ui < DKMAXTYPES && |
1366 |
|
|
strcasecmp(p, dktypenames[ui]); ui++) |
1367 |
|
|
; |
1368 |
|
|
if (ui < DKMAXTYPES) { |
1369 |
|
|
break; |
1370 |
|
|
} else { |
1371 |
|
|
printf("\"%s\" is not a valid disk type.\n", p); |
1372 |
|
|
fputs("Valid types are: ", stdout); |
1373 |
|
|
for (ui = 1; ui < DKMAXTYPES; ui++) { |
1374 |
|
|
printf("\"%s\"", dktypenames[ui]); |
1375 |
|
|
if (ui < DKMAXTYPES - 1) |
1376 |
|
|
fputs(", ", stdout); |
1377 |
|
|
} |
1378 |
|
|
putchar('\n'); |
1379 |
|
|
} |
1380 |
|
|
} |
1381 |
|
|
lp->d_type = ui; |
1382 |
|
|
|
1383 |
|
|
/* pack/label id */ |
1384 |
|
|
p = getstring("label name", |
1385 |
|
|
"15 char string that describes this label, usually the disk name.", |
1386 |
|
|
lp->d_packname); |
1387 |
|
|
if (p == NULL) { |
1388 |
|
|
fputs("Command aborted\n", stderr); |
1389 |
|
|
*lp = oldlabel; /* undo damage */ |
1390 |
|
|
return; |
1391 |
|
|
} |
1392 |
|
|
strncpy(lp->d_packname, p, sizeof(lp->d_packname)); /* checked */ |
1393 |
|
|
|
1394 |
|
|
/* sectors/track */ |
1395 |
|
|
for (;;) { |
1396 |
|
|
ui = getuint64(lp, "sectors/track", |
1397 |
|
|
"The Number of sectors per track.", lp->d_nsectors, |
1398 |
|
|
lp->d_nsectors, 0, 0); |
1399 |
|
|
if (ui == ULLONG_MAX - 1) { |
1400 |
|
|
fputs("Command aborted\n", stderr); |
1401 |
|
|
*lp = oldlabel; /* undo damage */ |
1402 |
|
|
return; |
1403 |
|
|
} if (ui == ULLONG_MAX) |
1404 |
|
|
fputs("Invalid entry\n", stderr); |
1405 |
|
|
else |
1406 |
|
|
break; |
1407 |
|
|
} |
1408 |
|
|
lp->d_nsectors = ui; |
1409 |
|
|
|
1410 |
|
|
/* tracks/cylinder */ |
1411 |
|
|
for (;;) { |
1412 |
|
|
ui = getuint64(lp, "tracks/cylinder", |
1413 |
|
|
"The number of tracks per cylinder.", lp->d_ntracks, |
1414 |
|
|
lp->d_ntracks, 0, 0); |
1415 |
|
|
if (ui == ULLONG_MAX - 1) { |
1416 |
|
|
fputs("Command aborted\n", stderr); |
1417 |
|
|
*lp = oldlabel; /* undo damage */ |
1418 |
|
|
return; |
1419 |
|
|
} else if (ui == ULLONG_MAX) |
1420 |
|
|
fputs("Invalid entry\n", stderr); |
1421 |
|
|
else |
1422 |
|
|
break; |
1423 |
|
|
} |
1424 |
|
|
lp->d_ntracks = ui; |
1425 |
|
|
|
1426 |
|
|
/* sectors/cylinder */ |
1427 |
|
|
for (;;) { |
1428 |
|
|
ui = getuint64(lp, "sectors/cylinder", |
1429 |
|
|
"The number of sectors per cylinder (Usually sectors/track " |
1430 |
|
|
"* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl, |
1431 |
|
|
0, 0); |
1432 |
|
|
if (ui == ULLONG_MAX - 1) { |
1433 |
|
|
fputs("Command aborted\n", stderr); |
1434 |
|
|
*lp = oldlabel; /* undo damage */ |
1435 |
|
|
return; |
1436 |
|
|
} else if (ui == ULLONG_MAX) |
1437 |
|
|
fputs("Invalid entry\n", stderr); |
1438 |
|
|
else |
1439 |
|
|
break; |
1440 |
|
|
} |
1441 |
|
|
lp->d_secpercyl = ui; |
1442 |
|
|
|
1443 |
|
|
/* number of cylinders */ |
1444 |
|
|
for (;;) { |
1445 |
|
|
ui = getuint64(lp, "number of cylinders", |
1446 |
|
|
"The total number of cylinders on the disk.", |
1447 |
|
|
lp->d_ncylinders, lp->d_ncylinders, 0, 0); |
1448 |
|
|
if (ui == ULLONG_MAX - 1) { |
1449 |
|
|
fputs("Command aborted\n", stderr); |
1450 |
|
|
*lp = oldlabel; /* undo damage */ |
1451 |
|
|
return; |
1452 |
|
|
} else if (ui == ULLONG_MAX) |
1453 |
|
|
fputs("Invalid entry\n", stderr); |
1454 |
|
|
else |
1455 |
|
|
break; |
1456 |
|
|
} |
1457 |
|
|
lp->d_ncylinders = ui; |
1458 |
|
|
|
1459 |
|
|
/* total sectors */ |
1460 |
|
|
for (;;) { |
1461 |
|
|
u_int64_t nsec = MAXIMUM(DL_GETDSIZE(lp), |
1462 |
|
|
(u_int64_t)lp->d_ncylinders * lp->d_secpercyl); |
1463 |
|
|
ui = getuint64(lp, "total sectors", |
1464 |
|
|
"The total number of sectors on the disk.", |
1465 |
|
|
nsec, nsec, 0, 0); |
1466 |
|
|
if (ui == ULLONG_MAX - 1) { |
1467 |
|
|
fputs("Command aborted\n", stderr); |
1468 |
|
|
*lp = oldlabel; /* undo damage */ |
1469 |
|
|
return; |
1470 |
|
|
} else if (ui == ULLONG_MAX) |
1471 |
|
|
fputs("Invalid entry\n", stderr); |
1472 |
|
|
else if (ui > DL_GETDSIZE(lp) && |
1473 |
|
|
ending_sector == DL_GETDSIZE(lp)) { |
1474 |
|
|
puts("You may want to increase the size of the 'c' " |
1475 |
|
|
"partition."); |
1476 |
|
|
break; |
1477 |
|
|
} else if (ui < DL_GETDSIZE(lp) && |
1478 |
|
|
ending_sector == DL_GETDSIZE(lp)) { |
1479 |
|
|
/* shrink free count */ |
1480 |
|
|
freesectors = editor_countfree(lp); |
1481 |
|
|
if (DL_GETDSIZE(lp) - ui > freesectors) |
1482 |
|
|
fprintf(stderr, |
1483 |
|
|
"Not enough free space to shrink by %llu " |
1484 |
|
|
"sectors (only %llu sectors left)\n", |
1485 |
|
|
DL_GETDSIZE(lp) - ui, freesectors); |
1486 |
|
|
else |
1487 |
|
|
break; |
1488 |
|
|
} else |
1489 |
|
|
break; |
1490 |
|
|
} |
1491 |
|
|
/* Adjust ending_sector if necessary. */ |
1492 |
|
|
if (ending_sector > ui) { |
1493 |
|
|
ending_sector = ui; |
1494 |
|
|
DL_SETBEND(lp, ending_sector); |
1495 |
|
|
} |
1496 |
|
|
DL_SETDSIZE(lp, ui); |
1497 |
|
|
} |
1498 |
|
|
|
1499 |
|
|
struct partition ** |
1500 |
|
|
sort_partitions(struct disklabel *lp) |
1501 |
|
|
{ |
1502 |
|
|
static struct partition *spp[MAXPARTITIONS+2]; |
1503 |
|
|
int i, npartitions; |
1504 |
|
|
|
1505 |
|
|
memset(spp, 0, sizeof(spp)); |
1506 |
|
|
|
1507 |
|
|
for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { |
1508 |
|
|
if (lp->d_partitions[i].p_fstype != FS_UNUSED && |
1509 |
|
|
lp->d_partitions[i].p_fstype != FS_BOOT && |
1510 |
|
|
DL_GETPSIZE(&lp->d_partitions[i]) != 0) |
1511 |
|
|
spp[npartitions++] = &lp->d_partitions[i]; |
1512 |
|
|
} |
1513 |
|
|
|
1514 |
|
|
/* |
1515 |
|
|
* Sort the partitions based on starting offset. |
1516 |
|
|
* This is safe because we guarantee no overlap. |
1517 |
|
|
*/ |
1518 |
|
|
if (npartitions > 1) |
1519 |
|
|
if (heapsort((void *)spp, npartitions, sizeof(spp[0]), |
1520 |
|
|
partition_cmp)) |
1521 |
|
|
err(4, "failed to sort partition table"); |
1522 |
|
|
|
1523 |
|
|
return(spp); |
1524 |
|
|
} |
1525 |
|
|
|
1526 |
|
|
/* |
1527 |
|
|
* Get a valid disk type if necessary. |
1528 |
|
|
*/ |
1529 |
|
|
void |
1530 |
|
|
getdisktype(struct disklabel *lp, char *banner, char *dev) |
1531 |
|
|
{ |
1532 |
|
|
int i; |
1533 |
|
|
char *s; |
1534 |
|
|
const char *def = "SCSI"; |
1535 |
|
|
const struct dtypes { |
1536 |
|
|
const char *dev; |
1537 |
|
|
const char *type; |
1538 |
|
|
} dtypes[] = { |
1539 |
|
|
{ "sd", "SCSI" }, |
1540 |
|
|
{ "wd", "IDE" }, |
1541 |
|
|
{ "fd", "FLOPPY" }, |
1542 |
|
|
{ "xd", "SMD" }, |
1543 |
|
|
{ "xy", "SMD" }, |
1544 |
|
|
{ "hd", "HP-IB" }, |
1545 |
|
|
{ "vnd", "VND" }, |
1546 |
|
|
{ "svnd", "VND" }, |
1547 |
|
|
{ NULL, NULL } |
1548 |
|
|
}; |
1549 |
|
|
|
1550 |
|
|
if ((s = basename(dev)) != NULL) { |
1551 |
|
|
if (*s == 'r') |
1552 |
|
|
s++; |
1553 |
|
|
i = strcspn(s, "0123456789"); |
1554 |
|
|
s[i] = '\0'; |
1555 |
|
|
dev = s; |
1556 |
|
|
for (i = 0; dtypes[i].dev != NULL; i++) { |
1557 |
|
|
if (strcmp(dev, dtypes[i].dev) == 0) { |
1558 |
|
|
def = dtypes[i].type; |
1559 |
|
|
break; |
1560 |
|
|
} |
1561 |
|
|
} |
1562 |
|
|
} |
1563 |
|
|
|
1564 |
|
|
if (lp->d_type > DKMAXTYPES || lp->d_type == 0) { |
1565 |
|
|
puts(banner); |
1566 |
|
|
puts("Possible values are:"); |
1567 |
|
|
printf("\"IDE\", "); |
1568 |
|
|
for (i = 1; i < DKMAXTYPES; i++) { |
1569 |
|
|
printf("\"%s\"", dktypenames[i]); |
1570 |
|
|
if (i < DKMAXTYPES - 1) |
1571 |
|
|
fputs(", ", stdout); |
1572 |
|
|
} |
1573 |
|
|
putchar('\n'); |
1574 |
|
|
|
1575 |
|
|
for (;;) { |
1576 |
|
|
s = getstring("Disk type", |
1577 |
|
|
"What kind of disk is this? Usually SCSI, IDE, " |
1578 |
|
|
"ESDI, ST506, or floppy.", def); |
1579 |
|
|
if (s == NULL) |
1580 |
|
|
continue; |
1581 |
|
|
if (strcasecmp(s, "IDE") == 0) { |
1582 |
|
|
lp->d_type = DTYPE_ESDI; |
1583 |
|
|
return; |
1584 |
|
|
} |
1585 |
|
|
for (i = 1; i < DKMAXTYPES; i++) |
1586 |
|
|
if (strcasecmp(s, dktypenames[i]) == 0) { |
1587 |
|
|
lp->d_type = i; |
1588 |
|
|
return; |
1589 |
|
|
} |
1590 |
|
|
printf("\"%s\" is not a valid disk type.\n", s); |
1591 |
|
|
fputs("Valid types are: ", stdout); |
1592 |
|
|
for (i = 1; i < DKMAXTYPES; i++) { |
1593 |
|
|
printf("\"%s\"", dktypenames[i]); |
1594 |
|
|
if (i < DKMAXTYPES - 1) |
1595 |
|
|
fputs(", ", stdout); |
1596 |
|
|
} |
1597 |
|
|
putchar('\n'); |
1598 |
|
|
} |
1599 |
|
|
} |
1600 |
|
|
} |
1601 |
|
|
|
1602 |
|
|
/* |
1603 |
|
|
* Get beginning and ending sectors of the OpenBSD portion of the disk |
1604 |
|
|
* from the user. |
1605 |
|
|
*/ |
1606 |
|
|
void |
1607 |
|
|
set_bounds(struct disklabel *lp) |
1608 |
|
|
{ |
1609 |
|
|
u_int64_t ui, start_temp; |
1610 |
|
|
|
1611 |
|
|
/* Starting sector */ |
1612 |
|
|
do { |
1613 |
|
|
ui = getuint64(lp, "Starting sector", |
1614 |
|
|
"The start of the OpenBSD portion of the disk.", |
1615 |
|
|
starting_sector, DL_GETDSIZE(lp), 0, 0); |
1616 |
|
|
if (ui == ULLONG_MAX - 1) { |
1617 |
|
|
fputs("Command aborted\n", stderr); |
1618 |
|
|
return; |
1619 |
|
|
} |
1620 |
|
|
} while (ui >= DL_GETDSIZE(lp)); |
1621 |
|
|
start_temp = ui; |
1622 |
|
|
|
1623 |
|
|
/* Size */ |
1624 |
|
|
do { |
1625 |
|
|
ui = getuint64(lp, "Size ('*' for entire disk)", |
1626 |
|
|
"The size of the OpenBSD portion of the disk ('*' for the " |
1627 |
|
|
"entire disk).", ending_sector - starting_sector, |
1628 |
|
|
DL_GETDSIZE(lp) - start_temp, 0, 0); |
1629 |
|
|
if (ui == ULLONG_MAX - 1) { |
1630 |
|
|
fputs("Command aborted\n", stderr); |
1631 |
|
|
return; |
1632 |
|
|
} |
1633 |
|
|
} while (ui > DL_GETDSIZE(lp) - start_temp); |
1634 |
|
|
ending_sector = start_temp + ui; |
1635 |
|
|
DL_SETBEND(lp, ending_sector); |
1636 |
|
|
starting_sector = start_temp; |
1637 |
|
|
DL_SETBSTART(lp, starting_sector); |
1638 |
|
|
} |
1639 |
|
|
|
1640 |
|
|
/* |
1641 |
|
|
* Allow user to interactively change disklabel UID. |
1642 |
|
|
*/ |
1643 |
|
|
void |
1644 |
|
|
set_duid(struct disklabel *lp) |
1645 |
|
|
{ |
1646 |
|
|
char *s; |
1647 |
|
|
int i; |
1648 |
|
|
|
1649 |
|
|
printf("The disklabel UID is currently: " |
1650 |
|
|
"%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n", |
1651 |
|
|
lp->d_uid[0], lp->d_uid[1], lp->d_uid[2], lp->d_uid[3], |
1652 |
|
|
lp->d_uid[4], lp->d_uid[5], lp->d_uid[6], lp->d_uid[7]); |
1653 |
|
|
|
1654 |
|
|
do { |
1655 |
|
|
s = getstring("duid", "The disklabel UID, given as a 16 " |
1656 |
|
|
"character hexadecimal string.", NULL); |
1657 |
|
|
if (s == NULL || strlen(s) == 0) { |
1658 |
|
|
fputs("Command aborted\n", stderr); |
1659 |
|
|
return; |
1660 |
|
|
} |
1661 |
|
|
i = duid_parse(lp, s); |
1662 |
|
|
if (i != 0) |
1663 |
|
|
fputs("Invalid UID entered.\n", stderr); |
1664 |
|
|
} while (i != 0); |
1665 |
|
|
} |
1666 |
|
|
|
1667 |
|
|
/* |
1668 |
|
|
* Return a list of the "chunks" of free space available |
1669 |
|
|
*/ |
1670 |
|
|
struct diskchunk * |
1671 |
|
|
free_chunks(struct disklabel *lp) |
1672 |
|
|
{ |
1673 |
|
|
struct partition **spp; |
1674 |
|
|
static struct diskchunk chunks[MAXPARTITIONS + 2]; |
1675 |
|
|
u_int64_t start, stop; |
1676 |
|
|
int i, numchunks; |
1677 |
|
|
|
1678 |
|
|
/* Sort the in-use partitions based on offset */ |
1679 |
|
|
spp = sort_partitions(lp); |
1680 |
|
|
|
1681 |
|
|
/* If there are no partitions, it's all free. */ |
1682 |
|
|
if (spp[0] == NULL) { |
1683 |
|
|
chunks[0].start = starting_sector; |
1684 |
|
|
chunks[0].stop = ending_sector; |
1685 |
|
|
chunks[1].start = chunks[1].stop = 0; |
1686 |
|
|
return(chunks); |
1687 |
|
|
} |
1688 |
|
|
|
1689 |
|
|
/* Find chunks of free space */ |
1690 |
|
|
numchunks = 0; |
1691 |
|
|
if (DL_GETPOFFSET(spp[0]) > starting_sector) { |
1692 |
|
|
chunks[0].start = starting_sector; |
1693 |
|
|
chunks[0].stop = DL_GETPOFFSET(spp[0]); |
1694 |
|
|
numchunks++; |
1695 |
|
|
} |
1696 |
|
|
for (i = 0; spp[i] != NULL; i++) { |
1697 |
|
|
start = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]); |
1698 |
|
|
if (start < starting_sector) |
1699 |
|
|
start = starting_sector; |
1700 |
|
|
else if (start > ending_sector) |
1701 |
|
|
start = ending_sector; |
1702 |
|
|
if (spp[i + 1] != NULL) |
1703 |
|
|
stop = DL_GETPOFFSET(spp[i+1]); |
1704 |
|
|
else |
1705 |
|
|
stop = ending_sector; |
1706 |
|
|
if (stop < starting_sector) |
1707 |
|
|
stop = starting_sector; |
1708 |
|
|
else if (stop > ending_sector) |
1709 |
|
|
stop = ending_sector; |
1710 |
|
|
if (start < stop) { |
1711 |
|
|
chunks[numchunks].start = start; |
1712 |
|
|
chunks[numchunks].stop = stop; |
1713 |
|
|
numchunks++; |
1714 |
|
|
} |
1715 |
|
|
} |
1716 |
|
|
|
1717 |
|
|
/* Terminate and return */ |
1718 |
|
|
chunks[numchunks].start = chunks[numchunks].stop = 0; |
1719 |
|
|
return(chunks); |
1720 |
|
|
} |
1721 |
|
|
|
1722 |
|
|
void |
1723 |
|
|
find_bounds(struct disklabel *lp) |
1724 |
|
|
{ |
1725 |
|
|
starting_sector = DL_GETBSTART(lp); |
1726 |
|
|
ending_sector = DL_GETBEND(lp); |
1727 |
|
|
|
1728 |
|
|
if (ending_sector) { |
1729 |
|
|
if (verbose) |
1730 |
|
|
printf("Treating sectors %llu-%llu as the OpenBSD" |
1731 |
|
|
" portion of the disk.\nYou can use the 'b'" |
1732 |
|
|
" command to change this.\n\n", starting_sector, |
1733 |
|
|
ending_sector); |
1734 |
|
|
} |
1735 |
|
|
} |
1736 |
|
|
|
1737 |
|
|
/* |
1738 |
|
|
* Calculate free space. |
1739 |
|
|
*/ |
1740 |
|
|
u_int64_t |
1741 |
|
|
editor_countfree(struct disklabel *lp) |
1742 |
|
|
{ |
1743 |
|
|
struct diskchunk *chunks; |
1744 |
|
|
u_int64_t freesectors = 0; |
1745 |
|
|
int i; |
1746 |
|
|
|
1747 |
|
|
chunks = free_chunks(lp); |
1748 |
|
|
|
1749 |
|
|
for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) |
1750 |
|
|
freesectors += chunks[i].stop - chunks[i].start; |
1751 |
|
|
|
1752 |
|
|
return (freesectors); |
1753 |
|
|
} |
1754 |
|
|
|
1755 |
|
|
void |
1756 |
|
|
editor_help(void) |
1757 |
|
|
{ |
1758 |
|
|
puts("Available commands:"); |
1759 |
|
|
puts( |
1760 |
|
|
" ? | h - show help n [part] - set mount point\n" |
1761 |
|
|
" A - auto partition all space p [unit] - print partitions\n" |
1762 |
|
|
" a [part] - add partition q - quit & save changes\n" |
1763 |
|
|
" b - set OpenBSD boundaries R [part] - resize auto allocated partition\n" |
1764 |
|
|
" c [part] - change partition size r - display free space\n" |
1765 |
|
|
" D - reset label to default s [path] - save label to file\n" |
1766 |
|
|
" d [part] - delete partition U - undo all changes\n" |
1767 |
|
|
" e - edit drive parameters u - undo last change\n" |
1768 |
|
|
" g [d|u] - [d]isk or [u]ser geometry w - write label to disk\n" |
1769 |
|
|
" i - modify disklabel UID X - toggle expert mode\n" |
1770 |
|
|
" l [unit] - print disk label header x - exit & lose changes\n" |
1771 |
|
|
" M - disklabel(8) man page z - delete all partitions\n" |
1772 |
|
|
" m [part] - modify partition\n" |
1773 |
|
|
"\n" |
1774 |
|
|
"Suffixes can be used to indicate units other than sectors:\n" |
1775 |
|
|
" 'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes) 't' (terabytes)\n" |
1776 |
|
|
" 'c' (cylinders), '%' (% of total disk), '&' (% of free space).\n" |
1777 |
|
|
"Values in non-sector units are truncated to the nearest cylinder boundary."); |
1778 |
|
|
|
1779 |
|
|
} |
1780 |
|
|
|
1781 |
|
|
void |
1782 |
|
|
mpcopy(char **to, char **from) |
1783 |
|
|
{ |
1784 |
|
|
int i; |
1785 |
|
|
|
1786 |
|
|
for (i = 0; i < MAXPARTITIONS; i++) { |
1787 |
|
|
free(to[i]); |
1788 |
|
|
to[i] = NULL; |
1789 |
|
|
if (from[i] != NULL) { |
1790 |
|
|
to[i] = strdup(from[i]); |
1791 |
|
|
if (to[i] == NULL) |
1792 |
|
|
errx(4, "out of memory"); |
1793 |
|
|
} |
1794 |
|
|
} |
1795 |
|
|
} |
1796 |
|
|
|
1797 |
|
|
int |
1798 |
|
|
mpequal(char **mp1, char **mp2) |
1799 |
|
|
{ |
1800 |
|
|
int i; |
1801 |
|
|
|
1802 |
|
|
for (i = 0; i < MAXPARTITIONS; i++) { |
1803 |
|
|
if (mp1[i] == NULL && mp2[i] == NULL) |
1804 |
|
|
continue; |
1805 |
|
|
|
1806 |
|
|
if ((mp1[i] != NULL && mp2[i] == NULL) || |
1807 |
|
|
(mp1[i] == NULL && mp2[i] != NULL) || |
1808 |
|
|
(strcmp(mp1[i], mp2[i]) != 0)) |
1809 |
|
|
return(0); |
1810 |
|
|
} |
1811 |
|
|
return(1); |
1812 |
|
|
} |
1813 |
|
|
|
1814 |
|
|
void |
1815 |
|
|
mpsave(struct disklabel *lp) |
1816 |
|
|
{ |
1817 |
|
|
int i, j; |
1818 |
|
|
char bdev[PATH_MAX], *p; |
1819 |
|
|
struct mountinfo mi[MAXPARTITIONS]; |
1820 |
|
|
FILE *fp; |
1821 |
|
|
u_int8_t fstype; |
1822 |
|
|
|
1823 |
|
|
if (!fstabfile) |
1824 |
|
|
return; |
1825 |
|
|
|
1826 |
|
|
memset(&mi, 0, sizeof(mi)); |
1827 |
|
|
|
1828 |
|
|
for (i = 0; i < MAXPARTITIONS; i++) { |
1829 |
|
|
fstype = lp->d_partitions[i].p_fstype; |
1830 |
|
|
if (mountpoints[i] != NULL || fstype == FS_SWAP) { |
1831 |
|
|
mi[i].mountpoint = mountpoints[i]; |
1832 |
|
|
mi[i].partno = i; |
1833 |
|
|
} |
1834 |
|
|
} |
1835 |
|
|
|
1836 |
|
|
/* Convert specname to bdev */ |
1837 |
|
|
if (uidflag) { |
1838 |
|
|
snprintf(bdev, sizeof(bdev), |
1839 |
|
|
"%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", |
1840 |
|
|
lab.d_uid[0], lab.d_uid[1], lab.d_uid[2], lab.d_uid[3], |
1841 |
|
|
lab.d_uid[4], lab.d_uid[5], lab.d_uid[6], lab.d_uid[7], |
1842 |
|
|
specname[strlen(specname)-1]); |
1843 |
|
|
} else if (strncmp(_PATH_DEV, specname, sizeof(_PATH_DEV) - 1) == 0 && |
1844 |
|
|
specname[sizeof(_PATH_DEV) - 1] == 'r') { |
1845 |
|
|
snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV, |
1846 |
|
|
&specname[sizeof(_PATH_DEV)]); |
1847 |
|
|
} else { |
1848 |
|
|
if ((p = strrchr(specname, '/')) == NULL || *(++p) != 'r') |
1849 |
|
|
return; |
1850 |
|
|
*p = '\0'; |
1851 |
|
|
snprintf(bdev, sizeof(bdev), "%s%s", specname, p + 1); |
1852 |
|
|
*p = 'r'; |
1853 |
|
|
} |
1854 |
|
|
bdev[strlen(bdev) - 1] = '\0'; |
1855 |
|
|
|
1856 |
|
|
/* Sort mountpoints so we don't try to mount /usr/local before /usr */ |
1857 |
|
|
qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp); |
1858 |
|
|
|
1859 |
|
|
if ((fp = fopen(fstabfile, "w"))) { |
1860 |
|
|
for (i = 0; i < MAXPARTITIONS; i++) { |
1861 |
|
|
j = mi[i].partno; |
1862 |
|
|
fstype = lp->d_partitions[j].p_fstype; |
1863 |
|
|
if (fstype == FS_SWAP) { |
1864 |
|
|
fprintf(fp, "%s%c none swap sw\n", bdev, 'a'+j); |
1865 |
|
|
} else if (mi[i].mountpoint) { |
1866 |
|
|
fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, |
1867 |
|
|
'a' + j, mi[i].mountpoint, |
1868 |
|
|
fstypesnames[fstype], j == 0 ? 1 : 2); |
1869 |
|
|
} |
1870 |
|
|
} |
1871 |
|
|
fclose(fp); |
1872 |
|
|
} |
1873 |
|
|
} |
1874 |
|
|
|
1875 |
|
|
void |
1876 |
|
|
mpfree(char **mp) |
1877 |
|
|
{ |
1878 |
|
|
int part; |
1879 |
|
|
|
1880 |
|
|
if (mp == NULL) |
1881 |
|
|
return; |
1882 |
|
|
|
1883 |
|
|
for (part = 0; part < MAXPARTITIONS; part++) |
1884 |
|
|
free(mp[part]); |
1885 |
|
|
|
1886 |
|
|
free(mp); |
1887 |
|
|
} |
1888 |
|
|
|
1889 |
|
|
int |
1890 |
|
|
get_offset(struct disklabel *lp, int partno) |
1891 |
|
|
{ |
1892 |
|
|
struct diskchunk *chunks; |
1893 |
|
|
struct partition *pp = &lp->d_partitions[partno]; |
1894 |
|
|
u_int64_t ui, maxsize; |
1895 |
|
|
int i, fstype; |
1896 |
|
|
|
1897 |
|
|
ui = getuint64(lp, "offset", |
1898 |
|
|
"Starting sector for this partition.", |
1899 |
|
|
DL_GETPOFFSET(pp), |
1900 |
|
|
DL_GETPOFFSET(pp), 0, DO_CONVERSIONS | |
1901 |
|
|
(pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); |
1902 |
|
|
|
1903 |
|
|
if (ui == ULLONG_MAX - 1) |
1904 |
|
|
fputs("Command aborted\n", stderr); |
1905 |
|
|
else if (ui == ULLONG_MAX) |
1906 |
|
|
fputs("Invalid entry\n", stderr); |
1907 |
|
|
else if (ui < starting_sector || ui >= ending_sector) |
1908 |
|
|
fprintf(stderr, "The offset must be >= %llu and < %llu, " |
1909 |
|
|
"the limits of the OpenBSD portion\n" |
1910 |
|
|
"of the disk. The 'b' command can change these limits.\n", |
1911 |
|
|
starting_sector, ending_sector); |
1912 |
|
|
#ifdef SUN_AAT0 |
1913 |
|
|
else if (partno == 0 && ui != 0) |
1914 |
|
|
fprintf(stderr, "This architecture requires that " |
1915 |
|
|
"partition 'a' start at sector 0.\n"); |
1916 |
|
|
#endif |
1917 |
|
|
else { |
1918 |
|
|
fstype = pp->p_fstype; |
1919 |
|
|
pp->p_fstype = FS_UNUSED; |
1920 |
|
|
chunks = free_chunks(lp); |
1921 |
|
|
pp->p_fstype = fstype; |
1922 |
|
|
for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { |
1923 |
|
|
if (ui < chunks[i].start || ui >= chunks[i].stop) |
1924 |
|
|
continue; |
1925 |
|
|
DL_SETPOFFSET(pp, ui); |
1926 |
|
|
maxsize = chunks[i].stop - DL_GETPOFFSET(pp); |
1927 |
|
|
if (DL_GETPSIZE(pp) > maxsize) |
1928 |
|
|
DL_SETPSIZE(pp, maxsize); |
1929 |
|
|
return (0); |
1930 |
|
|
} |
1931 |
|
|
fputs("The offset must be in a free area.\n", stderr); |
1932 |
|
|
} |
1933 |
|
|
|
1934 |
|
|
/* Partition offset was not set. */ |
1935 |
|
|
return (1); |
1936 |
|
|
} |
1937 |
|
|
|
1938 |
|
|
int |
1939 |
|
|
get_size(struct disklabel *lp, int partno) |
1940 |
|
|
{ |
1941 |
|
|
struct partition *pp = &lp->d_partitions[partno]; |
1942 |
|
|
u_int64_t maxsize, ui; |
1943 |
|
|
|
1944 |
|
|
maxsize = max_partition_size(lp, partno); |
1945 |
|
|
|
1946 |
|
|
ui = getuint64(lp, "size", "Size of the partition. " |
1947 |
|
|
"You may also say +/- amount for a relative change.", |
1948 |
|
|
DL_GETPSIZE(pp), maxsize, DL_GETPOFFSET(pp), |
1949 |
|
|
DO_CONVERSIONS | ((pp->p_fstype == FS_BSDFFS || |
1950 |
|
|
pp->p_fstype == FS_SWAP) ? DO_ROUNDING : 0)); |
1951 |
|
|
|
1952 |
|
|
if (ui == ULLONG_MAX - 1) |
1953 |
|
|
fputs("Command aborted\n", stderr); |
1954 |
|
|
else if (ui == ULLONG_MAX) |
1955 |
|
|
fputs("Invalid entry\n", stderr); |
1956 |
|
|
else if (ui == 0) |
1957 |
|
|
fputs("The size must be > 0 sectors\n", stderr); |
1958 |
|
|
else if (ui + DL_GETPOFFSET(pp) > ending_sector) |
1959 |
|
|
fprintf(stderr, "The size can't be more than " |
1960 |
|
|
"%llu sectors, or the partition would\n" |
1961 |
|
|
"extend beyond the last sector (%llu) of the " |
1962 |
|
|
"OpenBSD portion of\nthe disk. " |
1963 |
|
|
"The 'b' command can change this limit.\n", |
1964 |
|
|
ending_sector - DL_GETPOFFSET(pp), ending_sector); |
1965 |
|
|
else if (ui > maxsize) |
1966 |
|
|
fprintf(stderr,"Sorry, there are only %llu sectors left\n", |
1967 |
|
|
maxsize); |
1968 |
|
|
else { |
1969 |
|
|
DL_SETPSIZE(pp, ui); |
1970 |
|
|
return (0); |
1971 |
|
|
} |
1972 |
|
|
|
1973 |
|
|
/* Partition size was not set. */ |
1974 |
|
|
return (1); |
1975 |
|
|
} |
1976 |
|
|
|
1977 |
|
|
int |
1978 |
|
|
get_fsize(struct disklabel *lp, int partno) |
1979 |
|
|
{ |
1980 |
|
|
u_int64_t ui, fsize, frag; |
1981 |
|
|
struct partition *pp = &lp->d_partitions[partno]; |
1982 |
|
|
|
1983 |
|
|
if (!expert || pp->p_fstype != FS_BSDFFS) |
1984 |
|
|
return (0); |
1985 |
|
|
|
1986 |
|
|
fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); |
1987 |
|
|
frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); |
1988 |
|
|
if (fsize == 0) |
1989 |
|
|
frag = 8; |
1990 |
|
|
|
1991 |
|
|
for (;;) { |
1992 |
|
|
ui = getuint64(lp, "fragment size", |
1993 |
|
|
"Size of ffs block fragments. A multiple of the disk " |
1994 |
|
|
"sector-size.", fsize, ULLONG_MAX-2, 0, 0); |
1995 |
|
|
if (ui == ULLONG_MAX - 1) { |
1996 |
|
|
fputs("Command aborted\n", stderr); |
1997 |
|
|
return (1); |
1998 |
|
|
} else if (ui == ULLONG_MAX) { |
1999 |
|
|
fputs("Invalid entry\n", stderr); |
2000 |
|
|
} else if (ui < lp->d_secsize || (ui % lp->d_secsize) != 0) { |
2001 |
|
|
fprintf(stderr, "Error: fragment size must be a " |
2002 |
|
|
"multiple of the disk sector size (%d)\n", |
2003 |
|
|
lp->d_secsize); |
2004 |
|
|
} else |
2005 |
|
|
break; |
2006 |
|
|
} |
2007 |
|
|
if (ui == 0) |
2008 |
|
|
puts("Zero fragment size implies zero block size"); |
2009 |
|
|
pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui, frag); |
2010 |
|
|
return(0); |
2011 |
|
|
} |
2012 |
|
|
|
2013 |
|
|
int |
2014 |
|
|
get_bsize(struct disklabel *lp, int partno) |
2015 |
|
|
{ |
2016 |
|
|
u_int64_t adj, ui, bsize, frag, fsize, orig_offset, orig_size; |
2017 |
|
|
struct partition *pp = &lp->d_partitions[partno]; |
2018 |
|
|
char *p; |
2019 |
|
|
|
2020 |
|
|
if (pp->p_fstype != FS_BSDFFS) |
2021 |
|
|
return (0); |
2022 |
|
|
|
2023 |
|
|
/* Avoid dividing by zero... */ |
2024 |
|
|
if (pp->p_fragblock == 0) |
2025 |
|
|
return(1); |
2026 |
|
|
|
2027 |
|
|
if (!expert) |
2028 |
|
|
goto align; |
2029 |
|
|
|
2030 |
|
|
fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); |
2031 |
|
|
frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); |
2032 |
|
|
|
2033 |
|
|
for (;;) { |
2034 |
|
|
ui = getuint64(lp, "block size", |
2035 |
|
|
"Size of ffs blocks. 1, 2, 4 or 8 times ffs fragment size.", |
2036 |
|
|
fsize * frag, ULLONG_MAX - 2, 0, 0); |
2037 |
|
|
|
2038 |
|
|
/* sanity checks */ |
2039 |
|
|
if (ui == ULLONG_MAX - 1) { |
2040 |
|
|
fputs("Command aborted\n", stderr); |
2041 |
|
|
return(1); |
2042 |
|
|
} else if (ui == ULLONG_MAX) |
2043 |
|
|
fputs("Invalid entry\n", stderr); |
2044 |
|
|
else if (ui < getpagesize()) |
2045 |
|
|
fprintf(stderr, |
2046 |
|
|
"Error: block size must be at least as big " |
2047 |
|
|
"as page size (%d).\n", getpagesize()); |
2048 |
|
|
else if (ui < fsize || (fsize != ui && fsize * 2 != ui && |
2049 |
|
|
fsize * 4 != ui && fsize * 8 != ui)) |
2050 |
|
|
fprintf(stderr, "Error: block size must be 1, 2, 4 or " |
2051 |
|
|
"8 times fragment size (%llu).\n", |
2052 |
|
|
(unsigned long long) fsize); |
2053 |
|
|
else |
2054 |
|
|
break; |
2055 |
|
|
} |
2056 |
|
|
frag = ui / fsize; |
2057 |
|
|
pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fsize, frag); |
2058 |
|
|
|
2059 |
|
|
#ifndef SUN_CYLCHECK |
2060 |
|
|
p = getstring("Align partition to block size", |
2061 |
|
|
"Round the partition offset and size to multiples of bsize?", "y"); |
2062 |
|
|
|
2063 |
|
|
if (*p == 'n' || *p == 'N') |
2064 |
|
|
return (0); |
2065 |
|
|
#endif |
2066 |
|
|
|
2067 |
|
|
align: |
2068 |
|
|
|
2069 |
|
|
#ifndef SUN_CYLCHECK |
2070 |
|
|
orig_size = DL_GETPSIZE(pp); |
2071 |
|
|
orig_offset = DL_GETPOFFSET(pp); |
2072 |
|
|
|
2073 |
|
|
bsize = (DISKLABELV1_FFS_FRAG(pp->p_fragblock) * |
2074 |
|
|
DISKLABELV1_FFS_FSIZE(pp->p_fragblock)) / lp->d_secsize; |
2075 |
|
|
if (DL_GETPOFFSET(pp) != starting_sector) { |
2076 |
|
|
/* Can't change offset of first partition. */ |
2077 |
|
|
adj = bsize - (DL_GETPOFFSET(pp) % bsize); |
2078 |
|
|
if (adj != 0 && adj != bsize) { |
2079 |
|
|
DL_SETPOFFSET(pp, DL_GETPOFFSET(pp) + adj); |
2080 |
|
|
DL_SETPSIZE(pp, DL_GETPSIZE(pp) - adj); |
2081 |
|
|
} |
2082 |
|
|
} |
2083 |
|
|
/* Always align end. */ |
2084 |
|
|
adj = (DL_GETPOFFSET(pp) + DL_GETPSIZE(pp)) % bsize; |
2085 |
|
|
if (adj > 0) |
2086 |
|
|
DL_SETPSIZE(pp, DL_GETPSIZE(pp) - adj); |
2087 |
|
|
|
2088 |
|
|
if (orig_offset != DL_GETPOFFSET(pp) && !aflag) |
2089 |
|
|
printf("Rounding offset to bsize (%llu sectors): %llu\n", |
2090 |
|
|
bsize, DL_GETPOFFSET(pp)); |
2091 |
|
|
if (orig_size != DL_GETPSIZE(pp) && !aflag) |
2092 |
|
|
printf("Rounding size to bsize (%llu sectors): %llu\n", |
2093 |
|
|
bsize, DL_GETPSIZE(pp)); |
2094 |
|
|
#endif |
2095 |
|
|
return(0); |
2096 |
|
|
} |
2097 |
|
|
|
2098 |
|
|
int |
2099 |
|
|
get_fstype(struct disklabel *lp, int partno) |
2100 |
|
|
{ |
2101 |
|
|
char *p; |
2102 |
|
|
u_int64_t ui; |
2103 |
|
|
struct partition *pp = &lp->d_partitions[partno]; |
2104 |
|
|
|
2105 |
|
|
if (pp->p_fstype < FSMAXTYPES) { |
2106 |
|
|
p = getstring("FS type", |
2107 |
|
|
"Filesystem type (usually 4.2BSD or swap)", |
2108 |
|
|
fstypenames[pp->p_fstype]); |
2109 |
|
|
if (p == NULL) { |
2110 |
|
|
fputs("Command aborted\n", stderr); |
2111 |
|
|
return(1); |
2112 |
|
|
} |
2113 |
|
|
for (ui = 0; ui < FSMAXTYPES; ui++) { |
2114 |
|
|
if (!strcasecmp(p, fstypenames[ui])) { |
2115 |
|
|
pp->p_fstype = ui; |
2116 |
|
|
break; |
2117 |
|
|
} |
2118 |
|
|
} |
2119 |
|
|
if (ui >= FSMAXTYPES) { |
2120 |
|
|
printf("Unrecognized filesystem type '%s', treating " |
2121 |
|
|
"as 'unknown'\n", p); |
2122 |
|
|
pp->p_fstype = FS_OTHER; |
2123 |
|
|
} |
2124 |
|
|
} else { |
2125 |
|
|
for (;;) { |
2126 |
|
|
ui = getuint64(lp, "FS type (decimal)", |
2127 |
|
|
"Filesystem type as a decimal number; usually 7 " |
2128 |
|
|
"(4.2BSD) or 1 (swap).", |
2129 |
|
|
pp->p_fstype, pp->p_fstype, 0, 0); |
2130 |
|
|
if (ui == ULLONG_MAX - 1) { |
2131 |
|
|
fputs("Command aborted\n", stderr); |
2132 |
|
|
return(1); |
2133 |
|
|
} if (ui == ULLONG_MAX) |
2134 |
|
|
fputs("Invalid entry\n", stderr); |
2135 |
|
|
else |
2136 |
|
|
break; |
2137 |
|
|
} |
2138 |
|
|
pp->p_fstype = ui; |
2139 |
|
|
} |
2140 |
|
|
return(0); |
2141 |
|
|
} |
2142 |
|
|
|
2143 |
|
|
int |
2144 |
|
|
get_mp(struct disklabel *lp, int partno) |
2145 |
|
|
{ |
2146 |
|
|
struct partition *pp = &lp->d_partitions[partno]; |
2147 |
|
|
char *p; |
2148 |
|
|
int i; |
2149 |
|
|
|
2150 |
|
|
if (fstabfile && pp->p_fstype != FS_UNUSED && |
2151 |
|
|
pp->p_fstype != FS_SWAP && pp->p_fstype != FS_BOOT && |
2152 |
|
|
pp->p_fstype != FS_OTHER) { |
2153 |
|
|
for (;;) { |
2154 |
|
|
p = getstring("mount point", |
2155 |
|
|
"Where to mount this filesystem (ie: / /var /usr)", |
2156 |
|
|
mountpoints[partno] ? mountpoints[partno] : "none"); |
2157 |
|
|
if (p == NULL) { |
2158 |
|
|
fputs("Command aborted\n", stderr); |
2159 |
|
|
return(1); |
2160 |
|
|
} |
2161 |
|
|
if (strcasecmp(p, "none") == 0) { |
2162 |
|
|
free(mountpoints[partno]); |
2163 |
|
|
mountpoints[partno] = NULL; |
2164 |
|
|
break; |
2165 |
|
|
} |
2166 |
|
|
for (i = 0; i < MAXPARTITIONS; i++) |
2167 |
|
|
if (mountpoints[i] != NULL && i != partno && |
2168 |
|
|
strcmp(p, mountpoints[i]) == 0) |
2169 |
|
|
break; |
2170 |
|
|
if (i < MAXPARTITIONS) { |
2171 |
|
|
fprintf(stderr, "'%c' already being mounted at " |
2172 |
|
|
"'%s'\n", 'a'+i, p); |
2173 |
|
|
break; |
2174 |
|
|
} |
2175 |
|
|
if (*p == '/') { |
2176 |
|
|
/* XXX - might as well realloc */ |
2177 |
|
|
free(mountpoints[partno]); |
2178 |
|
|
if ((mountpoints[partno] = strdup(p)) == NULL) |
2179 |
|
|
errx(4, "out of memory"); |
2180 |
|
|
break; |
2181 |
|
|
} |
2182 |
|
|
fputs("Mount points must start with '/'\n", stderr); |
2183 |
|
|
} |
2184 |
|
|
} |
2185 |
|
|
return(0); |
2186 |
|
|
} |
2187 |
|
|
|
2188 |
|
|
int |
2189 |
|
|
micmp(const void *a1, const void *a2) |
2190 |
|
|
{ |
2191 |
|
|
struct mountinfo *mi1 = (struct mountinfo *)a1; |
2192 |
|
|
struct mountinfo *mi2 = (struct mountinfo *)a2; |
2193 |
|
|
|
2194 |
|
|
/* We want all the NULLs at the end... */ |
2195 |
|
|
if (mi1->mountpoint == NULL && mi2->mountpoint == NULL) |
2196 |
|
|
return(0); |
2197 |
|
|
else if (mi1->mountpoint == NULL) |
2198 |
|
|
return(1); |
2199 |
|
|
else if (mi2->mountpoint == NULL) |
2200 |
|
|
return(-1); |
2201 |
|
|
else |
2202 |
|
|
return(strcmp(mi1->mountpoint, mi2->mountpoint)); |
2203 |
|
|
} |
2204 |
|
|
|
2205 |
|
|
void |
2206 |
|
|
get_geometry(int f, struct disklabel **dgpp) |
2207 |
|
|
{ |
2208 |
|
|
struct stat st; |
2209 |
|
|
struct disklabel *disk_geop; |
2210 |
|
|
|
2211 |
|
|
if (fstat(f, &st) == -1) |
2212 |
|
|
err(4, "Can't stat device"); |
2213 |
|
|
|
2214 |
|
|
/* Get disk geometry */ |
2215 |
|
|
if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL) |
2216 |
|
|
errx(4, "out of memory"); |
2217 |
|
|
if (ioctl(f, DIOCGPDINFO, disk_geop) < 0) |
2218 |
|
|
err(4, "ioctl DIOCGPDINFO"); |
2219 |
|
|
*dgpp = disk_geop; |
2220 |
|
|
} |
2221 |
|
|
|
2222 |
|
|
void |
2223 |
|
|
set_geometry(struct disklabel *lp, struct disklabel *dgp, |
2224 |
|
|
struct disklabel *ugp, char *p) |
2225 |
|
|
{ |
2226 |
|
|
if (p == NULL) { |
2227 |
|
|
p = getstring("[d]isk or [u]ser geometry", |
2228 |
|
|
"Enter 'd' to use the geometry based on what the disk " |
2229 |
|
|
"itself thinks it is, or 'u' to use the geometry that " |
2230 |
|
|
"was found in the label.", |
2231 |
|
|
"d"); |
2232 |
|
|
} |
2233 |
|
|
if (p == NULL) { |
2234 |
|
|
fputs("Command aborted\n", stderr); |
2235 |
|
|
return; |
2236 |
|
|
} |
2237 |
|
|
switch (*p) { |
2238 |
|
|
case 'd': |
2239 |
|
|
case 'D': |
2240 |
|
|
if (dgp == NULL) |
2241 |
|
|
fputs("BIOS geometry not defined.\n", stderr); |
2242 |
|
|
else { |
2243 |
|
|
lp->d_secsize = dgp->d_secsize; |
2244 |
|
|
lp->d_nsectors = dgp->d_nsectors; |
2245 |
|
|
lp->d_ntracks = dgp->d_ntracks; |
2246 |
|
|
lp->d_ncylinders = dgp->d_ncylinders; |
2247 |
|
|
lp->d_secpercyl = dgp->d_secpercyl; |
2248 |
|
|
DL_SETDSIZE(lp, DL_GETDSIZE(dgp)); |
2249 |
|
|
} |
2250 |
|
|
break; |
2251 |
|
|
case 'u': |
2252 |
|
|
case 'U': |
2253 |
|
|
if (ugp == NULL) |
2254 |
|
|
fputs("BIOS geometry not defined.\n", stderr); |
2255 |
|
|
else { |
2256 |
|
|
lp->d_secsize = ugp->d_secsize; |
2257 |
|
|
lp->d_nsectors = ugp->d_nsectors; |
2258 |
|
|
lp->d_ntracks = ugp->d_ntracks; |
2259 |
|
|
lp->d_ncylinders = ugp->d_ncylinders; |
2260 |
|
|
lp->d_secpercyl = ugp->d_secpercyl; |
2261 |
|
|
DL_SETDSIZE(lp, DL_GETDSIZE(ugp)); |
2262 |
|
|
if (dgp != NULL && ugp->d_secsize == dgp->d_secsize && |
2263 |
|
|
ugp->d_nsectors == dgp->d_nsectors && |
2264 |
|
|
ugp->d_ntracks == dgp->d_ntracks && |
2265 |
|
|
ugp->d_ncylinders == dgp->d_ncylinders && |
2266 |
|
|
ugp->d_secpercyl == dgp->d_secpercyl && |
2267 |
|
|
DL_GETDSIZE(ugp) == DL_GETDSIZE(dgp)) |
2268 |
|
|
fputs("Note: user geometry is the same as disk " |
2269 |
|
|
"geometry.\n", stderr); |
2270 |
|
|
} |
2271 |
|
|
break; |
2272 |
|
|
default: |
2273 |
|
|
fputs("You must enter either 'd' or 'u'.\n", stderr); |
2274 |
|
|
break; |
2275 |
|
|
} |
2276 |
|
|
} |
2277 |
|
|
|
2278 |
|
|
void |
2279 |
|
|
zero_partitions(struct disklabel *lp) |
2280 |
|
|
{ |
2281 |
|
|
int i; |
2282 |
|
|
|
2283 |
|
|
for (i = 0; i < MAXPARTITIONS; i++) { |
2284 |
|
|
memset(&lp->d_partitions[i], 0, sizeof(struct partition)); |
2285 |
|
|
free(mountpoints[i]); |
2286 |
|
|
mountpoints[i] = NULL; |
2287 |
|
|
} |
2288 |
|
|
|
2289 |
|
|
DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp)); |
2290 |
|
|
} |
2291 |
|
|
|
2292 |
|
|
u_int64_t |
2293 |
|
|
max_partition_size(struct disklabel *lp, int partno) |
2294 |
|
|
{ |
2295 |
|
|
struct partition *pp = &lp->d_partitions[partno]; |
2296 |
|
|
struct diskchunk *chunks; |
2297 |
|
|
u_int64_t maxsize = 0, offset; |
2298 |
|
|
int fstype, i; |
2299 |
|
|
|
2300 |
|
|
fstype = pp->p_fstype; |
2301 |
|
|
pp->p_fstype = FS_UNUSED; |
2302 |
|
|
chunks = free_chunks(lp); |
2303 |
|
|
pp->p_fstype = fstype; |
2304 |
|
|
|
2305 |
|
|
offset = DL_GETPOFFSET(pp); |
2306 |
|
|
for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { |
2307 |
|
|
if (offset < chunks[i].start || offset >= chunks[i].stop) |
2308 |
|
|
continue; |
2309 |
|
|
maxsize = chunks[i].stop - offset; |
2310 |
|
|
break; |
2311 |
|
|
} |
2312 |
|
|
return (maxsize); |
2313 |
|
|
} |
2314 |
|
|
|
2315 |
|
|
void |
2316 |
|
|
psize(u_int64_t sz, char unit, struct disklabel *lp) |
2317 |
|
|
{ |
2318 |
|
|
double d = scale(sz, unit, lp); |
2319 |
|
|
if (d < 0) |
2320 |
|
|
printf("%llu", sz); |
2321 |
|
|
else |
2322 |
|
|
printf("%.*f%c", unit == 'B' ? 0 : 1, d, unit); |
2323 |
|
|
} |
2324 |
|
|
|
2325 |
|
|
void |
2326 |
|
|
display_edit(struct disklabel *lp, char unit, u_int64_t fr) |
2327 |
|
|
{ |
2328 |
|
|
int i; |
2329 |
|
|
|
2330 |
|
|
unit = canonical_unit(lp, unit); |
2331 |
|
|
|
2332 |
|
|
printf("OpenBSD area: "); |
2333 |
|
|
psize(starting_sector, 0, lp); |
2334 |
|
|
printf("-"); |
2335 |
|
|
psize(ending_sector, 0, lp); |
2336 |
|
|
printf("; size: "); |
2337 |
|
|
psize(ending_sector - starting_sector, unit, lp); |
2338 |
|
|
printf("; free: "); |
2339 |
|
|
psize(fr, unit, lp); |
2340 |
|
|
|
2341 |
|
|
printf("\n# %16.16s %16.16s fstype [fsize bsize cpg]\n", |
2342 |
|
|
"size", "offset"); |
2343 |
|
|
for (i = 0; i < lp->d_npartitions; i++) |
2344 |
|
|
display_partition(stdout, lp, i, unit); |
2345 |
|
|
} |
2346 |
|
|
|
2347 |
|
|
void |
2348 |
|
|
parse_autotable(char *filename) |
2349 |
|
|
{ |
2350 |
|
|
FILE *cfile; |
2351 |
|
|
size_t len; |
2352 |
|
|
char *buf, *t; |
2353 |
|
|
uint idx = 0, pctsum = 0; |
2354 |
|
|
struct space_allocation *sa; |
2355 |
|
|
|
2356 |
|
|
if ((cfile = fopen(filename, "r")) == NULL) |
2357 |
|
|
err(1, "%s", filename); |
2358 |
|
|
if ((alloc_table = calloc(1, sizeof(struct alloc_table))) == NULL) |
2359 |
|
|
err(1, NULL); |
2360 |
|
|
alloc_table_nitems = 1; |
2361 |
|
|
|
2362 |
|
|
while ((buf = fgetln(cfile, &len)) != NULL) { |
2363 |
|
|
if ((alloc_table[0].table = reallocarray(alloc_table[0].table, |
2364 |
|
|
idx + 1, sizeof(*sa))) == NULL) |
2365 |
|
|
err(1, NULL); |
2366 |
|
|
sa = &(alloc_table[0].table[idx]); |
2367 |
|
|
idx++; |
2368 |
|
|
|
2369 |
|
|
if ((sa->mp = get_token(&buf, &len)) == NULL || |
2370 |
|
|
(sa->mp[0] != '/' && strcmp(sa->mp, "swap"))) |
2371 |
|
|
errx(1, "%s: parse error on line %u", filename, idx); |
2372 |
|
|
if ((t = get_token(&buf, &len)) == NULL || |
2373 |
|
|
parse_sizerange(t, &sa->minsz, &sa->maxsz) == -1) |
2374 |
|
|
errx(1, "%s: parse error on line %u", filename, idx); |
2375 |
|
|
if ((t = get_token(&buf, &len)) != NULL && |
2376 |
|
|
parse_pct(t, &sa->rate) == -1) |
2377 |
|
|
errx(1, "%s: parse error on line %u", filename, idx); |
2378 |
|
|
if (sa->minsz > sa->maxsz) |
2379 |
|
|
errx(1, "%s: min size > max size on line %u", filename, |
2380 |
|
|
idx); |
2381 |
|
|
pctsum += sa->rate; |
2382 |
|
|
} |
2383 |
|
|
if (pctsum > 100) |
2384 |
|
|
errx(1, "%s: sum of extra space allocation > 100%%", filename); |
2385 |
|
|
alloc_table[0].sz = idx; |
2386 |
|
|
fclose(cfile); |
2387 |
|
|
} |
2388 |
|
|
|
2389 |
|
|
char * |
2390 |
|
|
get_token(char **s, size_t *len) |
2391 |
|
|
{ |
2392 |
|
|
char *p, *r; |
2393 |
|
|
size_t tlen = 0; |
2394 |
|
|
|
2395 |
|
|
p = *s; |
2396 |
|
|
while (*len > 0 && !isspace((u_char)*s[0])) { |
2397 |
|
|
(*s)++; |
2398 |
|
|
(*len)--; |
2399 |
|
|
tlen++; |
2400 |
|
|
} |
2401 |
|
|
if (tlen == 0) |
2402 |
|
|
return (NULL); |
2403 |
|
|
|
2404 |
|
|
/* eat whitespace */ |
2405 |
|
|
while (*len > 0 && isspace((u_char)*s[0])) { |
2406 |
|
|
(*s)++; |
2407 |
|
|
(*len)--; |
2408 |
|
|
} |
2409 |
|
|
|
2410 |
|
|
if ((r = strndup(p, tlen)) == NULL) |
2411 |
|
|
err(1, NULL); |
2412 |
|
|
return (r); |
2413 |
|
|
} |
2414 |
|
|
|
2415 |
|
|
int |
2416 |
|
|
apply_unit(double val, u_char unit, u_int64_t *n) |
2417 |
|
|
{ |
2418 |
|
|
u_int64_t factor = 1; |
2419 |
|
|
|
2420 |
|
|
switch (tolower(unit)) { |
2421 |
|
|
case 't': |
2422 |
|
|
factor *= 1024; |
2423 |
|
|
/* FALLTHROUGH */ |
2424 |
|
|
case 'g': |
2425 |
|
|
factor *= 1024; |
2426 |
|
|
/* FALLTHROUGH */ |
2427 |
|
|
case 'm': |
2428 |
|
|
factor *= 1024; |
2429 |
|
|
/* FALLTHROUGH */ |
2430 |
|
|
case 'k': |
2431 |
|
|
factor *= 1024; |
2432 |
|
|
break; |
2433 |
|
|
default: |
2434 |
|
|
return (-1); |
2435 |
|
|
} |
2436 |
|
|
|
2437 |
|
|
val *= factor / DEV_BSIZE; |
2438 |
|
|
if (val > ULLONG_MAX) |
2439 |
|
|
return (-1); |
2440 |
|
|
*n = val; |
2441 |
|
|
return (0); |
2442 |
|
|
} |
2443 |
|
|
|
2444 |
|
|
int |
2445 |
|
|
parse_sizespec(const char *buf, double *val, char **unit) |
2446 |
|
|
{ |
2447 |
|
|
*val = strtod(buf, unit); |
2448 |
|
|
if ((*val == 0 && *unit == buf) || *val <= 0) |
2449 |
|
|
return (-1); |
2450 |
|
|
if (*unit != NULL && *unit[0] == '\0') |
2451 |
|
|
*unit = NULL; |
2452 |
|
|
return (0); |
2453 |
|
|
} |
2454 |
|
|
|
2455 |
|
|
int |
2456 |
|
|
parse_sizerange(char *buf, u_int64_t *min, u_int64_t *max) |
2457 |
|
|
{ |
2458 |
|
|
char *p, *unit1 = NULL, *unit2 = NULL; |
2459 |
|
|
double val1 = 0, val2 = 0; |
2460 |
|
|
|
2461 |
|
|
if ((p = strchr(buf, '-')) != NULL) { |
2462 |
|
|
p[0] = '\0'; |
2463 |
|
|
p++; |
2464 |
|
|
} |
2465 |
|
|
*max = 0; |
2466 |
|
|
if (parse_sizespec(buf, &val1, &unit1) == -1) |
2467 |
|
|
return (-1); |
2468 |
|
|
if (p != NULL && p[0] != '\0') { |
2469 |
|
|
if (p[0] == '*') |
2470 |
|
|
*max = -1; |
2471 |
|
|
else |
2472 |
|
|
if (parse_sizespec(p, &val2, &unit2) == -1) |
2473 |
|
|
return (-1); |
2474 |
|
|
} |
2475 |
|
|
if (unit1 == NULL && (unit1 = unit2) == NULL) |
2476 |
|
|
return (-1); |
2477 |
|
|
if (apply_unit(val1, unit1[0], min) == -1) |
2478 |
|
|
return (-1); |
2479 |
|
|
if (val2 > 0) { |
2480 |
|
|
if (apply_unit(val2, unit2[0], max) == -1) |
2481 |
|
|
return (-1); |
2482 |
|
|
} else |
2483 |
|
|
if (*max == 0) |
2484 |
|
|
*max = *min; |
2485 |
|
|
free(buf); |
2486 |
|
|
return (0); |
2487 |
|
|
} |
2488 |
|
|
|
2489 |
|
|
int |
2490 |
|
|
parse_pct(char *buf, int *n) |
2491 |
|
|
{ |
2492 |
|
|
const char *errstr; |
2493 |
|
|
|
2494 |
|
|
if (buf[strlen(buf) - 1] == '%') |
2495 |
|
|
buf[strlen(buf) - 1] = '\0'; |
2496 |
|
|
*n = strtonum(buf, 0, 100, &errstr); |
2497 |
|
|
if (errstr) { |
2498 |
|
|
warnx("parse percent %s: %s", buf, errstr); |
2499 |
|
|
return (-1); |
2500 |
|
|
} |
2501 |
|
|
free(buf); |
2502 |
|
|
return (0); |
2503 |
|
|
} |