Upload Tizen:Base source
[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/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
65 static void xbsd_delete_part (void);
66 static void xbsd_new_part (void);
67 static void xbsd_write_disklabel (void);
68 static int xbsd_create_disklabel (void);
69 static void xbsd_edit_disklabel (void);
70 static void xbsd_write_bootstrap (void);
71 static void xbsd_change_fstype (void);
72 static int xbsd_get_part_index (int max);
73 static int xbsd_check_new_partition (int *i);
74 static void xbsd_list_types (void);
75 static u_short xbsd_dkcksum (struct xbsd_disklabel *lp);
76 static int xbsd_initlabel  (struct partition *p, struct xbsd_disklabel *d,
77                             int pindex);
78 static int xbsd_readlabel  (struct partition *p, struct xbsd_disklabel *d);
79 static int xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d);
80 static void sync_disks (void);
81
82 #if defined (__alpha__)
83 void alpha_bootblock_checksum (char *boot);
84 #endif
85
86 #if !defined (__alpha__)
87 static int xbsd_translate_fstype (int linux_type);
88 static void xbsd_link_part (void);
89 static struct partition *xbsd_part;
90 static int xbsd_part_index;
91 #endif
92
93 #if defined (__alpha__)
94 /* We access this through a u_int64_t * when checksumming */
95 static char disklabelbuffer[BSD_BBSIZE] __attribute__((aligned(8)));
96 #else
97 static char disklabelbuffer[BSD_BBSIZE];
98 #endif
99
100 static 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  */
111 int
112 check_osf_label(void) {
113         if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
114                 return 0;
115         return 1;
116 }
117
118 int
119 btrydev (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
127 static void
128 bmenu (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__)
149 static int
150 hidden(int type) {
151         return type ^ 0x10;
152 }
153
154 static int
155 is_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
163 void
164 bselect (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
252 static void
253 xbsd_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
266 static void
267 xbsd_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
304 void
305 xbsd_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
402 static void
403 xbsd_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
415 static int
416 xbsd_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
446 static int
447 edit_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
459 static void
460 xbsd_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
493 static int
494 xbsd_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
514 static void
515 xbsd_write_bootstrap (void)
516 {
517   char *bootdir = BSD_LINUX_BOOTDIR;
518   char path[sizeof(BSD_LINUX_BOOTDIR) + 1 + 2 + 4];  /* BSD_LINUX_BOOTDIR + / + {sd,wd} + boot */
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   memmove (&dl, d, 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   memmove (d, &dl, 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
584 static void
585 xbsd_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
593 static int
594 xbsd_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
606 static int
607 xbsd_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
637 static void
638 xbsd_list_types (void) {
639         list_types (xbsd_fstypes);
640 }
641
642 static u_short
643 xbsd_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
654 static int
655 xbsd_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  */
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__ */