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:
5
6   Copyright (c) 1987, 1988 Regents of the University of California.
7   All rights reserved.
8
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:
19  	This product includes software developed by the University of
20  	California, Berkeley and its contributors.
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.
24
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.
36
37   Changes:
38   19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
39
40   20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
41   support for OSF/1 disklabels on Alpha.
42   Also fixed unaligned accesses in alpha_bootblock_checksum()
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>
53#include "nls.h"
54
55#include <sys/ioctl.h>
56#include <sys/param.h>
57
58#include "common.h"
59#include "fdisk.h"
60#define FREEBSD_PARTITION	0xa5
61#define NETBSD_PARTITION	0xa9
62#define DKTYPENAMES
63#include "fdiskbsdlabel.h"
64
65static void xbsd_delete_part (void);
66static void xbsd_new_part (void);
67static void xbsd_write_disklabel (void);
68static int xbsd_create_disklabel (void);
69static void xbsd_edit_disklabel (void);
70static void xbsd_write_bootstrap (void);
71static void xbsd_change_fstype (void);
72static int xbsd_get_part_index (int max);
73static int xbsd_check_new_partition (int *i);
74static void xbsd_list_types (void);
75static u_short xbsd_dkcksum (struct xbsd_disklabel *lp);
76static int xbsd_initlabel  (struct partition *p, struct xbsd_disklabel *d,
77			    int pindex);
78static int xbsd_readlabel  (struct partition *p, struct xbsd_disklabel *d);
79static int xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d);
80static void sync_disks (void);
81
82#if defined (__alpha__)
83void alpha_bootblock_checksum (char *boot);
84#endif
85
86#if !defined (__alpha__)
87static int xbsd_translate_fstype (int linux_type);
88static void xbsd_link_part (void);
89static struct partition *xbsd_part;
90static int xbsd_part_index;
91#endif
92
93#if defined (__alpha__)
94/* We access this through a u_int64_t * when checksumming */
95static char disklabelbuffer[BSD_BBSIZE] __attribute__((aligned(8)));
96#else
97static char disklabelbuffer[BSD_BBSIZE];
98#endif
99
100static struct xbsd_disklabel xbsd_dlabel;
101
102#define bsd_cround(n) \
103	(display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
104
105/*
106 * Test whether the whole disk has BSD disk label magic.
107 *
108 * Note: often reformatting with DOS-type label leaves the BSD magic,
109 * so this does not mean that there is a BSD disk label.
110 */
111int
112check_osf_label(void) {
113	if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
114		return 0;
115	return 1;
116}
117
118int
119btrydev (char * dev) {
120	if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
121		return -1;
122	printf(_("\nBSD label for device: %s\n"), dev);
123	xbsd_print_disklabel (0);
124	return 0;
125}
126
127static void
128bmenu (void) {
129  puts (_("Command action"));
130  puts (_("   d   delete a BSD partition"));
131  puts (_("   e   edit drive data"));
132  puts (_("   i   install bootstrap"));
133  puts (_("   l   list known filesystem types"));
134  puts (_("   m   print this menu"));
135  puts (_("   n   add a new BSD partition"));
136  puts (_("   p   print BSD partition table"));
137  puts (_("   q   quit without saving changes"));
138  puts (_("   r   return to main menu"));
139  puts (_("   s   show complete disklabel"));
140  puts (_("   t   change a partition's filesystem id"));
141  puts (_("   u   change units (cylinders/sectors)"));
142  puts (_("   w   write disklabel to disk"));
143#if !defined (__alpha__)
144  puts (_("   x   link BSD partition to non-BSD partition"));
145#endif
146}
147
148#if !defined (__alpha__)
149static int
150hidden(int type) {
151	return type ^ 0x10;
152}
153
154static int
155is_bsd_partition_type(int type) {
156	return (type == FREEBSD_PARTITION ||
157		type == hidden(FREEBSD_PARTITION) ||
158		type == NETBSD_PARTITION ||
159		type == hidden(NETBSD_PARTITION));
160}
161#endif
162
163void
164bselect (void) {
165#if !defined (__alpha__)
166  int t, ss;
167  struct partition *p;
168
169  for (t=0; t<4; t++) {
170    p = get_part_table(t);
171    if (p && is_bsd_partition_type(p->sys_ind)) {
172      xbsd_part = p;
173      xbsd_part_index = t;
174      ss = get_start_sect(xbsd_part);
175      if (ss == 0) {
176	fprintf (stderr, _("Partition %s has invalid starting sector 0.\n"),
177		 partname(disk_device, t+1, 0));
178	return;
179      }
180      printf (_("Reading disklabel of %s at sector %d.\n"),
181	      partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
182      if (xbsd_readlabel (xbsd_part, &xbsd_dlabel) == 0)
183	if (xbsd_create_disklabel () == 0)
184	  return;
185      break;
186    }
187  }
188
189  if (t == 4) {
190    printf (_("There is no *BSD partition on %s.\n"), disk_device);
191    return;
192  }
193
194#elif defined (__alpha__)
195
196  if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
197    if (xbsd_create_disklabel () == 0)
198      exit ( EXIT_SUCCESS );
199
200#endif
201
202  while (1) {
203    putchar ('\n');
204    switch (tolower (read_char (_("BSD disklabel command (m for help): ")))) {
205      case 'd':
206	xbsd_delete_part ();
207	break;
208      case 'e':
209	xbsd_edit_disklabel ();
210	break;
211      case 'i':
212	xbsd_write_bootstrap ();
213	break;
214      case 'l':
215	xbsd_list_types ();
216	break;
217      case 'n':
218	xbsd_new_part ();
219	break;
220      case 'p':
221	xbsd_print_disklabel (0);
222	break;
223      case 'q':
224	close (fd);
225	exit ( EXIT_SUCCESS );
226      case 'r':
227	return;
228      case 's':
229	xbsd_print_disklabel (1);
230	break;
231      case 't':
232	xbsd_change_fstype ();
233	break;
234      case 'u':
235	change_units();
236	break;
237      case 'w':
238	xbsd_write_disklabel ();
239	break;
240#if !defined (__alpha__)
241      case 'x':
242	xbsd_link_part ();
243	break;
244#endif
245      default:
246	bmenu ();
247	break;
248    }
249  }
250}
251
252static void
253xbsd_delete_part (void)
254{
255  int i;
256
257  i = xbsd_get_part_index (xbsd_dlabel.d_npartitions);
258  xbsd_dlabel.d_partitions[i].p_size   = 0;
259  xbsd_dlabel.d_partitions[i].p_offset = 0;
260  xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
261  if (xbsd_dlabel.d_npartitions == i + 1)
262    while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
263      xbsd_dlabel.d_npartitions--;
264}
265
266static void
267xbsd_new_part (void)
268{
269  unsigned int begin, end;
270  char mesg[256];
271  int i;
272
273  if (!xbsd_check_new_partition (&i))
274    return;
275
276#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
277  begin = get_start_sect(xbsd_part);
278  end = begin + get_nr_sects(xbsd_part) - 1;
279#else
280  begin = 0;
281  end = xbsd_dlabel.d_secperunit - 1;
282#endif
283
284  snprintf (mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
285  begin = read_int (bsd_cround (begin), bsd_cround (begin), bsd_cround (end),
286		    0, mesg);
287
288  if (display_in_cyl_units)
289    begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
290
291  snprintf (mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
292	   str_units(SINGULAR));
293  end = read_int (bsd_cround (begin), bsd_cround (end), bsd_cround (end),
294		  bsd_cround (begin), mesg);
295
296  if (display_in_cyl_units)
297    end = end * xbsd_dlabel.d_secpercyl - 1;
298
299  xbsd_dlabel.d_partitions[i].p_size   = end - begin + 1;
300  xbsd_dlabel.d_partitions[i].p_offset = begin;
301  xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
302}
303
304void
305xbsd_print_disklabel (int show_all) {
306  struct xbsd_disklabel *lp = &xbsd_dlabel;
307  struct xbsd_partition *pp;
308  FILE *f = stdout;
309  int i, j;
310
311  if (show_all) {
312#if defined (__alpha__)
313    fprintf(f, "# %s:\n", disk_device);
314#else
315    fprintf(f, "# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
316#endif
317    if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
318      fprintf(f, _("type: %s\n"), xbsd_dktypenames[lp->d_type]);
319    else
320      fprintf(f, _("type: %d\n"), lp->d_type);
321    fprintf(f, _("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
322    fprintf(f, _("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
323    fprintf(f, _("flags:"));
324    if (lp->d_flags & BSD_D_REMOVABLE)
325      fprintf(f, _(" removable"));
326    if (lp->d_flags & BSD_D_ECC)
327      fprintf(f, _(" ecc"));
328    if (lp->d_flags & BSD_D_BADSECT)
329      fprintf(f, _(" badsect"));
330    fprintf(f, "\n");
331    /* On various machines the fields of *lp are short/int/long */
332    /* In order to avoid problems, we cast them all to long. */
333    fprintf(f, _("bytes/sector: %ld\n"), (long) lp->d_secsize);
334    fprintf(f, _("sectors/track: %ld\n"), (long) lp->d_nsectors);
335    fprintf(f, _("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
336    fprintf(f, _("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
337    fprintf(f, _("cylinders: %ld\n"), (long) lp->d_ncylinders);
338    fprintf(f, _("rpm: %d\n"), lp->d_rpm);
339    fprintf(f, _("interleave: %d\n"), lp->d_interleave);
340    fprintf(f, _("trackskew: %d\n"), lp->d_trackskew);
341    fprintf(f, _("cylinderskew: %d\n"), lp->d_cylskew);
342    fprintf(f, _("headswitch: %ld\t\t# milliseconds\n"),
343	    (long) lp->d_headswitch);
344    fprintf(f, _("track-to-track seek: %ld\t# milliseconds\n"),
345	    (long) lp->d_trkseek);
346    fprintf(f, _("drivedata: "));
347    for (i = NDDATA - 1; i >= 0; i--)
348      if (lp->d_drivedata[i])
349	break;
350    if (i < 0)
351      i = 0;
352    for (j = 0; j <= i; j++)
353      fprintf(f, "%ld ", (long) lp->d_drivedata[j]);
354  }
355  fprintf (f, _("\n%d partitions:\n"), lp->d_npartitions);
356  fprintf (f, _("#       start       end      size     fstype   [fsize bsize   cpg]\n"));
357  pp = lp->d_partitions;
358  for (i = 0; i < lp->d_npartitions; i++, pp++) {
359    if (pp->p_size) {
360      if (display_in_cyl_units && lp->d_secpercyl) {
361	fprintf(f, "  %c: %8ld%c %8ld%c %8ld%c  ",
362		'a' + i,
363		(long) pp->p_offset / lp->d_secpercyl + 1,
364		(pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
365		(long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1)
366			/ lp->d_secpercyl,
367		((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
368		(long) pp->p_size / lp->d_secpercyl,
369		(pp->p_size % lp->d_secpercyl) ? '*' : ' ');
370      } else {
371	fprintf(f, "  %c: %8ld  %8ld  %8ld   ",
372		'a' + i,
373		(long) pp->p_offset,
374		(long) pp->p_offset + pp->p_size - 1,
375		(long) pp->p_size);
376      }
377      if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
378	fprintf(f, "%8.8s", xbsd_fstypes[pp->p_fstype].name);
379      else
380	fprintf(f, "%8x", pp->p_fstype);
381      switch (pp->p_fstype) {
382	case BSD_FS_UNUSED:
383	  fprintf(f, "    %5ld %5ld %5.5s ",
384		  (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
385	  break;
386
387	case BSD_FS_BSDFFS:
388	  fprintf(f, "    %5ld %5ld %5d ",
389		  (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag,
390		  pp->p_cpg);
391	  break;
392
393	default:
394	  fprintf(f, "%22.22s", "");
395	  break;
396      }
397      fprintf(f, "\n");
398    }
399  }
400}
401
402static void
403xbsd_write_disklabel (void) {
404#if defined (__alpha__)
405	printf (_("Writing disklabel to %s.\n"), disk_device);
406	xbsd_writelabel (NULL, &xbsd_dlabel);
407#else
408	printf (_("Writing disklabel to %s.\n"),
409		partname(disk_device, xbsd_part_index+1, 0));
410	xbsd_writelabel (xbsd_part, &xbsd_dlabel);
411#endif
412	reread_partition_table(0);	/* no exit yet */
413}
414
415static int
416xbsd_create_disklabel (void) {
417	char c;
418
419#if defined (__alpha__)
420	fprintf (stderr, _("%s contains no disklabel.\n"), disk_device);
421#else
422	fprintf (stderr, _("%s contains no disklabel.\n"),
423		 partname(disk_device, xbsd_part_index+1, 0));
424#endif
425
426	while (1) {
427		c = read_char (_("Do you want to create a disklabel? (y/n) "));
428		if (tolower(c) == 'y') {
429			if (xbsd_initlabel (
430#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
431    defined (__s390__) || defined (__s390x__)
432				NULL, &xbsd_dlabel, 0
433#else
434				xbsd_part, &xbsd_dlabel, xbsd_part_index
435#endif
436				) == 1) {
437				xbsd_print_disklabel (1);
438				return 1;
439			} else
440				return 0;
441		} else if (c == 'n')
442			return 0;
443	}
444}
445
446static int
447edit_int (int def, char *mesg)
448{
449  do {
450    fputs (mesg, stdout);
451    printf (" (%d): ", def);
452    if (!read_line ())
453      return def;
454  }
455  while (!isdigit (*line_ptr));
456  return atoi (line_ptr);
457}
458
459static void
460xbsd_edit_disklabel (void)
461{
462  struct xbsd_disklabel *d;
463
464  d = &xbsd_dlabel;
465
466#if defined (__alpha__) || defined (__ia64__)
467  d -> d_secsize    = (u_long) edit_int ((u_long) d -> d_secsize     ,_("bytes/sector"));
468  d -> d_nsectors   = (u_long) edit_int ((u_long) d -> d_nsectors    ,_("sectors/track"));
469  d -> d_ntracks    = (u_long) edit_int ((u_long) d -> d_ntracks     ,_("tracks/cylinder"));
470  d -> d_ncylinders = (u_long) edit_int ((u_long) d -> d_ncylinders  ,_("cylinders"));
471#endif
472
473  /* d -> d_secpercyl can be != d -> d_nsectors * d -> d_ntracks */
474  while (1)
475  {
476    d -> d_secpercyl = (u_long) edit_int ((u_long) d -> d_nsectors * d -> d_ntracks,
477					  _("sectors/cylinder"));
478    if (d -> d_secpercyl <= d -> d_nsectors * d -> d_ntracks)
479      break;
480
481    printf (_("Must be <= sectors/track * tracks/cylinder (default).\n"));
482  }
483  d -> d_rpm        = (u_short) edit_int ((u_short) d -> d_rpm       ,_("rpm"));
484  d -> d_interleave = (u_short) edit_int ((u_short) d -> d_interleave,_("interleave"));
485  d -> d_trackskew  = (u_short) edit_int ((u_short) d -> d_trackskew ,_("trackskew"));
486  d -> d_cylskew    = (u_short) edit_int ((u_short) d -> d_cylskew   ,_("cylinderskew"));
487  d -> d_headswitch = (u_long) edit_int ((u_long) d -> d_headswitch  ,_("headswitch"));
488  d -> d_trkseek    = (u_long) edit_int ((u_long) d -> d_trkseek     ,_("track-to-track seek"));
489
490  d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
491}
492
493static int
494xbsd_get_bootstrap (char *path, void *ptr, int size)
495{
496  int fd;
497
498  if ((fd = open (path, O_RDONLY)) < 0)
499  {
500    perror (path);
501    return 0;
502  }
503  if (read (fd, ptr, size) < 0)
504  {
505    perror (path);
506    close (fd);
507    return 0;
508  }
509  printf (" ... %s\n", path);
510  close (fd);
511  return 1;
512}
513
514static void
515xbsd_write_bootstrap (void)
516{
517  char *bootdir = BSD_LINUX_BOOTDIR;
518  char path[MAXPATHLEN];
519  char *dkbasename;
520  struct xbsd_disklabel dl;
521  char *d, *p, *e;
522  int sector;
523
524  if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
525    dkbasename = "sd";
526  else
527    dkbasename = "wd";
528
529  printf (_("Bootstrap: %sboot -> boot%s (%s): "),
530	  dkbasename, dkbasename, dkbasename);
531  if (read_line ()) {
532    line_ptr[strlen (line_ptr)-1] = '\0';
533    dkbasename = line_ptr;
534  }
535  snprintf (path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
536  if (!xbsd_get_bootstrap (path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
537    return;
538
539  /* We need a backup of the disklabel (xbsd_dlabel might have changed). */
540  d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
541  bcopy (d, &dl, sizeof (struct xbsd_disklabel));
542
543  /* The disklabel will be overwritten by 0's from bootxx anyway */
544  bzero (d, sizeof (struct xbsd_disklabel));
545
546  snprintf (path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
547  if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
548			  (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
549    return;
550
551  e = d + sizeof (struct xbsd_disklabel);
552  for (p=d; p < e; p++)
553    if (*p) {
554      fprintf (stderr, _("Bootstrap overlaps with disk label!\n"));
555      exit ( EXIT_FAILURE );
556    }
557
558  bcopy (&dl, d, sizeof (struct xbsd_disklabel));
559
560#if defined (__powerpc__) || defined (__hppa__)
561  sector = 0;
562#elif defined (__alpha__)
563  sector = 0;
564  alpha_bootblock_checksum (disklabelbuffer);
565#else
566  sector = get_start_sect(xbsd_part);
567#endif
568
569  if (lseek (fd, (off_t) sector * SECTOR_SIZE, SEEK_SET) == -1)
570    fatal (unable_to_seek);
571  if (BSD_BBSIZE != write (fd, disklabelbuffer, BSD_BBSIZE))
572    fatal (unable_to_write);
573
574#if defined (__alpha__)
575  printf (_("Bootstrap installed on %s.\n"), disk_device);
576#else
577  printf (_("Bootstrap installed on %s.\n"),
578    partname (disk_device, xbsd_part_index+1, 0));
579#endif
580
581  sync_disks ();
582}
583
584static void
585xbsd_change_fstype (void)
586{
587  int i;
588
589  i = xbsd_get_part_index (xbsd_dlabel.d_npartitions);
590  xbsd_dlabel.d_partitions[i].p_fstype = read_hex (xbsd_fstypes);
591}
592
593static int
594xbsd_get_part_index (int max)
595{
596  char prompt[256];
597  char l;
598
599  snprintf (prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
600  do
601     l = tolower (read_char (prompt));
602  while (l < 'a' || l > 'a' + max - 1);
603  return l - 'a';
604}
605
606static int
607xbsd_check_new_partition (int *i) {
608
609	/* room for more? various BSD flavours have different maxima */
610	if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
611		int t;
612
613		for (t = 0; t < BSD_MAXPARTITIONS; t++)
614			if (xbsd_dlabel.d_partitions[t].p_size == 0)
615				break;
616
617		if (t == BSD_MAXPARTITIONS) {
618			fprintf (stderr, _("The maximum number of partitions "
619					   "has been created\n"));
620			return 0;
621		}
622	}
623
624	*i = xbsd_get_part_index (BSD_MAXPARTITIONS);
625
626	if (*i >= xbsd_dlabel.d_npartitions)
627		xbsd_dlabel.d_npartitions = (*i) + 1;
628
629	if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
630		fprintf (stderr, _("This partition already exists.\n"));
631		return 0;
632	}
633
634	return 1;
635}
636
637static void
638xbsd_list_types (void) {
639	list_types (xbsd_fstypes);
640}
641
642static u_short
643xbsd_dkcksum (struct xbsd_disklabel *lp) {
644	u_short *start, *end;
645	u_short sum = 0;
646
647	start = (u_short *) lp;
648	end = (u_short *) &lp->d_partitions[lp->d_npartitions];
649	while (start < end)
650		sum ^= *start++;
651	return sum;
652}
653
654static int
655xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex) {
656	struct xbsd_partition *pp;
657	struct geom g;
658
659	get_geometry (fd, &g);
660	bzero (d, sizeof (struct xbsd_disklabel));
661
662	d -> d_magic = BSD_DISKMAGIC;
663
664	if (strncmp (disk_device, "/dev/sd", 7) == 0)
665		d -> d_type = BSD_DTYPE_SCSI;
666	else
667		d -> d_type = BSD_DTYPE_ST506;
668
669#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
670	d -> d_subtype = BSD_DSTYPE_INDOSPART & pindex;
671#endif
672
673#if !defined (__alpha__)
674	d -> d_flags = BSD_D_DOSPART;
675#else
676	d -> d_flags = 0;
677#endif
678	d -> d_secsize = SECTOR_SIZE;		/* bytes/sector  */
679	d -> d_nsectors = g.sectors;		/* sectors/track */
680	d -> d_ntracks = g.heads;		/* tracks/cylinder (heads) */
681	d -> d_ncylinders = g.cylinders;
682	d -> d_secpercyl  = g.sectors * g.heads;/* sectors/cylinder */
683	if (d -> d_secpercyl == 0)
684		d -> d_secpercyl = 1;		/* avoid segfaults */
685	d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
686
687	d -> d_rpm = 3600;
688	d -> d_interleave = 1;
689	d -> d_trackskew = 0;
690	d -> d_cylskew = 0;
691	d -> d_headswitch = 0;
692	d -> d_trkseek = 0;
693
694	d -> d_magic2 = BSD_DISKMAGIC;
695	d -> d_bbsize = BSD_BBSIZE;
696	d -> d_sbsize = BSD_SBSIZE;
697
698#if !defined (__alpha__)
699	d -> d_npartitions = 4;
700	pp = &d -> d_partitions[2];		/* Partition C should be
701						   the NetBSD partition */
702	pp -> p_offset = get_start_sect(p);
703	pp -> p_size   = get_nr_sects(p);
704	pp -> p_fstype = BSD_FS_UNUSED;
705	pp = &d -> d_partitions[3];		/* Partition D should be
706						   the whole disk */
707	pp -> p_offset = 0;
708	pp -> p_size   = d -> d_secperunit;
709	pp -> p_fstype = BSD_FS_UNUSED;
710#elif defined (__alpha__)
711	d -> d_npartitions = 3;
712	pp = &d -> d_partitions[2];		/* Partition C should be
713						   the whole disk */
714	pp -> p_offset = 0;
715	pp -> p_size   = d -> d_secperunit;
716	pp -> p_fstype = BSD_FS_UNUSED;
717#endif
718
719	return 1;
720}
721
722/*
723 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
724 * If it has the right magic, return 1.
725 */
726static int
727xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
728{
729	int t, sector;
730
731	/* p is used only to get the starting sector */
732#if !defined (__alpha__)
733	sector = (p ? get_start_sect(p) : 0);
734#elif defined (__alpha__)
735	sector = 0;
736#endif
737
738	if (lseek (fd, (off_t) sector * SECTOR_SIZE, SEEK_SET) == -1)
739		fatal (unable_to_seek);
740	if (BSD_BBSIZE != read (fd, disklabelbuffer, BSD_BBSIZE))
741		fatal (unable_to_read);
742
743	bcopy (&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
744	       d, sizeof (struct xbsd_disklabel));
745
746	if (d -> d_magic != BSD_DISKMAGIC || d -> d_magic2 != BSD_DISKMAGIC)
747		return 0;
748
749	for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++) {
750		d -> d_partitions[t].p_size   = 0;
751		d -> d_partitions[t].p_offset = 0;
752		d -> d_partitions[t].p_fstype = BSD_FS_UNUSED;
753	}
754
755	if (d -> d_npartitions > BSD_MAXPARTITIONS)
756		fprintf (stderr, _("Warning: too many partitions "
757				   "(%d, maximum is %d).\n"),
758			 d -> d_npartitions, BSD_MAXPARTITIONS);
759	return 1;
760}
761
762static int
763xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
764{
765  unsigned int sector;
766
767#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
768  sector = get_start_sect(p) + BSD_LABELSECTOR;
769#else
770  sector = BSD_LABELSECTOR;
771#endif
772
773  d -> d_checksum = 0;
774  d -> d_checksum = xbsd_dkcksum (d);
775
776  /* This is necessary if we want to write the bootstrap later,
777     otherwise we'd write the old disklabel with the bootstrap.
778  */
779  bcopy (d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
780	 sizeof (struct xbsd_disklabel));
781
782#if defined (__alpha__) && BSD_LABELSECTOR == 0
783  alpha_bootblock_checksum (disklabelbuffer);
784  if (lseek (fd, (off_t) 0, SEEK_SET) == -1)
785    fatal (unable_to_seek);
786  if (BSD_BBSIZE != write (fd, disklabelbuffer, BSD_BBSIZE))
787    fatal (unable_to_write);
788#else
789  if (lseek (fd, (off_t) sector * SECTOR_SIZE + BSD_LABELOFFSET,
790		   SEEK_SET) == -1)
791    fatal (unable_to_seek);
792  if (sizeof (struct xbsd_disklabel) != write (fd, d, sizeof (struct xbsd_disklabel)))
793    fatal (unable_to_write);
794#endif
795
796  sync_disks ();
797
798  return 1;
799}
800
801static void
802sync_disks (void)
803{
804  printf (_("\nSyncing disks.\n"));
805  sync ();
806  sleep (4);
807}
808
809#if !defined (__alpha__)
810static int
811xbsd_translate_fstype (int linux_type)
812{
813  switch (linux_type)
814  {
815    case 0x01: /* DOS 12-bit FAT   */
816    case 0x04: /* DOS 16-bit <32M  */
817    case 0x06: /* DOS 16-bit >=32M */
818    case 0xe1: /* DOS access       */
819    case 0xe3: /* DOS R/O          */
820    case 0xf2: /* DOS secondary    */
821      return BSD_FS_MSDOS;
822    case 0x07: /* OS/2 HPFS        */
823      return BSD_FS_HPFS;
824    default:
825      return BSD_FS_OTHER;
826  }
827}
828
829static void
830xbsd_link_part (void)
831{
832  int k, i;
833  struct partition *p;
834
835  k = get_partition (1, partitions);
836
837  if (!xbsd_check_new_partition (&i))
838    return;
839
840  p = get_part_table(k);
841
842  xbsd_dlabel.d_partitions[i].p_size   = get_nr_sects(p);
843  xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
844  xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
845}
846#endif
847
848#if defined (__alpha__)
849
850#if !defined(__GLIBC__)
851typedef unsigned long long u_int64_t;
852#endif
853
854void
855alpha_bootblock_checksum (char *boot)
856{
857  u_int64_t *dp, sum;
858  int i;
859
860  dp = (u_int64_t *)boot;
861  sum = 0;
862  for (i = 0; i < 63; i++)
863    sum += dp[i];
864  dp[63] = sum;
865}
866#endif /* __alpha__ */
867