]> git.ipfire.org Git - thirdparty/util-linux.git/blame - fdisks/fdiskbsdlabel.c
fdisk: (bsd) use ask API for add partition dialog
[thirdparty/util-linux.git] / fdisks / fdiskbsdlabel.c
CommitLineData
726f69e2
KZ
1/*
2 NetBSD disklabel editor for Linux fdisk
3 Written by Bernhard Fastenrath (fasten@informatik.uni-bonn.de)
4 with code from the NetBSD disklabel command:
50ea6795 5
726f69e2
KZ
6 Copyright (c) 1987, 1988 Regents of the University of California.
7 All rights reserved.
50ea6795 8
726f69e2
KZ
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12 1. Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in the
16 documentation and/or other materials provided with the distribution.
17 3. All advertising materials mentioning features or use of this software
18 must display the following acknowledgement:
50ea6795
KZ
19 This product includes software developed by the University of
20 California, Berkeley and its contributors.
726f69e2
KZ
21 4. Neither the name of the University nor the names of its contributors
22 may be used to endorse or promote products derived from this software
23 without specific prior written permission.
50ea6795 24
726f69e2
KZ
25 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 SUCH DAMAGE.
7eda085c
KZ
36
37 Changes:
38 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
22853e4a
KZ
39
40 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
63cccae4
KZ
41 support for OSF/1 disklabels on Alpha.
42 Also fixed unaligned accesses in alpha_bootblock_checksum()
726f69e2
KZ
43*/
44
45#include <unistd.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <fcntl.h>
50#include <ctype.h>
51#include <setjmp.h>
52#include <errno.h>
7eda085c 53#include "nls.h"
726f69e2 54
726f69e2
KZ
55#include <sys/param.h>
56
7eda085c 57#include "common.h"
726f69e2 58#include "fdisk.h"
e8f26419
KZ
59#define FREEBSD_PARTITION 0xa5
60#define NETBSD_PARTITION 0xa9
726f69e2 61#define DKTYPENAMES
5c36a0eb 62#include "fdiskbsdlabel.h"
3c88fb56 63#include "fdiskdoslabel.h"
726f69e2 64
0c5d095e
KZ
65/*
66 * in-memory fdisk BSD stuff
67 */
68struct fdisk_bsd_label {
69 struct fdisk_label head; /* generic part */
70};
71
72
9ffeb235 73static int xbsd_delete_part (struct fdisk_context *cxt, size_t partnum);
bddd84e7 74static void xbsd_edit_disklabel (struct fdisk_context *cxt);
918afd3f 75static int xbsd_write_bootstrap (struct fdisk_context *cxt);
9ffeb235 76static void xbsd_change_fstype (struct fdisk_context *cxt);
bddd84e7
KZ
77static int xbsd_get_part_index (struct fdisk_context *cxt, int max);
78static int xbsd_check_new_partition (struct fdisk_context *cxt, int *i);
95961ee2 79static unsigned short xbsd_dkcksum (struct xbsd_disklabel *lp);
7737f698
DB
80static int xbsd_initlabel (struct fdisk_context *cxt,
81 struct partition *p, struct xbsd_disklabel *d,
63cccae4 82 int pindex);
7737f698
DB
83static int xbsd_readlabel (struct fdisk_context *cxt,
84 struct partition *p, struct xbsd_disklabel *d);
85static int xbsd_writelabel (struct fdisk_context *cxt, struct partition *p, struct xbsd_disklabel *d);
726f69e2 86static void sync_disks (void);
22853e4a 87
726f69e2
KZ
88#if defined (__alpha__)
89void alpha_bootblock_checksum (char *boot);
90#endif
91
22853e4a
KZ
92#if !defined (__alpha__)
93static int xbsd_translate_fstype (int linux_type);
e53ced85 94static void xbsd_link_part (struct fdisk_context *cxt);
fd6b7a7f
KZ
95static struct partition *xbsd_part;
96static int xbsd_part_index;
726f69e2
KZ
97#endif
98
22853e4a
KZ
99#if defined (__alpha__)
100/* We access this through a u_int64_t * when checksumming */
101static char disklabelbuffer[BSD_BBSIZE] __attribute__((aligned(8)));
102#else
103static char disklabelbuffer[BSD_BBSIZE];
104#endif
105
106static struct xbsd_disklabel xbsd_dlabel;
107
ec10aa67
KZ
108#define bsd_cround(c, n) \
109 (fdisk_context_use_cylinders(c) ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
22853e4a 110
63cccae4
KZ
111/*
112 * Test whether the whole disk has BSD disk label magic.
113 *
114 * Note: often reformatting with DOS-type label leaves the BSD magic,
115 * so this does not mean that there is a BSD disk label.
116 */
b8855c86 117static int
9ffeb235 118osf_probe_label(struct fdisk_context *cxt)
8a95621d 119{
9ffeb235
KZ
120 assert(cxt);
121 assert(cxt->label);
122 assert(fdisk_is_disklabel(cxt, OSF));
123
7737f698 124 if (xbsd_readlabel (cxt, NULL, &xbsd_dlabel) == 0)
63cccae4
KZ
125 return 0;
126 return 1;
22853e4a
KZ
127}
128
22853e4a 129#if !defined (__alpha__)
9ffeb235
KZ
130static int hidden(int type)
131{
5c36a0eb
KZ
132 return type ^ 0x10;
133}
134
9ffeb235
KZ
135static int is_bsd_partition_type(int type)
136{
e8f26419
KZ
137 return (type == FREEBSD_PARTITION ||
138 type == hidden(FREEBSD_PARTITION) ||
139 type == NETBSD_PARTITION ||
140 type == hidden(NETBSD_PARTITION));
5c36a0eb 141}
22853e4a 142#endif
5c36a0eb 143
9ffeb235 144static int xbsd_write_disklabel (struct fdisk_context *cxt)
fae7b1bc 145{
fae7b1bc 146 printf (_("Writing disklabel to %s.\n"), cxt->dev_path);
e09435aa 147#if defined (__alpha__)
fae7b1bc
DB
148 xbsd_writelabel (cxt, NULL, &xbsd_dlabel);
149#else
fae7b1bc
DB
150 xbsd_writelabel (cxt, xbsd_part, &xbsd_dlabel);
151#endif
152 reread_partition_table(cxt, 0); /* no exit yet */
153
154 return 0;
155}
156
8254c3a5 157static int xbsd_add_part (struct fdisk_context *cxt,
9ffeb235 158 size_t partnum __attribute__((__unused__)),
ed470672 159 struct fdisk_parttype *t __attribute__((__unused__)))
0f639e54 160{
682802db 161 struct fdisk_ask *ask;
0f639e54 162 unsigned int begin, end;
8254c3a5 163 int i, rc;
0f639e54 164
9ffeb235
KZ
165 assert(cxt);
166 assert(cxt->label);
167 assert(fdisk_is_disklabel(cxt, OSF));
168
bddd84e7 169 rc = xbsd_check_new_partition(cxt, &i);
8254c3a5
DB
170 if (rc)
171 return rc;
0f639e54
DB
172
173#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
174 begin = get_start_sect(xbsd_part);
175 end = begin + get_nr_sects(xbsd_part) - 1;
176#else
177 begin = 0;
178 end = xbsd_dlabel.d_secperunit - 1;
179#endif
682802db 180 ask = fdisk_new_ask();
0f639e54 181
682802db
KZ
182 /*
183 * First sector
184 */
185 if (fdisk_context_use_cylinders(cxt))
186 fdisk_ask_set_query(ask, _("First cylinder"));
187 else
188 fdisk_ask_set_query(ask, _("First sector"));
189
190 fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
191 fdisk_ask_number_set_low(ask, bsd_cround(cxt, begin));
192 fdisk_ask_number_set_default(ask, bsd_cround(cxt, begin));
193 fdisk_ask_number_set_high(ask, bsd_cround(cxt, end));
194
195 rc = fdisk_do_ask(cxt, ask);
196 if (rc) {
197 fdisk_free_ask(ask);
198 return rc;
199 }
200 begin = fdisk_ask_number_get_result(ask);
0f639e54 201
ec10aa67 202 if (fdisk_context_use_cylinders(cxt))
0f639e54
DB
203 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
204
682802db
KZ
205 fdisk_reset_ask(ask);
206
207 /*
208 * Last sector
209 */
210 fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET);
211
212 if (fdisk_context_use_cylinders(cxt)) {
213 fdisk_ask_set_query(ask, _("Last cylinder, +cylinders or +size{K,M,G,T,P}"));
214 fdisk_ask_number_set_unit(ask,
215 cxt->sector_size *
216 fdisk_context_get_units_per_sector(cxt));
217 } else {
218 fdisk_ask_set_query(ask, _("Last sector, +sectors or +size{K,M,G,T,P}"));
219 fdisk_ask_number_set_unit(ask,cxt->sector_size);
220 }
221
222 fdisk_ask_number_set_low(ask, bsd_cround(cxt, begin));
223 fdisk_ask_number_set_default(ask, bsd_cround(cxt, end));
224 fdisk_ask_number_set_high(ask, bsd_cround(cxt, end));
225 fdisk_ask_number_set_base(ask, bsd_cround(cxt, begin));
226
227 rc = fdisk_do_ask(cxt, ask);
228 end = fdisk_ask_number_get_result(ask);
229 fdisk_free_ask(ask);
230 if (rc)
231 return rc;
0f639e54 232
ec10aa67 233 if (fdisk_context_use_cylinders(cxt))
0f639e54
DB
234 end = end * xbsd_dlabel.d_secpercyl - 1;
235
236 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
237 xbsd_dlabel.d_partitions[i].p_offset = begin;
238 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
8254c3a5 239
9ffeb235
KZ
240 cxt->label->nparts_cur = xbsd_dlabel.d_npartitions;
241 fdisk_label_set_changed(cxt->label, 1);
acf263d5 242
8254c3a5 243 return 0;
0f639e54
DB
244}
245
9ffeb235 246static int xbsd_create_disklabel(struct fdisk_context *cxt)
639f1d56
DB
247{
248 char c;
249
9ffeb235
KZ
250 assert(cxt);
251 assert(cxt->label);
252 assert(fdisk_is_disklabel(cxt, OSF));
253
682802db 254 fprintf (stderr, _("%s contains no BSD disklabel.\n"), cxt->dev_path);
639f1d56
DB
255
256 while (1) {
682802db 257 c = read_char(cxt, _("Do you want to create a BSD disklabel? (y/n) "));
639f1d56
DB
258 if (tolower(c) == 'y') {
259 if (xbsd_initlabel (cxt,
260#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
261 defined (__s390__) || defined (__s390x__)
262 NULL, &xbsd_dlabel, 0
263#else
264 xbsd_part, &xbsd_dlabel, xbsd_part_index
265#endif
266 ) == 1) {
267 xbsd_print_disklabel (cxt, 1);
9ffeb235
KZ
268 cxt->label->nparts_cur = xbsd_dlabel.d_npartitions;
269 cxt->label->nparts_max = BSD_MAXPARTITIONS;
639f1d56
DB
270 return 1;
271 } else
272 return 0;
273 } else if (c == 'n')
274 return 0;
275 }
276}
277
726f69e2 278void
7737f698 279bsd_command_prompt (struct fdisk_context *cxt)
e97a991a 280{
22853e4a 281#if !defined (__alpha__)
2b6fc908 282 int t, ss;
22853e4a 283 struct partition *p;
726f69e2 284
e09435aa
KZ
285 assert(cxt);
286 assert(cxt->parent);
287
22853e4a
KZ
288 for (t=0; t<4; t++) {
289 p = get_part_table(t);
e8f26419 290 if (p && is_bsd_partition_type(p->sys_ind)) {
22853e4a 291 xbsd_part = p;
fd6b7a7f 292 xbsd_part_index = t;
2b6fc908 293 ss = get_start_sect(xbsd_part);
e09435aa
KZ
294
295 /* TODO - partname uses static buffer!!! */
296 cxt->dev_path = partname(cxt->parent->dev_path, t+1, 0);
297 if (cxt->dev_path)
298 cxt->dev_path = strdup(cxt->dev_path);
299
5c36a0eb 300 if (ss == 0) {
22853e4a 301 fprintf (stderr, _("Partition %s has invalid starting sector 0.\n"),
e09435aa 302 cxt->dev_path);
22853e4a 303 return;
726f69e2 304 }
22853e4a 305 printf (_("Reading disklabel of %s at sector %d.\n"),
e09435aa 306 cxt->dev_path, ss + BSD_LABELSECTOR);
7737f698 307 if (xbsd_readlabel (cxt, xbsd_part, &xbsd_dlabel) == 0)
9ffeb235 308 if (xbsd_create_disklabel (cxt) == 0)
726f69e2
KZ
309 return;
310 break;
311 }
22853e4a 312 }
726f69e2 313
5c36a0eb 314 if (t == 4) {
823f0fd1 315 printf (_("There is no *BSD partition on %s.\n"), cxt->dev_path);
726f69e2
KZ
316 return;
317 }
318
319#elif defined (__alpha__)
320
7737f698
DB
321 if (xbsd_readlabel (cxt, NULL, &xbsd_dlabel) == 0)
322 if (xbsd_create_disklabel (cxt) == 0)
726f69e2
KZ
323 exit ( EXIT_SUCCESS );
324
325#endif
326
22853e4a 327 while (1) {
726f69e2 328 putchar ('\n');
bddd84e7 329 switch (tolower (read_char(cxt, _("BSD disklabel command (m for help): ")))) {
726f69e2 330 case 'd':
9ffeb235 331 xbsd_delete_part(cxt, xbsd_get_part_index(cxt, xbsd_dlabel.d_npartitions));
61c4cb85 332 break;
726f69e2 333 case 'e':
bddd84e7 334 xbsd_edit_disklabel (cxt);
726f69e2
KZ
335 break;
336 case 'i':
7737f698 337 xbsd_write_bootstrap (cxt);
726f69e2
KZ
338 break;
339 case 'l':
7b575fcc 340 list_partition_types (cxt);
726f69e2
KZ
341 break;
342 case 'n':
9ffeb235 343 xbsd_add_part (cxt, 0, 0);
0f639e54 344 break;
726f69e2 345 case 'p':
7737f698 346 xbsd_print_disklabel (cxt, 0);
726f69e2
KZ
347 break;
348 case 'q':
823f0fd1 349 close (cxt->dev_fd);
726f69e2 350 exit ( EXIT_SUCCESS );
22853e4a
KZ
351 case 'r':
352 return;
726f69e2 353 case 's':
7737f698 354 xbsd_print_disklabel (cxt, 1);
726f69e2
KZ
355 break;
356 case 't':
9ffeb235 357 xbsd_change_fstype (cxt);
22853e4a
KZ
358 break;
359 case 'u':
ec10aa67 360 toggle_units(cxt);
726f69e2
KZ
361 break;
362 case 'w':
9ffeb235 363 xbsd_write_disklabel (cxt);
726f69e2 364 break;
22853e4a 365#if !defined (__alpha__)
726f69e2 366 case 'x':
e53ced85 367 xbsd_link_part (cxt);
726f69e2
KZ
368 break;
369#endif
370 default:
39f01b7b 371 print_fdisk_menu(cxt);
726f69e2
KZ
372 break;
373 }
374 }
375}
376
8a95621d 377static int xbsd_delete_part(
9ffeb235
KZ
378 struct fdisk_context *cxt,
379 size_t partnum)
726f69e2 380{
9ffeb235
KZ
381 assert(cxt);
382 assert(cxt->label);
383 assert(fdisk_is_disklabel(cxt, OSF));
384
61c4cb85
DB
385 xbsd_dlabel.d_partitions[partnum].p_size = 0;
386 xbsd_dlabel.d_partitions[partnum].p_offset = 0;
387 xbsd_dlabel.d_partitions[partnum].p_fstype = BSD_FS_UNUSED;
388 if (xbsd_dlabel.d_npartitions == partnum + 1)
389 while (!xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size)
390 xbsd_dlabel.d_npartitions--;
1f5eb51b 391
9ffeb235
KZ
392 cxt->label->nparts_cur = xbsd_dlabel.d_npartitions;
393 fdisk_label_set_changed(cxt->label, 1);
1f5eb51b 394 return 0;
726f69e2
KZ
395}
396
22853e4a 397void
9ffeb235
KZ
398xbsd_print_disklabel (struct fdisk_context *cxt, int show_all)
399{
fd6b7a7f
KZ
400 struct xbsd_disklabel *lp = &xbsd_dlabel;
401 struct xbsd_partition *pp;
726f69e2
KZ
402 FILE *f = stdout;
403 int i, j;
404
22853e4a 405 if (show_all) {
823f0fd1 406 fprintf(f, "# %s:\n", cxt->dev_path);
726f69e2 407 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
7eda085c 408 fprintf(f, _("type: %s\n"), xbsd_dktypenames[lp->d_type]);
726f69e2 409 else
7eda085c
KZ
410 fprintf(f, _("type: %d\n"), lp->d_type);
411 fprintf(f, _("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
412 fprintf(f, _("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
413 fprintf(f, _("flags:"));
726f69e2 414 if (lp->d_flags & BSD_D_REMOVABLE)
7eda085c 415 fprintf(f, _(" removable"));
726f69e2 416 if (lp->d_flags & BSD_D_ECC)
7eda085c 417 fprintf(f, _(" ecc"));
726f69e2 418 if (lp->d_flags & BSD_D_BADSECT)
7eda085c 419 fprintf(f, _(" badsect"));
726f69e2 420 fprintf(f, "\n");
fd6b7a7f
KZ
421 /* On various machines the fields of *lp are short/int/long */
422 /* In order to avoid problems, we cast them all to long. */
7eda085c
KZ
423 fprintf(f, _("bytes/sector: %ld\n"), (long) lp->d_secsize);
424 fprintf(f, _("sectors/track: %ld\n"), (long) lp->d_nsectors);
425 fprintf(f, _("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
426 fprintf(f, _("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
427 fprintf(f, _("cylinders: %ld\n"), (long) lp->d_ncylinders);
428 fprintf(f, _("rpm: %d\n"), lp->d_rpm);
429 fprintf(f, _("interleave: %d\n"), lp->d_interleave);
430 fprintf(f, _("trackskew: %d\n"), lp->d_trackskew);
431 fprintf(f, _("cylinderskew: %d\n"), lp->d_cylskew);
22853e4a
KZ
432 fprintf(f, _("headswitch: %ld\t\t# milliseconds\n"),
433 (long) lp->d_headswitch);
434 fprintf(f, _("track-to-track seek: %ld\t# milliseconds\n"),
435 (long) lp->d_trkseek);
7eda085c 436 fprintf(f, _("drivedata: "));
726f69e2
KZ
437 for (i = NDDATA - 1; i >= 0; i--)
438 if (lp->d_drivedata[i])
439 break;
440 if (i < 0)
441 i = 0;
442 for (j = 0; j <= i; j++)
fd6b7a7f 443 fprintf(f, "%ld ", (long) lp->d_drivedata[j]);
726f69e2 444 }
7eda085c 445 fprintf (f, _("\n%d partitions:\n"), lp->d_npartitions);
22853e4a 446 fprintf (f, _("# start end size fstype [fsize bsize cpg]\n"));
726f69e2
KZ
447 pp = lp->d_partitions;
448 for (i = 0; i < lp->d_npartitions; i++, pp++) {
449 if (pp->p_size) {
ec10aa67 450 if (fdisk_context_use_cylinders(cxt) && lp->d_secpercyl) {
22853e4a
KZ
451 fprintf(f, " %c: %8ld%c %8ld%c %8ld%c ",
452 'a' + i,
453 (long) pp->p_offset / lp->d_secpercyl + 1,
454 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
455 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1)
456 / lp->d_secpercyl,
457 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
458 (long) pp->p_size / lp->d_secpercyl,
459 (pp->p_size % lp->d_secpercyl) ? '*' : ' ');
460 } else {
461 fprintf(f, " %c: %8ld %8ld %8ld ",
462 'a' + i,
463 (long) pp->p_offset,
464 (long) pp->p_offset + pp->p_size - 1,
465 (long) pp->p_size);
466 }
726f69e2 467 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
fd6b7a7f 468 fprintf(f, "%8.8s", xbsd_fstypes[pp->p_fstype].name);
726f69e2
KZ
469 else
470 fprintf(f, "%8x", pp->p_fstype);
22853e4a
KZ
471 switch (pp->p_fstype) {
472 case BSD_FS_UNUSED:
fd6b7a7f
KZ
473 fprintf(f, " %5ld %5ld %5.5s ",
474 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
726f69e2 475 break;
50ea6795 476
726f69e2 477 case BSD_FS_BSDFFS:
fd6b7a7f
KZ
478 fprintf(f, " %5ld %5ld %5d ",
479 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag,
726f69e2
KZ
480 pp->p_cpg);
481 break;
50ea6795 482
726f69e2 483 default:
22853e4a 484 fprintf(f, "%22.22s", "");
726f69e2
KZ
485 break;
486 }
22853e4a 487 fprintf(f, "\n");
726f69e2
KZ
488 }
489 }
490}
491
bddd84e7
KZ
492static unsigned long
493edit_int(struct fdisk_context *cxt, unsigned long def, char *mesg)
726f69e2
KZ
494{
495 do {
496 fputs (mesg, stdout);
bddd84e7
KZ
497 printf (" (%lu): ", def);
498 if (!read_line(cxt, NULL))
726f69e2 499 return def;
bddd84e7
KZ
500 } while (!isdigit (*line_ptr));
501
502 return strtoul(line_ptr, NULL, 10); /* TODO check it! */
50ea6795 503}
726f69e2
KZ
504
505static void
bddd84e7 506xbsd_edit_disklabel(struct fdisk_context *cxt)
726f69e2 507{
fd6b7a7f 508 struct xbsd_disklabel *d;
726f69e2 509
fd6b7a7f 510 d = &xbsd_dlabel;
726f69e2 511
22853e4a 512#if defined (__alpha__) || defined (__ia64__)
bddd84e7
KZ
513 d -> d_secsize = edit_int(cxt, d->d_secsize ,_("bytes/sector"));
514 d -> d_nsectors = edit_int(cxt, d->d_nsectors ,_("sectors/track"));
515 d -> d_ntracks = edit_int(cxt, d->d_ntracks ,_("tracks/cylinder"));
516 d -> d_ncylinders = edit_int(cxt, d->d_ncylinders ,_("cylinders"));
726f69e2
KZ
517#endif
518
519 /* d -> d_secpercyl can be != d -> d_nsectors * d -> d_ntracks */
520 while (1)
521 {
bddd84e7 522 d -> d_secpercyl = edit_int(cxt, (unsigned long) d->d_nsectors * d -> d_ntracks,
7eda085c 523 _("sectors/cylinder"));
726f69e2
KZ
524 if (d -> d_secpercyl <= d -> d_nsectors * d -> d_ntracks)
525 break;
526
7eda085c 527 printf (_("Must be <= sectors/track * tracks/cylinder (default).\n"));
726f69e2 528 }
bddd84e7
KZ
529 d -> d_rpm = (unsigned short) edit_int(cxt, d->d_rpm ,_("rpm"));
530 d -> d_interleave = (unsigned short) edit_int(cxt, d->d_interleave,_("interleave"));
531 d -> d_trackskew = (unsigned short) edit_int(cxt, d->d_trackskew ,_("trackskew"));
532 d -> d_cylskew = (unsigned short) edit_int(cxt, d->d_cylskew ,_("cylinderskew"));
533 d -> d_headswitch = edit_int(cxt, d->d_headswitch ,_("headswitch"));
534 d -> d_trkseek = edit_int(cxt, d->d_trkseek ,_("track-to-track seek"));
726f69e2
KZ
535
536 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
537}
538
539static int
fd6b7a7f 540xbsd_get_bootstrap (char *path, void *ptr, int size)
726f69e2
KZ
541{
542 int fd;
543
544 if ((fd = open (path, O_RDONLY)) < 0)
545 {
546 perror (path);
547 return 0;
548 }
549 if (read (fd, ptr, size) < 0)
550 {
551 perror (path);
552 close (fd);
553 return 0;
554 }
555 printf (" ... %s\n", path);
556 close (fd);
557 return 1;
558}
559
918afd3f 560static int
7737f698 561xbsd_write_bootstrap (struct fdisk_context *cxt)
726f69e2
KZ
562{
563 char *bootdir = BSD_LINUX_BOOTDIR;
7e5fad47 564 char path[sizeof(BSD_LINUX_BOOTDIR) + 1 + 2 + 4]; /* BSD_LINUX_BOOTDIR + / + {sd,wd} + boot */
726f69e2 565 char *dkbasename;
fd6b7a7f 566 struct xbsd_disklabel dl;
726f69e2
KZ
567 char *d, *p, *e;
568 int sector;
569
fd6b7a7f 570 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
726f69e2
KZ
571 dkbasename = "sd";
572 else
573 dkbasename = "wd";
574
c07ebfa1
KZ
575 printf (_("Bootstrap: %sboot -> boot%s (%s): "),
576 dkbasename, dkbasename, dkbasename);
bddd84e7 577 if (read_line(cxt, NULL)) {
726f69e2
KZ
578 line_ptr[strlen (line_ptr)-1] = '\0';
579 dkbasename = line_ptr;
580 }
c07ebfa1 581 snprintf (path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
22853e4a 582 if (!xbsd_get_bootstrap (path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
918afd3f 583 return -1;
726f69e2 584
fd6b7a7f 585 /* We need a backup of the disklabel (xbsd_dlabel might have changed). */
22853e4a 586 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
c0f19ccf 587 memmove (&dl, d, sizeof (struct xbsd_disklabel));
726f69e2
KZ
588
589 /* The disklabel will be overwritten by 0's from bootxx anyway */
56054a79 590 memset (d, 0, sizeof (struct xbsd_disklabel));
726f69e2 591
c07ebfa1 592 snprintf (path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
22853e4a 593 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
fd6b7a7f 594 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
918afd3f 595 return -1;
726f69e2 596
fd6b7a7f 597 e = d + sizeof (struct xbsd_disklabel);
726f69e2 598 for (p=d; p < e; p++)
c07ebfa1 599 if (*p) {
918afd3f
KZ
600 fdisk_warnx(cxt, _("Bootstrap overlaps with disk label!\n"));
601 return -EINVAL;
726f69e2
KZ
602 }
603
c0f19ccf 604 memmove (d, &dl, sizeof (struct xbsd_disklabel));
726f69e2 605
364cda48 606#if defined (__powerpc__) || defined (__hppa__)
5c36a0eb 607 sector = 0;
726f69e2
KZ
608#elif defined (__alpha__)
609 sector = 0;
22853e4a
KZ
610 alpha_bootblock_checksum (disklabelbuffer);
611#else
612 sector = get_start_sect(xbsd_part);
726f69e2
KZ
613#endif
614
918afd3f
KZ
615 if (lseek (cxt->dev_fd, (off_t) sector * SECTOR_SIZE, SEEK_SET) == -1) {
616 fdisk_warn(cxt, _("seek failed: %s"), cxt->dev_path);
617 return -errno;
618 }
619 if (BSD_BBSIZE != write (cxt->dev_fd, disklabelbuffer, BSD_BBSIZE)) {
620 fdisk_warn(cxt, _("write failed: %s"), cxt->dev_path);
621 return -errno;
622 }
726f69e2 623
823f0fd1 624 printf (_("Bootstrap installed on %s.\n"), cxt->dev_path);
726f69e2 625 sync_disks ();
918afd3f 626 return 0;
726f69e2
KZ
627}
628
02460b8a 629/* TODO: remove this, use regular change_partition_type() in fdisk.c */
9ffeb235 630static void xbsd_change_fstype (struct fdisk_context *cxt)
726f69e2
KZ
631{
632 int i;
559d921e 633 struct fdisk_parttype *t;
726f69e2 634
9ffeb235
KZ
635 assert(cxt);
636 assert(cxt->label);
637 assert(fdisk_is_disklabel(cxt, OSF));
638
bddd84e7 639 i = xbsd_get_part_index (cxt, xbsd_dlabel.d_npartitions);
559d921e
KZ
640 t = read_partition_type(cxt);
641
642 if (t) {
643 xbsd_dlabel.d_partitions[i].p_fstype = t->type;
644 fdisk_free_parttype(t);
9ffeb235 645 fdisk_label_set_changed(cxt->label, 1);
559d921e 646 }
726f69e2
KZ
647}
648
649static int
bddd84e7 650xbsd_get_part_index(struct fdisk_context *cxt, int max)
726f69e2 651{
eb63b9b8 652 char prompt[256];
726f69e2
KZ
653 char l;
654
c07ebfa1 655 snprintf (prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
726f69e2 656 do
bddd84e7 657 l = tolower(read_char(cxt, prompt));
726f69e2
KZ
658 while (l < 'a' || l > 'a' + max - 1);
659 return l - 'a';
660}
661
662static int
9ffeb235
KZ
663xbsd_check_new_partition(struct fdisk_context *cxt, int *i)
664{
63cccae4
KZ
665 /* room for more? various BSD flavours have different maxima */
666 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
667 int t;
726f69e2 668
63cccae4
KZ
669 for (t = 0; t < BSD_MAXPARTITIONS; t++)
670 if (xbsd_dlabel.d_partitions[t].p_size == 0)
671 break;
726f69e2 672
63cccae4
KZ
673 if (t == BSD_MAXPARTITIONS) {
674 fprintf (stderr, _("The maximum number of partitions "
675 "has been created\n"));
8254c3a5 676 return -EINVAL;
63cccae4
KZ
677 }
678 }
726f69e2 679
bddd84e7 680 *i = xbsd_get_part_index(cxt, BSD_MAXPARTITIONS);
63cccae4
KZ
681
682 if (*i >= xbsd_dlabel.d_npartitions)
683 xbsd_dlabel.d_npartitions = (*i) + 1;
684
685 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
686 fprintf (stderr, _("This partition already exists.\n"));
8254c3a5 687 return -EINVAL;
63cccae4
KZ
688 }
689
8254c3a5 690 return 0;
726f69e2
KZ
691}
692
95961ee2 693static unsigned short
63cccae4 694xbsd_dkcksum (struct xbsd_disklabel *lp) {
95961ee2
JW
695 unsigned short *start, *end;
696 unsigned short sum = 0;
50ea6795 697
95961ee2
JW
698 start = (unsigned short *) lp;
699 end = (unsigned short *) &lp->d_partitions[lp->d_npartitions];
63cccae4
KZ
700 while (start < end)
701 sum ^= *start++;
702 return sum;
726f69e2
KZ
703}
704
705static int
7737f698 706xbsd_initlabel (struct fdisk_context *cxt, struct partition *p, struct xbsd_disklabel *d,
e99da659 707 int pindex __attribute__((__unused__))) {
63cccae4 708 struct xbsd_partition *pp;
726f69e2 709
56054a79 710 memset (d, 0, sizeof (struct xbsd_disklabel));
726f69e2 711
63cccae4 712 d -> d_magic = BSD_DISKMAGIC;
726f69e2 713
823f0fd1 714 if (strncmp (cxt->dev_path, "/dev/sd", 7) == 0)
63cccae4
KZ
715 d -> d_type = BSD_DTYPE_SCSI;
716 else
717 d -> d_type = BSD_DTYPE_ST506;
726f69e2
KZ
718
719#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
63cccae4 720 d -> d_subtype = BSD_DSTYPE_INDOSPART & pindex;
726f69e2
KZ
721#endif
722
22853e4a 723#if !defined (__alpha__)
63cccae4 724 d -> d_flags = BSD_D_DOSPART;
726f69e2 725#else
63cccae4 726 d -> d_flags = 0;
726f69e2 727#endif
63cccae4 728 d -> d_secsize = SECTOR_SIZE; /* bytes/sector */
24cd580b
DB
729 d -> d_nsectors = cxt->geom.sectors; /* sectors/track */
730 d -> d_ntracks = cxt->geom.heads; /* tracks/cylinder (heads) */
731 d -> d_ncylinders = cxt->geom.cylinders;
732 d -> d_secpercyl = cxt->geom.sectors * cxt->geom.heads;/* sectors/cylinder */
63cccae4
KZ
733 if (d -> d_secpercyl == 0)
734 d -> d_secpercyl = 1; /* avoid segfaults */
735 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
736
737 d -> d_rpm = 3600;
738 d -> d_interleave = 1;
739 d -> d_trackskew = 0;
740 d -> d_cylskew = 0;
741 d -> d_headswitch = 0;
742 d -> d_trkseek = 0;
743
744 d -> d_magic2 = BSD_DISKMAGIC;
745 d -> d_bbsize = BSD_BBSIZE;
746 d -> d_sbsize = BSD_SBSIZE;
726f69e2 747
22853e4a 748#if !defined (__alpha__)
63cccae4
KZ
749 d -> d_npartitions = 4;
750 pp = &d -> d_partitions[2]; /* Partition C should be
751 the NetBSD partition */
752 pp -> p_offset = get_start_sect(p);
753 pp -> p_size = get_nr_sects(p);
754 pp -> p_fstype = BSD_FS_UNUSED;
755 pp = &d -> d_partitions[3]; /* Partition D should be
756 the whole disk */
757 pp -> p_offset = 0;
758 pp -> p_size = d -> d_secperunit;
759 pp -> p_fstype = BSD_FS_UNUSED;
726f69e2 760#elif defined (__alpha__)
63cccae4
KZ
761 d -> d_npartitions = 3;
762 pp = &d -> d_partitions[2]; /* Partition C should be
763 the whole disk */
764 pp -> p_offset = 0;
765 pp -> p_size = d -> d_secperunit;
50ea6795 766 pp -> p_fstype = BSD_FS_UNUSED;
726f69e2
KZ
767#endif
768
63cccae4 769 return 1;
726f69e2
KZ
770}
771
63cccae4
KZ
772/*
773 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
774 * If it has the right magic, return 1.
775 */
726f69e2 776static int
7737f698 777xbsd_readlabel (struct fdisk_context *cxt, struct partition *p, struct xbsd_disklabel *d)
726f69e2 778{
63cccae4 779 int t, sector;
726f69e2 780
acf263d5
KZ
781 assert(cxt);
782 assert(cxt->label);
783
63cccae4 784 /* p is used only to get the starting sector */
22853e4a 785#if !defined (__alpha__)
63cccae4 786 sector = (p ? get_start_sect(p) : 0);
726f69e2 787#elif defined (__alpha__)
63cccae4 788 sector = 0;
726f69e2
KZ
789#endif
790
823f0fd1 791 if (lseek (cxt->dev_fd, (off_t) sector * SECTOR_SIZE, SEEK_SET) == -1)
bddd84e7 792 return 0;
823f0fd1 793 if (BSD_BBSIZE != read (cxt->dev_fd, disklabelbuffer, BSD_BBSIZE))
bddd84e7 794 return 0;
726f69e2 795
c0f19ccf
DM
796 memmove (d,
797 &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
798 sizeof (struct xbsd_disklabel));
726f69e2 799
63cccae4
KZ
800 if (d -> d_magic != BSD_DISKMAGIC || d -> d_magic2 != BSD_DISKMAGIC)
801 return 0;
726f69e2 802
63cccae4
KZ
803 for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++) {
804 d -> d_partitions[t].p_size = 0;
805 d -> d_partitions[t].p_offset = 0;
50ea6795 806 d -> d_partitions[t].p_fstype = BSD_FS_UNUSED;
63cccae4
KZ
807 }
808
809 if (d -> d_npartitions > BSD_MAXPARTITIONS)
810 fprintf (stderr, _("Warning: too many partitions "
811 "(%d, maximum is %d).\n"),
812 d -> d_npartitions, BSD_MAXPARTITIONS);
acf263d5
KZ
813
814 cxt->label->nparts_cur = d->d_npartitions;
815 cxt->label->nparts_max = BSD_MAXPARTITIONS;
63cccae4 816 return 1;
726f69e2
KZ
817}
818
819static int
7737f698 820xbsd_writelabel (struct fdisk_context *cxt, struct partition *p, struct xbsd_disklabel *d)
726f69e2 821{
df1dddf9 822 unsigned int sector;
726f69e2 823
364cda48 824#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
2b6fc908 825 sector = get_start_sect(p) + BSD_LABELSECTOR;
364cda48 826#else
726f69e2
KZ
827 sector = BSD_LABELSECTOR;
828#endif
829
830 d -> d_checksum = 0;
fd6b7a7f 831 d -> d_checksum = xbsd_dkcksum (d);
726f69e2
KZ
832
833 /* This is necessary if we want to write the bootstrap later,
834 otherwise we'd write the old disklabel with the bootstrap.
835 */
c0f19ccf
DM
836 memmove (&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET], d,
837 sizeof (struct xbsd_disklabel));
726f69e2
KZ
838
839#if defined (__alpha__) && BSD_LABELSECTOR == 0
22853e4a 840 alpha_bootblock_checksum (disklabelbuffer);
918afd3f
KZ
841 if (lseek (cxt->dev_fd, (off_t) 0, SEEK_SET) == -1) {
842 fdisk_warn(cxt, _("seek failed: %d"), cxt->dev_path);
843 return -errno;
844 }
845 if (BSD_BBSIZE != write (cxt->dev_fd, disklabelbuffer, BSD_BBSIZE)) {
846 fdisk_warn(cxt, _("write failed: %d"), cxt->dev_path);
847 return -errno;
848 }
726f69e2 849#else
823f0fd1 850 if (lseek (cxt->dev_fd, (off_t) sector * SECTOR_SIZE + BSD_LABELOFFSET,
918afd3f
KZ
851 SEEK_SET) == -1) {
852 fdisk_warn(cxt, _("seek failed: %d"), cxt->dev_path);
853 return -errno;
854 }
855 if (sizeof (struct xbsd_disklabel) != write (cxt->dev_fd, d, sizeof (struct xbsd_disklabel))) {
856 fdisk_warn(cxt, _("write failed: %d"), cxt->dev_path);
857 return -errno;
858 }
726f69e2
KZ
859#endif
860
861 sync_disks ();
918afd3f 862 return 0;
726f69e2
KZ
863}
864
865static void
866sync_disks (void)
867{
7eda085c 868 printf (_("\nSyncing disks.\n"));
726f69e2
KZ
869 sync ();
870 sleep (4);
871}
872
22853e4a 873#if !defined (__alpha__)
726f69e2 874static int
fd6b7a7f 875xbsd_translate_fstype (int linux_type)
726f69e2
KZ
876{
877 switch (linux_type)
878 {
879 case 0x01: /* DOS 12-bit FAT */
880 case 0x04: /* DOS 16-bit <32M */
881 case 0x06: /* DOS 16-bit >=32M */
882 case 0xe1: /* DOS access */
883 case 0xe3: /* DOS R/O */
884 case 0xf2: /* DOS secondary */
885 return BSD_FS_MSDOS;
886 case 0x07: /* OS/2 HPFS */
887 return BSD_FS_HPFS;
888 default:
889 return BSD_FS_OTHER;
890 }
891}
892
e09435aa
KZ
893/*
894 * link partition from parent (DOS) to nested BSD partition table
895 */
726f69e2 896static void
e53ced85 897xbsd_link_part (struct fdisk_context *cxt)
726f69e2 898{
e09435aa
KZ
899 size_t k;
900 int i;
901 struct partition *p;
726f69e2 902
b4fb2a61
KZ
903 if (!cxt->parent)
904 return; /* not nested PT */
905
e09435aa
KZ
906 if (fdisk_ask_partnum(cxt->parent, &k, FALSE))
907 return;
726f69e2 908
e09435aa
KZ
909 if (xbsd_check_new_partition(cxt, &i))
910 return;
726f69e2 911
e09435aa 912 p = get_part_table(k);
22853e4a 913
e09435aa
KZ
914 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
915 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
916 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
726f69e2
KZ
917}
918#endif
919
920#if defined (__alpha__)
726f69e2 921
eb63b9b8 922#if !defined(__GLIBC__)
2b6fc908
KZ
923typedef unsigned long long u_int64_t;
924#endif
925
726f69e2
KZ
926void
927alpha_bootblock_checksum (char *boot)
928{
929 u_int64_t *dp, sum;
930 int i;
50ea6795 931
726f69e2
KZ
932 dp = (u_int64_t *)boot;
933 sum = 0;
934 for (i = 0; i < 63; i++)
935 sum += dp[i];
936 dp[63] = sum;
937}
938#endif /* __alpha__ */
b8855c86 939
8a95621d
KZ
940static struct fdisk_parttype *xbsd_get_parttype(
941 struct fdisk_context *cxt,
9ffeb235 942 size_t n)
010186f2
KZ
943{
944 struct fdisk_parttype *t;
945
9ffeb235
KZ
946 assert(cxt);
947 assert(cxt->label);
948 assert(fdisk_is_disklabel(cxt, OSF));
949
010186f2
KZ
950 if (n >= xbsd_dlabel.d_npartitions)
951 return NULL;
952
953 t = fdisk_get_parttype_from_code(cxt, xbsd_dlabel.d_partitions[n].p_fstype);
954 if (!t)
955 t = fdisk_new_unknown_parttype(xbsd_dlabel.d_partitions[n].p_fstype, NULL);
956 return t;
957}
958
8a95621d 959static int xbsd_set_parttype(
9ffeb235
KZ
960 struct fdisk_context *cxt,
961 size_t partnum,
8a95621d 962 struct fdisk_parttype *t)
02460b8a
KZ
963{
964 struct xbsd_partition *p;
965
9ffeb235
KZ
966 assert(cxt);
967 assert(cxt->label);
968 assert(fdisk_is_disklabel(cxt, OSF));
969
02460b8a
KZ
970 if (partnum >= xbsd_dlabel.d_npartitions || !t || t->type > UINT8_MAX)
971 return -EINVAL;
972
973 p = &xbsd_dlabel.d_partitions[partnum];
974 if (t->type == p->p_fstype)
975 return 0;
976
977 p->p_fstype = t->type;
9ffeb235 978 fdisk_label_set_changed(cxt->label, 1);
02460b8a
KZ
979 return 0;
980}
981
0c5d095e 982static const struct fdisk_label_operations bsd_operations =
b8855c86 983{
0c5d095e
KZ
984 .probe = osf_probe_label,
985 .write = xbsd_write_disklabel,
986 .create = xbsd_create_disklabel,
987 .part_add = xbsd_add_part,
988 .part_delete = xbsd_delete_part,
989 .part_get_type = xbsd_get_parttype,
990 .part_set_type = xbsd_set_parttype
b8855c86 991};
0c5d095e
KZ
992
993
994/*
995 * allocates BSD label driver
996 */
997struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt)
998{
999 struct fdisk_label *lb;
1000 struct fdisk_bsd_label *bsd;
1001
1002 assert(cxt);
1003
1004 bsd = calloc(1, sizeof(*bsd));
1005 if (!bsd)
1006 return NULL;
1007
1008 /* initialize generic part of the driver */
1009 lb = (struct fdisk_label *) bsd;
1010 lb->name = "bsd";
53b422ab 1011 lb->id = FDISK_DISKLABEL_OSF;
0c5d095e
KZ
1012 lb->op = &bsd_operations;
1013 lb->parttypes = xbsd_fstypes;
1014 lb->nparttypes = ARRAY_SIZE(xbsd_fstypes);
1015
baa7cccc
KZ
1016 /* don't ask for partition number for op->part_add() */
1017 lb->flags = FDISK_LABEL_FL_ADDPART_NOPARTNO;
1018
0c5d095e
KZ
1019 return lb;
1020}