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