Deleted Added
full compact
label.c (8681) label.c (8702)
1/*
2 * The new sysinstall program.
3 *
4 * This is probably the last program in the `sysinstall' line - the next
5 * generation being essentially a complete rewrite.
6 *
1/*
2 * The new sysinstall program.
3 *
4 * This is probably the last program in the `sysinstall' line - the next
5 * generation being essentially a complete rewrite.
6 *
7 * $Id: label.c,v 1.19 1995/05/21 17:53:27 jkh Exp $
7 * $Id: label.c,v 1.20 1995/05/21 18:24:33 jkh Exp $
8 *
9 * Copyright (c) 1995
10 * Jordan Hubbard. All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer,
17 * verbatim and that no modifications are made prior to this
18 * point in the file.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. All advertising materials mentioning features or use of this software
23 * must display the following acknowledgement:
24 * This product includes software developed by Jordan Hubbard
25 * for the FreeBSD Project.
26 * 4. The name of Jordan Hubbard or the FreeBSD project may not be used to
27 * endorse or promote products derived from this software without specific
28 * prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 *
42 */
43
44#include "sysinstall.h"
45#include <ctype.h>
46#include <sys/disklabel.h>
47
48/*
49 * Everything to do with editing the contents of disk labels.
50 */
51
52/* A nice message we use a lot in the disklabel editor */
53#define MSG_NOT_APPLICABLE "That option is not applicable here"
54
55/*
56 * I make some pretty gross assumptions about having a max of 50 chunks
57 * total - 8 slices and 42 partitions. I can't easily display many more
58 * than that on the screen at once!
59 *
60 * For 2.1 I'll revisit this and try to make it more dynamic, but since
61 * this will catch 99.99% of all possible cases, I'm not too worried.
62 */
63#define MAX_CHUNKS 50
64
65/* Where to start printing the freebsd slices */
66#define CHUNK_SLICE_START_ROW 2
67#define CHUNK_PART_START_ROW 11
68
8 *
9 * Copyright (c) 1995
10 * Jordan Hubbard. All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer,
17 * verbatim and that no modifications are made prior to this
18 * point in the file.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. All advertising materials mentioning features or use of this software
23 * must display the following acknowledgement:
24 * This product includes software developed by Jordan Hubbard
25 * for the FreeBSD Project.
26 * 4. The name of Jordan Hubbard or the FreeBSD project may not be used to
27 * endorse or promote products derived from this software without specific
28 * prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 *
42 */
43
44#include "sysinstall.h"
45#include <ctype.h>
46#include <sys/disklabel.h>
47
48/*
49 * Everything to do with editing the contents of disk labels.
50 */
51
52/* A nice message we use a lot in the disklabel editor */
53#define MSG_NOT_APPLICABLE "That option is not applicable here"
54
55/*
56 * I make some pretty gross assumptions about having a max of 50 chunks
57 * total - 8 slices and 42 partitions. I can't easily display many more
58 * than that on the screen at once!
59 *
60 * For 2.1 I'll revisit this and try to make it more dynamic, but since
61 * this will catch 99.99% of all possible cases, I'm not too worried.
62 */
63#define MAX_CHUNKS 50
64
65/* Where to start printing the freebsd slices */
66#define CHUNK_SLICE_START_ROW 2
67#define CHUNK_PART_START_ROW 11
68
69/* One MB worth of blocks */
70#define ONE_MEG 2048
71
69/* The smallest filesystem we're willing to create */
72/* The smallest filesystem we're willing to create */
70#define FS_MIN_SIZE 2048
73#define FS_MIN_SIZE ONE_MEG
71
72/* The smallest root filesystem we're willing to create */
74
75/* The smallest root filesystem we're willing to create */
73#define ROOT_MIN_SIZE 40960 /* 20MB */
76#define ROOT_MIN_SIZE (20 * ONE_MEG)
74
75/* All the chunks currently displayed on the screen */
76static struct {
77 struct disk *d;
78 struct chunk *c;
79 PartType type;
80} label_chunk_info[MAX_CHUNKS + 1];
81static int here;
82
83/* See if we're already using a desired partition name */
84static Boolean
85check_conflict(char *name)
86{
87 int i;
88
89 for (i = 0; label_chunk_info[i].d; i++)
90 if (label_chunk_info[i].type == PART_FILESYSTEM
91 && label_chunk_info[i].c->private
92 && !strcmp(((PartInfo *)label_chunk_info[i].c->private)->mountpoint, name))
93 return TRUE;
94 return FALSE;
95}
96
97/* How much space is in this FreeBSD slice? */
98static int
99space_free(struct chunk *c)
100{
101 struct chunk *c1 = c->part;
102 int sz = c->size;
103
104 while (c1) {
105 if (c1->type != unused)
106 sz -= c1->size;
107 c1 = c1->next;
108 }
109 if (sz < 0)
110 msgFatal("Partitions are larger than actual chunk??");
111 return sz;
112}
113
114/* Snapshot the current situation into the displayed chunks structure */
115static void
116record_label_chunks()
117{
118 int i, j, p;
119 struct chunk *c1, *c2;
120 Device **devs;
121 Disk *d;
122
123 devs = deviceFind(NULL, DEVICE_TYPE_DISK);
124 if (!devs) {
125 msgConfirm("No disks found!");
126 return;
127 }
128
129 j = p = 0;
130 /* First buzz through and pick up the FreeBSD slices */
131 for (i = 0; devs[i]; i++) {
132 if (!devs[i]->enabled)
133 continue;
134 d = (Disk *)devs[i]->private;
135 if (!d->chunks)
136 msgFatal("No chunk list found for %s!", d->name);
137
138 /* Put the slice entries first */
139 for (c1 = d->chunks->part; c1; c1 = c1->next) {
140 if (c1->type == freebsd) {
141 label_chunk_info[j].type = PART_SLICE;
142 label_chunk_info[j].d = d;
143 label_chunk_info[j].c = c1;
144 ++j;
145 }
146 }
147 }
148 /* Now run through again and get the FreeBSD partition entries */
149 for (i = 0; devs[i]; i++) {
150 if (!devs[i]->enabled)
151 continue;
152 d = (Disk *)devs[i]->private;
153 /* Then buzz through and pick up the partitions */
154 for (c1 = d->chunks->part; c1; c1 = c1->next) {
155 if (c1->type == freebsd) {
156 for (c2 = c1->part; c2; c2 = c2->next) {
157 if (c2->type == part) {
158 if (c2->subtype == FS_SWAP)
159 label_chunk_info[j].type = PART_SWAP;
160 else
161 label_chunk_info[j].type = PART_FILESYSTEM;
162 label_chunk_info[j].d = d;
163 label_chunk_info[j].c = c2;
164 ++j;
165 }
166 }
167 }
168 else if (c1->type == fat) {
169 label_chunk_info[j].type = PART_FAT;
170 label_chunk_info[j].d = d;
171 label_chunk_info[j].c = c1;
77
78/* All the chunks currently displayed on the screen */
79static struct {
80 struct disk *d;
81 struct chunk *c;
82 PartType type;
83} label_chunk_info[MAX_CHUNKS + 1];
84static int here;
85
86/* See if we're already using a desired partition name */
87static Boolean
88check_conflict(char *name)
89{
90 int i;
91
92 for (i = 0; label_chunk_info[i].d; i++)
93 if (label_chunk_info[i].type == PART_FILESYSTEM
94 && label_chunk_info[i].c->private
95 && !strcmp(((PartInfo *)label_chunk_info[i].c->private)->mountpoint, name))
96 return TRUE;
97 return FALSE;
98}
99
100/* How much space is in this FreeBSD slice? */
101static int
102space_free(struct chunk *c)
103{
104 struct chunk *c1 = c->part;
105 int sz = c->size;
106
107 while (c1) {
108 if (c1->type != unused)
109 sz -= c1->size;
110 c1 = c1->next;
111 }
112 if (sz < 0)
113 msgFatal("Partitions are larger than actual chunk??");
114 return sz;
115}
116
117/* Snapshot the current situation into the displayed chunks structure */
118static void
119record_label_chunks()
120{
121 int i, j, p;
122 struct chunk *c1, *c2;
123 Device **devs;
124 Disk *d;
125
126 devs = deviceFind(NULL, DEVICE_TYPE_DISK);
127 if (!devs) {
128 msgConfirm("No disks found!");
129 return;
130 }
131
132 j = p = 0;
133 /* First buzz through and pick up the FreeBSD slices */
134 for (i = 0; devs[i]; i++) {
135 if (!devs[i]->enabled)
136 continue;
137 d = (Disk *)devs[i]->private;
138 if (!d->chunks)
139 msgFatal("No chunk list found for %s!", d->name);
140
141 /* Put the slice entries first */
142 for (c1 = d->chunks->part; c1; c1 = c1->next) {
143 if (c1->type == freebsd) {
144 label_chunk_info[j].type = PART_SLICE;
145 label_chunk_info[j].d = d;
146 label_chunk_info[j].c = c1;
147 ++j;
148 }
149 }
150 }
151 /* Now run through again and get the FreeBSD partition entries */
152 for (i = 0; devs[i]; i++) {
153 if (!devs[i]->enabled)
154 continue;
155 d = (Disk *)devs[i]->private;
156 /* Then buzz through and pick up the partitions */
157 for (c1 = d->chunks->part; c1; c1 = c1->next) {
158 if (c1->type == freebsd) {
159 for (c2 = c1->part; c2; c2 = c2->next) {
160 if (c2->type == part) {
161 if (c2->subtype == FS_SWAP)
162 label_chunk_info[j].type = PART_SWAP;
163 else
164 label_chunk_info[j].type = PART_FILESYSTEM;
165 label_chunk_info[j].d = d;
166 label_chunk_info[j].c = c2;
167 ++j;
168 }
169 }
170 }
171 else if (c1->type == fat) {
172 label_chunk_info[j].type = PART_FAT;
173 label_chunk_info[j].d = d;
174 label_chunk_info[j].c = c1;
175 ++j;
172 }
173 }
174 }
175 label_chunk_info[j].d = NULL;
176 label_chunk_info[j].c = NULL;
177 if (here >= j)
178 here = j ? j - 1 : 0;
179}
180
181/* A new partition entry */
182static PartInfo *
183new_part(char *mpoint, Boolean newfs, u_long size)
184{
185 PartInfo *ret;
186 u_long target,divisor;
187
188 ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
189 strncpy(ret->mountpoint, mpoint, FILENAME_MAX);
190 strcpy(ret->newfs_cmd, "newfs");
191 ret->newfs = newfs;
192 if (!size)
193 return ret;
194 for(target = size; target; target--) {
195 for(divisor = 4096 ; divisor > 1023; divisor--) {
196 if (!(target % divisor)) {
197 sprintf(ret->newfs_cmd+strlen(ret->newfs_cmd),
198 " -u %ld",divisor);
199 return ret;
200 }
201 }
202 }
203 return ret;
204}
205
206/* Get the mountpoint for a partition and save it away */
207PartInfo *
208get_mountpoint(struct chunk *old)
209{
210 char *val;
211 PartInfo *tmp;
212
176 }
177 }
178 }
179 label_chunk_info[j].d = NULL;
180 label_chunk_info[j].c = NULL;
181 if (here >= j)
182 here = j ? j - 1 : 0;
183}
184
185/* A new partition entry */
186static PartInfo *
187new_part(char *mpoint, Boolean newfs, u_long size)
188{
189 PartInfo *ret;
190 u_long target,divisor;
191
192 ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
193 strncpy(ret->mountpoint, mpoint, FILENAME_MAX);
194 strcpy(ret->newfs_cmd, "newfs");
195 ret->newfs = newfs;
196 if (!size)
197 return ret;
198 for(target = size; target; target--) {
199 for(divisor = 4096 ; divisor > 1023; divisor--) {
200 if (!(target % divisor)) {
201 sprintf(ret->newfs_cmd+strlen(ret->newfs_cmd),
202 " -u %ld",divisor);
203 return ret;
204 }
205 }
206 }
207 return ret;
208}
209
210/* Get the mountpoint for a partition and save it away */
211PartInfo *
212get_mountpoint(struct chunk *old)
213{
214 char *val;
215 PartInfo *tmp;
216
213 dialog_clear(); clear();
214 val = msgGetInput(old && old->private ? ((PartInfo *)old->private)->mountpoint : NULL,
215 "Please specify a mount point for the partition");
216 if (!val)
217 return NULL;
218
219 /* Is it just the same value? */
220 if (old && old->private && !strcmp(((PartInfo *)old->private)->mountpoint, val))
221 return NULL;
222 if (check_conflict(val)) {
223 msgConfirm("You already have a mount point for %s assigned!", val);
224 return NULL;
225 }
226 if (*val != '/') {
227 msgConfirm("Mount point must start with a / character");
228 return NULL;
229 }
230 if (!strcmp(val, "/")) {
231 if (old)
232 old->flags |= CHUNK_IS_ROOT;
233 } else if (old) {
234 old->flags &= ~CHUNK_IS_ROOT;
235 }
236 safe_free(old ? old->private : NULL);
237 tmp = new_part(val, TRUE, 0);
238 if (old) {
239 old->private = tmp;
240 old->private_free = safe_free;
241 }
242 return tmp;
243}
244
245/* Get the type of the new partiton */
246static PartType
247get_partition_type(void)
248{
249 char selection[20];
250 int i;
251
252 static unsigned char *fs_types[] = {
253 "FS",
254 "A file system",
255 "Swap",
256 "A swap partition.",
257 };
217 val = msgGetInput(old && old->private ? ((PartInfo *)old->private)->mountpoint : NULL,
218 "Please specify a mount point for the partition");
219 if (!val)
220 return NULL;
221
222 /* Is it just the same value? */
223 if (old && old->private && !strcmp(((PartInfo *)old->private)->mountpoint, val))
224 return NULL;
225 if (check_conflict(val)) {
226 msgConfirm("You already have a mount point for %s assigned!", val);
227 return NULL;
228 }
229 if (*val != '/') {
230 msgConfirm("Mount point must start with a / character");
231 return NULL;
232 }
233 if (!strcmp(val, "/")) {
234 if (old)
235 old->flags |= CHUNK_IS_ROOT;
236 } else if (old) {
237 old->flags &= ~CHUNK_IS_ROOT;
238 }
239 safe_free(old ? old->private : NULL);
240 tmp = new_part(val, TRUE, 0);
241 if (old) {
242 old->private = tmp;
243 old->private_free = safe_free;
244 }
245 return tmp;
246}
247
248/* Get the type of the new partiton */
249static PartType
250get_partition_type(void)
251{
252 char selection[20];
253 int i;
254
255 static unsigned char *fs_types[] = {
256 "FS",
257 "A file system",
258 "Swap",
259 "A swap partition.",
260 };
258 dialog_clear(); clear();
259 i = dialog_menu("Please choose a partition type",
260 "If you want to use this partition for swap space, select Swap.\nIf you want to put a filesystem on it, choose FS.", -1, -1, 2, 2, fs_types, selection, NULL, NULL);
261 if (!i) {
262 if (!strcmp(selection, "FS"))
263 return PART_FILESYSTEM;
264 else if (!strcmp(selection, "Swap"))
265 return PART_SWAP;
266 }
267 return PART_NONE;
268}
269
270/* If the user wants a special newfs command for this, set it */
271static void
272getNewfsCmd(PartInfo *p)
273{
274 char *val;
275
276 val = msgGetInput(p->newfs_cmd,
277 "Please enter the newfs command and options you'd like to use in\ncreating this file system.");
278 if (val)
279 strncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
280}
281
282
283#define MAX_MOUNT_NAME 12
284
285#define PART_PART_COL 0
286#define PART_MOUNT_COL 8
287#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
288#define PART_NEWFS_COL (PART_SIZE_COL + 7)
289#define PART_OFF 38
290
291/* How many mounted partitions to display in column before going to next */
292#define CHUNK_COLUMN_MAX 5
293
294/* stick this all up on the screen */
295static void
296print_label_chunks(void)
297{
298 int i, j, srow, prow, pcol;
299 int sz;
300
301 attrset(A_REVERSE);
302 mvaddstr(0, 25, "FreeBSD Disklabel Editor");
303 clrtobot();
304 attrset(A_NORMAL);
305
306 for (i = 0; i < 2; i++) {
307 mvaddstr(CHUNK_PART_START_ROW - 2, PART_PART_COL + (i * PART_OFF), "Part");
308 mvaddstr(CHUNK_PART_START_ROW - 1, PART_PART_COL + (i * PART_OFF), "----");
309
310 mvaddstr(CHUNK_PART_START_ROW - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
311 mvaddstr(CHUNK_PART_START_ROW - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
312
313 mvaddstr(CHUNK_PART_START_ROW - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size");
314 mvaddstr(CHUNK_PART_START_ROW - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----");
315
316 mvaddstr(CHUNK_PART_START_ROW - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
317 mvaddstr(CHUNK_PART_START_ROW - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
318 }
319 srow = CHUNK_SLICE_START_ROW;
320 prow = CHUNK_PART_START_ROW;
321 pcol = 0;
322
323 for (i = 0; label_chunk_info[i].d; i++) {
324 if (i == here)
325 attrset(A_REVERSE);
326 /* Is it a slice entry displayed at the top? */
327 if (label_chunk_info[i].type == PART_SLICE) {
328 sz = space_free(label_chunk_info[i].c);
329 mvprintw(srow++, 0,
330 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
331 label_chunk_info[i].d->name,
261 i = dialog_menu("Please choose a partition type",
262 "If you want to use this partition for swap space, select Swap.\nIf you want to put a filesystem on it, choose FS.", -1, -1, 2, 2, fs_types, selection, NULL, NULL);
263 if (!i) {
264 if (!strcmp(selection, "FS"))
265 return PART_FILESYSTEM;
266 else if (!strcmp(selection, "Swap"))
267 return PART_SWAP;
268 }
269 return PART_NONE;
270}
271
272/* If the user wants a special newfs command for this, set it */
273static void
274getNewfsCmd(PartInfo *p)
275{
276 char *val;
277
278 val = msgGetInput(p->newfs_cmd,
279 "Please enter the newfs command and options you'd like to use in\ncreating this file system.");
280 if (val)
281 strncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
282}
283
284
285#define MAX_MOUNT_NAME 12
286
287#define PART_PART_COL 0
288#define PART_MOUNT_COL 8
289#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
290#define PART_NEWFS_COL (PART_SIZE_COL + 7)
291#define PART_OFF 38
292
293/* How many mounted partitions to display in column before going to next */
294#define CHUNK_COLUMN_MAX 5
295
296/* stick this all up on the screen */
297static void
298print_label_chunks(void)
299{
300 int i, j, srow, prow, pcol;
301 int sz;
302
303 attrset(A_REVERSE);
304 mvaddstr(0, 25, "FreeBSD Disklabel Editor");
305 clrtobot();
306 attrset(A_NORMAL);
307
308 for (i = 0; i < 2; i++) {
309 mvaddstr(CHUNK_PART_START_ROW - 2, PART_PART_COL + (i * PART_OFF), "Part");
310 mvaddstr(CHUNK_PART_START_ROW - 1, PART_PART_COL + (i * PART_OFF), "----");
311
312 mvaddstr(CHUNK_PART_START_ROW - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
313 mvaddstr(CHUNK_PART_START_ROW - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
314
315 mvaddstr(CHUNK_PART_START_ROW - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size");
316 mvaddstr(CHUNK_PART_START_ROW - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----");
317
318 mvaddstr(CHUNK_PART_START_ROW - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
319 mvaddstr(CHUNK_PART_START_ROW - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
320 }
321 srow = CHUNK_SLICE_START_ROW;
322 prow = CHUNK_PART_START_ROW;
323 pcol = 0;
324
325 for (i = 0; label_chunk_info[i].d; i++) {
326 if (i == here)
327 attrset(A_REVERSE);
328 /* Is it a slice entry displayed at the top? */
329 if (label_chunk_info[i].type == PART_SLICE) {
330 sz = space_free(label_chunk_info[i].c);
331 mvprintw(srow++, 0,
332 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
333 label_chunk_info[i].d->name,
332 label_chunk_info[i].c->name, sz, (sz / 2048));
334 label_chunk_info[i].c->name, sz, (sz / ONE_MEG));
333 }
334 /* Otherwise it's a DOS, swap or filesystem entry, at the bottom */
335 else {
336 char onestr[PART_OFF], num[10], *mountpoint, *newfs;
337
338 /*
339 * We copy this into a blank-padded string so that it looks like
340 * a solid bar in reverse-video
341 */
342 memset(onestr, ' ', PART_OFF - 1);
343 onestr[PART_OFF - 1] = '\0';
344 /* Go for two columns */
345 if (prow == (CHUNK_PART_START_ROW + CHUNK_COLUMN_MAX)) {
346 pcol = PART_OFF;
347 prow = CHUNK_PART_START_ROW;
348 }
349 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name,
350 strlen(label_chunk_info[i].c->name));
351 /* If it's a filesystem, display the mountpoint */
352 if (label_chunk_info[i].type == PART_FILESYSTEM) {
353 if (label_chunk_info[i].c->private == NULL) {
354 static int mnt = 0;
355 char foo[10];
356
357 /*
358 * Hmm! A partition that must have already been here.
359 * Fill in a fake mountpoint and register it
360 */
361 sprintf(foo, "/mnt%d", mnt++);
362 label_chunk_info[i].c->private =
363 new_part(foo, FALSE,label_chunk_info[i].c->size);
364 label_chunk_info[i].c->private_free = safe_free;
365 }
366 mountpoint = ((PartInfo *)label_chunk_info[i].c->private)->mountpoint;
367 newfs = ((PartInfo *)label_chunk_info[i].c->private)->newfs ? "Y" : "N";
368 }
369 else if (label_chunk_info[i].type == PART_SWAP) {
370 mountpoint = "swap";
371 newfs = " ";
372 }
373 else if (label_chunk_info[i].type == PART_FAT) {
374 mountpoint = "DOS FAT";
375 newfs = "*";
376 }
377 else {
378 mountpoint = "<unknown>";
379 newfs = "*";
380 }
381 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
382 onestr[PART_MOUNT_COL + j] = mountpoint[j];
383 snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ?
335 }
336 /* Otherwise it's a DOS, swap or filesystem entry, at the bottom */
337 else {
338 char onestr[PART_OFF], num[10], *mountpoint, *newfs;
339
340 /*
341 * We copy this into a blank-padded string so that it looks like
342 * a solid bar in reverse-video
343 */
344 memset(onestr, ' ', PART_OFF - 1);
345 onestr[PART_OFF - 1] = '\0';
346 /* Go for two columns */
347 if (prow == (CHUNK_PART_START_ROW + CHUNK_COLUMN_MAX)) {
348 pcol = PART_OFF;
349 prow = CHUNK_PART_START_ROW;
350 }
351 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name,
352 strlen(label_chunk_info[i].c->name));
353 /* If it's a filesystem, display the mountpoint */
354 if (label_chunk_info[i].type == PART_FILESYSTEM) {
355 if (label_chunk_info[i].c->private == NULL) {
356 static int mnt = 0;
357 char foo[10];
358
359 /*
360 * Hmm! A partition that must have already been here.
361 * Fill in a fake mountpoint and register it
362 */
363 sprintf(foo, "/mnt%d", mnt++);
364 label_chunk_info[i].c->private =
365 new_part(foo, FALSE,label_chunk_info[i].c->size);
366 label_chunk_info[i].c->private_free = safe_free;
367 }
368 mountpoint = ((PartInfo *)label_chunk_info[i].c->private)->mountpoint;
369 newfs = ((PartInfo *)label_chunk_info[i].c->private)->newfs ? "Y" : "N";
370 }
371 else if (label_chunk_info[i].type == PART_SWAP) {
372 mountpoint = "swap";
373 newfs = " ";
374 }
375 else if (label_chunk_info[i].type == PART_FAT) {
376 mountpoint = "DOS FAT";
377 newfs = "*";
378 }
379 else {
380 mountpoint = "<unknown>";
381 newfs = "*";
382 }
383 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
384 onestr[PART_MOUNT_COL + j] = mountpoint[j];
385 snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ?
384 label_chunk_info[i].c->size / 2048 : 0);
386 label_chunk_info[i].c->size / ONE_MEG : 0);
385 memcpy(onestr + PART_SIZE_COL, num, strlen(num));
386 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
387 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
388 mvaddstr(prow, pcol, onestr);
389 ++prow;
390 }
391 if (i == here)
392 attrset(A_NORMAL);
393 }
394}
395
396static void
397print_command_summary()
398{
399 mvprintw(17, 0,
400 "The following commands are valid here (upper or lower case):");
401 mvprintw(19, 0, "C = Create Partition D = Delete Partition M = Mount Partition");
402 mvprintw(20, 0, "N = Newfs Options T = Toggle Newfs ESC = Exit this screen");
403 mvprintw(21, 0, "The default target will be displayed in ");
404
405 attrset(A_REVERSE);
406 addstr("reverse video.");
407 attrset(A_NORMAL);
408 mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to move.");
409 move(0, 0);
410}
411
412int
413diskLabelEditor(char *str)
414{
415 int sz, key = 0;
416 Boolean labeling;
417 char *msg = NULL;
418 PartInfo *p;
419 PartType type;
420
421 labeling = TRUE;
422 keypad(stdscr, TRUE);
423 record_label_chunks();
424
425 if (!getenv(DISK_PARTITIONED)) {
426 msgConfirm("You need to partition your disk(s) before you can assign disk labels.");
427 return 0;
428 }
387 memcpy(onestr + PART_SIZE_COL, num, strlen(num));
388 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
389 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
390 mvaddstr(prow, pcol, onestr);
391 ++prow;
392 }
393 if (i == here)
394 attrset(A_NORMAL);
395 }
396}
397
398static void
399print_command_summary()
400{
401 mvprintw(17, 0,
402 "The following commands are valid here (upper or lower case):");
403 mvprintw(19, 0, "C = Create Partition D = Delete Partition M = Mount Partition");
404 mvprintw(20, 0, "N = Newfs Options T = Toggle Newfs ESC = Exit this screen");
405 mvprintw(21, 0, "The default target will be displayed in ");
406
407 attrset(A_REVERSE);
408 addstr("reverse video.");
409 attrset(A_NORMAL);
410 mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to move.");
411 move(0, 0);
412}
413
414int
415diskLabelEditor(char *str)
416{
417 int sz, key = 0;
418 Boolean labeling;
419 char *msg = NULL;
420 PartInfo *p;
421 PartType type;
422
423 labeling = TRUE;
424 keypad(stdscr, TRUE);
425 record_label_chunks();
426
427 if (!getenv(DISK_PARTITIONED)) {
428 msgConfirm("You need to partition your disk(s) before you can assign disk labels.");
429 return 0;
430 }
429 clear();
431 dialog_clear(); clear();
430 while (labeling) {
432 while (labeling) {
433 clear();
431 print_label_chunks();
432 print_command_summary();
433 if (msg) {
434 attrset(A_REVERSE); mvprintw(23, 0, msg); attrset(A_NORMAL);
435 beep();
436 msg = NULL;
437 }
438 refresh();
439 key = toupper(getch());
440 switch (key) {
441
442 case KEY_UP:
443 case '-':
444 if (here != 0)
445 --here;
446 break;
447
448 case KEY_DOWN:
449 case '+':
450 case '\r':
451 case '\n':
452 if (label_chunk_info[here + 1].d)
453 ++here;
454 break;
455
456 case KEY_HOME:
457 here = 0;
458 break;
459
460 case KEY_END:
461 while (label_chunk_info[here + 1].d)
462 ++here;
463 break;
464
465 case KEY_F(1):
466 case '?':
467 systemDisplayFile("disklabel.hlp");
468 break;
469
470 case 'C':
471 if (label_chunk_info[here].type != PART_SLICE) {
472 msg = "You can only do this in a master partition (see top of screen)";
473 break;
474 }
475 sz = space_free(label_chunk_info[here].c);
476 if (sz <= FS_MIN_SIZE) {
477 msg = "Not enough space to create additional FreeBSD partition";
478 break;
479 }
480 {
434 print_label_chunks();
435 print_command_summary();
436 if (msg) {
437 attrset(A_REVERSE); mvprintw(23, 0, msg); attrset(A_NORMAL);
438 beep();
439 msg = NULL;
440 }
441 refresh();
442 key = toupper(getch());
443 switch (key) {
444
445 case KEY_UP:
446 case '-':
447 if (here != 0)
448 --here;
449 break;
450
451 case KEY_DOWN:
452 case '+':
453 case '\r':
454 case '\n':
455 if (label_chunk_info[here + 1].d)
456 ++here;
457 break;
458
459 case KEY_HOME:
460 here = 0;
461 break;
462
463 case KEY_END:
464 while (label_chunk_info[here + 1].d)
465 ++here;
466 break;
467
468 case KEY_F(1):
469 case '?':
470 systemDisplayFile("disklabel.hlp");
471 break;
472
473 case 'C':
474 if (label_chunk_info[here].type != PART_SLICE) {
475 msg = "You can only do this in a master partition (see top of screen)";
476 break;
477 }
478 sz = space_free(label_chunk_info[here].c);
479 if (sz <= FS_MIN_SIZE) {
480 msg = "Not enough space to create additional FreeBSD partition";
481 break;
482 }
483 {
481 char *val, *cp, tmpb[20];
482 int size;
483 struct chunk *tmp;
484 u_long flags = 0;
484 char *val, *cp, tmpb[20];
485 int size;
486 struct chunk *tmp;
487 u_long flags = 0;
485
488
486 snprintf(tmpb, 20, "%d", sz);
487 val = msgGetInput(tmpb, "Please specify the size for new FreeBSD partition in blocks, or append\na trailing `M' for megabytes (e.g. 20M).");
488 if (!val || (size = strtol(val, &cp, 0)) <= 0)
489 break;
489 snprintf(tmpb, 20, "%d", sz);
490 val = msgGetInput(tmpb, "Please specify the size for new FreeBSD partition in blocks, or append\na trailing `M' for megabytes (e.g. 20M).");
491 if (!val || (size = strtol(val, &cp, 0)) <= 0)
492 break;
490
493
491 if (*cp && toupper(*cp) == 'M')
492 size *= 2048;
494 if (sz <= FS_MIN_SIZE) {
495 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
496 break;
497 }
498 if (*cp && toupper(*cp) == 'M')
499 size *= ONE_MEG;
493
500
494 type = get_partition_type();
495 if (type == PART_NONE)
496 break;
497
498 if (type == PART_FILESYSTEM) {
499 if ((p = get_mountpoint(NULL)) == NULL)
501 type = get_partition_type();
502 if (type == PART_NONE)
500 break;
503 break;
501 else if (!strcmp(p->mountpoint, "/"))
502 flags |= CHUNK_IS_ROOT;
503 else
504 flags &= ~CHUNK_IS_ROOT;
505 } else
506 p = NULL;
507
504
508 if ((flags & CHUNK_IS_ROOT)) {
509 if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) {
510 msgConfirm("This region cannot be used for your root partition as\nthe FreeBSD boot code cannot deal with a root partition created in\nsuch a location. Please choose another location for your root\npartition and try again!");
511 break;
505 if (type == PART_FILESYSTEM) {
506 if ((p = get_mountpoint(NULL)) == NULL)
507 break;
508 else if (!strcmp(p->mountpoint, "/"))
509 flags |= CHUNK_IS_ROOT;
510 else
511 flags &= ~CHUNK_IS_ROOT;
512 } else
513 p = NULL;
514
515 if ((flags & CHUNK_IS_ROOT)) {
516 if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) {
517 msgConfirm("This region cannot be used for your root partition as\nthe FreeBSD boot code cannot deal with a root partition created in\nsuch a location. Please choose another location for your root\npartition and try again!");
518 break;
519 }
520 if (size < ROOT_MIN_SIZE) {
521 msgConfirm("This is too small a size for a root partition. For a variety of\nreasons, root partitions should be at least %dMB in size", ROOT_MIN_SIZE / ONE_MEG);
522 break;
523 }
512 }
524 }
513 if (size < ROOT_MIN_SIZE) {
514 msgConfirm("This is too small a size for a root partition. For a variety of\nreasons, root partitions should be at least %dMB in size", ROOT_MIN_SIZE / 2048);
525 tmp = Create_Chunk_DWIM(label_chunk_info[here].d,
526 label_chunk_info[here].c,
527 size, part,
528 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
529 flags);
530 if (!tmp) {
531 msgConfirm("Unable to create the partition. Too big?");
515 break;
516 }
532 break;
533 }
517 }
518 tmp = Create_Chunk_DWIM(label_chunk_info[here].d,
519 label_chunk_info[here].c,
520 size, part,
521 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
522 flags);
523 if (!tmp) {
524 msgConfirm("Unable to create the partition. Too big?");
525 break;
526 }
527 if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) {
534 if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) {
528 msgConfirm("This region cannot be used for your root partition as it starts\nor extends past the 1024'th cylinder mark and is thus a\npoor location to boot from. Please choose another\nlocation for your root partition and try again!");
529 Delete_Chunk(label_chunk_info[here].d, tmp);
530 break;
535 msgConfirm("This region cannot be used for your root partition as it starts\nor extends past the 1024'th cylinder mark and is thus a\npoor location to boot from. Please choose another\nlocation for your root partition and try again!");
536 Delete_Chunk(label_chunk_info[here].d, tmp);
537 break;
531 }
532 if (type != PART_SWAP) {
538 }
539 if (type != PART_SWAP) {
533 /* This is needed to tell the newfs -u about the size */
534 tmp->private = new_part(p->mountpoint,p->newfs,tmp->size);
535 safe_free(p);
540 /* This is needed to tell the newfs -u about the size */
541 tmp->private = new_part(p->mountpoint,p->newfs,tmp->size);
542 safe_free(p);
536 } else {
543 } else {
537 tmp->private = p;
544 tmp->private = p;
538 }
539 tmp->private_free = safe_free;
540 record_label_chunks();
545 }
546 tmp->private_free = safe_free;
547 record_label_chunks();
541 }
542 break;
543
544 case 'D': /* delete */
545 if (label_chunk_info[here].type == PART_SLICE) {
546 msg = MSG_NOT_APPLICABLE;
547 break;
548 }
549 else if (label_chunk_info[here].type == PART_FAT) {
550 msg = "Use the Disk Partition Editor to delete this";
551 break;
552 }
553 Delete_Chunk(label_chunk_info[here].d, label_chunk_info[here].c);
554 record_label_chunks();
555 break;
556
557 case 'M': /* mount */
558 switch(label_chunk_info[here].type) {
559 case PART_SLICE:
560 msg = MSG_NOT_APPLICABLE;
561 break;
562
563 case PART_SWAP:
564 msg = "You don't need to specify a mountpoint for a swap partition.";
565 break;
566
567 case PART_FAT:
568 case PART_FILESYSTEM:
569 p = get_mountpoint(label_chunk_info[here].c);
570 if (p) {
571 p->newfs = FALSE;
572 record_label_chunks();
573 }
574 break;
575
576 default:
577 msgFatal("Bogus partition under cursor???");
578 break;
579 }
580 break;
581
582 case 'N': /* Set newfs options */
583 if (label_chunk_info[here].c->private &&
584 ((PartInfo *)label_chunk_info[here].c->private)->newfs)
585 getNewfsCmd(label_chunk_info[here].c->private);
586 else
587 msg = MSG_NOT_APPLICABLE;
588 break;
589
590 case 'T': /* Toggle newfs state */
591 if (label_chunk_info[here].type == PART_FILESYSTEM &&
592 label_chunk_info[here].c->private) {
593 PartInfo *pi = ((PartInfo *)
594 label_chunk_info[here].c->private);
595 label_chunk_info[here].c->private = new_part(
596 pi->mountpoint,
597 !pi->newfs,
598 label_chunk_info[here].c->size);
599 safe_free(pi);
600 }
601 else
602 msg = MSG_NOT_APPLICABLE;
603 break;
604
605 case 'W':
606 if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\nThis is an entirely undocumented feature which you are not\nexpected to understand!")) {
607 int i;
608 Device **devs;
609
610 dialog_clear();
611 end_dialog();
612 DialogActive = FALSE;
613 devs = deviceFind(NULL, DEVICE_TYPE_DISK);
614 if (!devs) {
615 msgConfirm("Can't find any disk devicse!");
616 break;
617 }
618 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
619 if (devs[i]->enabled)
620 slice_wizard(((Disk *)devs[i]->private));
621 }
622 DialogActive = TRUE;
623 dialog_clear();
624 record_label_chunks();
625 }
626 else
627 msg = "A most prudent choice!";
628 break;
629
630 case 27: /* ESC */
631 labeling = FALSE;
632 break;
633
634 default:
635 beep();
636 msg = "Type F1 or ? for help";
637 break;
638 }
639 }
640 variable_set2(DISK_LABELLED, "yes");
641 dialog_clear();
548 }
549 break;
550
551 case 'D': /* delete */
552 if (label_chunk_info[here].type == PART_SLICE) {
553 msg = MSG_NOT_APPLICABLE;
554 break;
555 }
556 else if (label_chunk_info[here].type == PART_FAT) {
557 msg = "Use the Disk Partition Editor to delete this";
558 break;
559 }
560 Delete_Chunk(label_chunk_info[here].d, label_chunk_info[here].c);
561 record_label_chunks();
562 break;
563
564 case 'M': /* mount */
565 switch(label_chunk_info[here].type) {
566 case PART_SLICE:
567 msg = MSG_NOT_APPLICABLE;
568 break;
569
570 case PART_SWAP:
571 msg = "You don't need to specify a mountpoint for a swap partition.";
572 break;
573
574 case PART_FAT:
575 case PART_FILESYSTEM:
576 p = get_mountpoint(label_chunk_info[here].c);
577 if (p) {
578 p->newfs = FALSE;
579 record_label_chunks();
580 }
581 break;
582
583 default:
584 msgFatal("Bogus partition under cursor???");
585 break;
586 }
587 break;
588
589 case 'N': /* Set newfs options */
590 if (label_chunk_info[here].c->private &&
591 ((PartInfo *)label_chunk_info[here].c->private)->newfs)
592 getNewfsCmd(label_chunk_info[here].c->private);
593 else
594 msg = MSG_NOT_APPLICABLE;
595 break;
596
597 case 'T': /* Toggle newfs state */
598 if (label_chunk_info[here].type == PART_FILESYSTEM &&
599 label_chunk_info[here].c->private) {
600 PartInfo *pi = ((PartInfo *)
601 label_chunk_info[here].c->private);
602 label_chunk_info[here].c->private = new_part(
603 pi->mountpoint,
604 !pi->newfs,
605 label_chunk_info[here].c->size);
606 safe_free(pi);
607 }
608 else
609 msg = MSG_NOT_APPLICABLE;
610 break;
611
612 case 'W':
613 if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\nThis is an entirely undocumented feature which you are not\nexpected to understand!")) {
614 int i;
615 Device **devs;
616
617 dialog_clear();
618 end_dialog();
619 DialogActive = FALSE;
620 devs = deviceFind(NULL, DEVICE_TYPE_DISK);
621 if (!devs) {
622 msgConfirm("Can't find any disk devicse!");
623 break;
624 }
625 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
626 if (devs[i]->enabled)
627 slice_wizard(((Disk *)devs[i]->private));
628 }
629 DialogActive = TRUE;
630 dialog_clear();
631 record_label_chunks();
632 }
633 else
634 msg = "A most prudent choice!";
635 break;
636
637 case 27: /* ESC */
638 labeling = FALSE;
639 break;
640
641 default:
642 beep();
643 msg = "Type F1 or ? for help";
644 break;
645 }
646 }
647 variable_set2(DISK_LABELLED, "yes");
648 dialog_clear();
642 refresh();
643 return 0;
644}
645
646
647
649 return 0;
650}
651
652
653