1 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2
3 libparted - a library for manipulating disk partitions
4 Copyright (C) 2000, 2001, 2007 Free Software Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19 Contributor: Matt Wilson <msw@redhat.com>
20 */
21
22 #include <config.h>
23
24 #include <parted/parted.h>
25 #include <parted/debug.h>
26 #include <parted/endian.h>
27
28 #if ENABLE_NLS
29 # include <libintl.h>
30 # define _(String) dgettext (PACKAGE, String)
31 #else
32 # define _(String) (String)
33 #endif /* ENABLE_NLS */
34
35 /* struct's & #define's stolen from libfdisk, which probably came from
36 * Linux...
37 */
38
39 #define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
40 #define BSD_MAXPARTITIONS 8
41 #define BSD_FS_UNUSED 0 /* disklabel unused partition entry ID */
42 #define BSD_LABEL_OFFSET 64
43
44 #define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
45 #define BSD_DTYPE_MSCP 2 /* MSCP */
46 #define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
47 #define BSD_DTYPE_SCSI 4 /* SCSI */
48 #define BSD_DTYPE_ESDI 5 /* ESDI interface */
49 #define BSD_DTYPE_ST506 6 /* ST506 etc. */
50 #define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
51 #define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
52 #define BSD_DTYPE_FLOPPY 10 /* floppy */
53
54 #define BSD_BBSIZE 8192 /* size of boot area, with label */
55 #define BSD_SBSIZE 8192 /* max size of fs superblock */
56
57 typedef struct _BSDRawPartition BSDRawPartition;
58 typedef struct _BSDRawLabel BSDRawLabel;
59
60 #ifdef __sun
61 #define __attribute__(X) /*nothing*/
62 #endif /* __sun */
63
64 #ifdef __sun
65 #pragma pack(1)
66 #endif
67 struct _BSDRawPartition { /* the partition table */
68 uint32_t p_size; /* number of sectors in partition */
69 uint32_t p_offset; /* starting sector */
70 uint32_t p_fsize; /* file system basic fragment size */
71 uint8_t p_fstype; /* file system type, see below */
72 uint8_t p_frag; /* file system fragments per block */
73 uint16_t p_cpg; /* file system cylinders per group */
74 } __attribute__((packed));
75 #ifdef __sun
76 #pragma pack()
77 #endif
78
79 #ifdef __sun
80 #pragma pack(1)
81 #endif
82 struct _BSDRawLabel {
83 uint32_t d_magic; /* the magic number */
84 int16_t d_type; /* drive type */
85 int16_t d_subtype; /* controller/d_type specific */
86 int8_t d_typename[16]; /* type name, e.g. "eagle" */
87 int8_t d_packname[16]; /* pack identifier */
88 uint32_t d_secsize; /* # of bytes per sector */
89 uint32_t d_nsectors; /* # of data sectors per track */
90 uint32_t d_ntracks; /* # of tracks per cylinder */
91 uint32_t d_ncylinders; /* # of data cylinders per unit */
92 uint32_t d_secpercyl; /* # of data sectors per cylinder */
93 uint32_t d_secperunit; /* # of data sectors per unit */
94 uint16_t d_sparespertrack; /* # of spare sectors per track */
95 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
96 uint32_t d_acylinders; /* # of alt. cylinders per unit */
97 uint16_t d_rpm; /* rotational speed */
98 uint16_t d_interleave; /* hardware sector interleave */
99 uint16_t d_trackskew; /* sector 0 skew, per track */
100 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
101 uint32_t d_headswitch; /* head switch time, usec */
102 uint32_t d_trkseek; /* track-to-track seek, usec */
103 uint32_t d_flags; /* generic flags */
104 #define NDDATA 5
105 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
106 #define NSPARE 5
107 uint32_t d_spare[NSPARE]; /* reserved for future use */
108 uint32_t d_magic2; /* the magic number (again) */
109 uint16_t d_checksum; /* xor of data incl. partitions */
110
111 /* file system and partition information: */
112 uint16_t d_npartitions; /* number of partitions in following */
113 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
114 uint32_t d_sbsize; /* max size of fs superblock, bytes */
115 BSDRawPartition d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
116 } __attribute__((packed));
117 #ifdef __sun
118 #pragma pack()
119 #endif
120
121 typedef struct {
122 char boot_code [512];
123 } BSDDiskData;
124
125 typedef struct {
126 uint8_t type;
127 } BSDPartitionData;
128
129 static PedDiskType bsd_disk_type;
130
131 /* XXX fixme: endian? */
132 static unsigned short
xbsd_dkcksum(BSDRawLabel * lp)133 xbsd_dkcksum (BSDRawLabel *lp) {
134 unsigned short *start, *end;
135 unsigned short sum = 0;
136
137 lp->d_checksum = 0;
138 start = (u_short*) lp;
139 end = (u_short*) &lp->d_partitions [
140 PED_LE16_TO_CPU (lp->d_npartitions)];
141 while (start < end)
142 sum ^= *start++;
143 return sum;
144 }
145
146 /* XXX fixme: endian? */
147 static void
alpha_bootblock_checksum(char * boot)148 alpha_bootblock_checksum (char *boot) {
149 uint64_t *dp, sum;
150 int i;
151
152 dp = (uint64_t *)boot;
153 sum = 0;
154 for (i = 0; i < 63; i++)
155 sum += dp[i];
156 dp[63] = sum;
157 }
158
159
160 static int
bsd_probe(const PedDevice * dev)161 bsd_probe (const PedDevice *dev)
162 {
163 char boot[512];
164 BSDRawLabel *label;
165
166 PED_ASSERT (dev != NULL, return 0);
167
168 if (dev->sector_size != 512)
169 return 0;
170
171 if (!ped_device_read (dev, boot, 0, 1))
172 return 0;
173
174 label = (BSDRawLabel *) (boot + BSD_LABEL_OFFSET);
175
176 alpha_bootblock_checksum(boot);
177
178 /* check magic */
179 if (PED_LE32_TO_CPU (label->d_magic) != BSD_DISKMAGIC)
180 return 0;
181
182 return 1;
183 }
184
185 static PedDisk*
bsd_alloc(const PedDevice * dev)186 bsd_alloc (const PedDevice* dev)
187 {
188 PedDisk* disk;
189 BSDDiskData* bsd_specific;
190 BSDRawLabel* label;
191
192 PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return 0);
193
194 disk = _ped_disk_alloc ((PedDevice*)dev, &bsd_disk_type);
195 if (!disk)
196 goto error;
197 disk->disk_specific = bsd_specific = ped_malloc (sizeof (BSDDiskData));
198 if (!bsd_specific)
199 goto error_free_disk;
200 /* Initialize the first byte to zero, so that the code in bsd_write
201 knows to call _probe_and_add_boot_code. Initializing all of the
202 remaining buffer is a little wasteful, but the alternative is to
203 figure out why a block at offset 340 would otherwise be used
204 uninitialized. */
205 memset(bsd_specific->boot_code, 0, sizeof (bsd_specific->boot_code));
206
207 label = (BSDRawLabel*) (bsd_specific->boot_code + BSD_LABEL_OFFSET);
208
209 label->d_magic = PED_CPU_TO_LE32 (BSD_DISKMAGIC);
210 label->d_type = PED_CPU_TO_LE16 (BSD_DTYPE_SCSI);
211 label->d_flags = 0;
212 label->d_secsize = PED_CPU_TO_LE16 (dev->sector_size);
213 label->d_nsectors = PED_CPU_TO_LE32 (dev->bios_geom.sectors);
214 label->d_ntracks = PED_CPU_TO_LE32 (dev->bios_geom.heads);
215 label->d_ncylinders = PED_CPU_TO_LE32 (dev->bios_geom.cylinders);
216 label->d_secpercyl = PED_CPU_TO_LE32 (dev->bios_geom.sectors
217 * dev->bios_geom.heads);
218 label->d_secperunit
219 = PED_CPU_TO_LE32 (dev->bios_geom.sectors
220 * dev->bios_geom.heads
221 * dev->bios_geom.cylinders);
222
223 label->d_rpm = PED_CPU_TO_LE16 (3600);
224 label->d_interleave = PED_CPU_TO_LE16 (1);;
225 label->d_trackskew = 0;
226 label->d_cylskew = 0;
227 label->d_headswitch = 0;
228 label->d_trkseek = 0;
229
230 label->d_magic2 = PED_CPU_TO_LE32 (BSD_DISKMAGIC);
231 label->d_bbsize = PED_CPU_TO_LE32 (BSD_BBSIZE);
232 label->d_sbsize = PED_CPU_TO_LE32 (BSD_SBSIZE);
233
234 label->d_npartitions = 0;
235 label->d_checksum = xbsd_dkcksum (label);
236 return disk;
237
238 error_free_disk:
239 ped_free (disk);
240 error:
241 return NULL;
242 }
243
244 static PedDisk*
bsd_duplicate(const PedDisk * disk)245 bsd_duplicate (const PedDisk* disk)
246 {
247 PedDisk* new_disk;
248 BSDDiskData* new_bsd_data;
249 BSDDiskData* old_bsd_data = (BSDDiskData*) disk->disk_specific;
250
251 new_disk = ped_disk_new_fresh (disk->dev, &bsd_disk_type);
252 if (!new_disk)
253 return NULL;
254
255 new_bsd_data = (BSDDiskData*) new_disk->disk_specific;
256 memcpy (new_bsd_data->boot_code, old_bsd_data->boot_code, 512);
257 return new_disk;
258 }
259
260 static void
bsd_free(PedDisk * disk)261 bsd_free (PedDisk* disk)
262 {
263 ped_free (disk->disk_specific);
264 _ped_disk_free (disk);
265 }
266
267 #ifndef DISCOVER_ONLY
268 static int
bsd_clobber(PedDevice * dev)269 bsd_clobber (PedDevice* dev)
270 {
271 char boot [512];
272 BSDRawLabel* label = (BSDRawLabel *) (boot + BSD_LABEL_OFFSET);
273
274 if (!ped_device_read (dev, boot, 0, 1))
275 return 0;
276 label->d_magic = 0;
277 return ped_device_write (dev, (void*) boot, 0, 1);
278 }
279 #endif /* !DISCOVER_ONLY */
280
281 static int
bsd_read(PedDisk * disk)282 bsd_read (PedDisk* disk)
283 {
284 BSDDiskData* bsd_specific = (BSDDiskData*) disk->disk_specific;
285 BSDRawLabel* label;
286 int i;
287
288 ped_disk_delete_all (disk);
289
290 if (!ped_device_read (disk->dev, bsd_specific->boot_code, 0, 1))
291 goto error;
292 label = (BSDRawLabel *) (bsd_specific->boot_code + BSD_LABEL_OFFSET);
293
294 for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
295 PedPartition* part;
296 BSDPartitionData* bsd_part_data;
297 PedSector start;
298 PedSector end;
299 PedConstraint* constraint_exact;
300
301 if (!label->d_partitions[i - 1].p_size
302 || !label->d_partitions[i - 1].p_fstype)
303 continue;
304 start = PED_LE32_TO_CPU(label->d_partitions[i - 1].p_offset);
305 end = PED_LE32_TO_CPU(label->d_partitions[i - 1].p_offset)
306 + PED_LE32_TO_CPU(label->d_partitions[i - 1].p_size) - 1;
307 part = ped_partition_new (disk, 0, NULL, start, end);
308 if (!part)
309 goto error;
310 bsd_part_data = part->disk_specific;
311 bsd_part_data->type = label->d_partitions[i - 1].p_fstype;
312 part->num = i;
313 part->fs_type = ped_file_system_probe (&part->geom);
314
315 constraint_exact = ped_constraint_exact (&part->geom);
316 if (!ped_disk_add_partition (disk, part, constraint_exact))
317 goto error;
318 ped_constraint_destroy (constraint_exact);
319 }
320
321 return 1;
322
323 error:
324 return 0;
325 }
326
327 static void
_probe_and_add_boot_code(const PedDisk * disk)328 _probe_and_add_boot_code (const PedDisk* disk)
329 {
330 BSDDiskData* bsd_specific;
331 BSDRawLabel* old_label;
332 char old_boot_code [512];
333
334 bsd_specific = (BSDDiskData*) disk->disk_specific;
335 old_label = (BSDRawLabel*) (old_boot_code + BSD_LABEL_OFFSET);
336
337 if (!ped_device_read (disk->dev, old_boot_code, 0, 1))
338 return;
339 if (old_boot_code [0]
340 && old_label->d_magic == PED_CPU_TO_LE32 (BSD_DISKMAGIC))
341 memcpy (bsd_specific->boot_code, old_boot_code, 512);
342 }
343
344 #ifndef DISCOVER_ONLY
345 static int
bsd_write(const PedDisk * disk)346 bsd_write (const PedDisk* disk)
347 {
348 BSDDiskData* bsd_specific;
349 BSDRawLabel* label;
350 BSDPartitionData* bsd_data;
351 PedPartition* part;
352 int i;
353 int max_part = 0;
354
355 PED_ASSERT (disk != NULL, return 0);
356 PED_ASSERT (disk->dev != NULL, return 0);
357
358 bsd_specific = (BSDDiskData*) disk->disk_specific;
359 label = (BSDRawLabel *) (bsd_specific->boot_code + BSD_LABEL_OFFSET);
360
361 if (!bsd_specific->boot_code [0])
362 _probe_and_add_boot_code (disk);
363
364 memset (label->d_partitions, 0,
365 sizeof (BSDRawPartition) * BSD_MAXPARTITIONS);
366
367 for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
368 part = ped_disk_get_partition (disk, i);
369 if (!part)
370 continue;
371 bsd_data = part->disk_specific;
372 label->d_partitions[i - 1].p_fstype = bsd_data->type;
373 label->d_partitions[i - 1].p_offset
374 = PED_CPU_TO_LE32 (part->geom.start);
375 label->d_partitions[i - 1].p_size
376 = PED_CPU_TO_LE32 (part->geom.length);
377 max_part = i;
378 }
379
380 label->d_npartitions = PED_CPU_TO_LE16 (max_part) + 1;
381 label->d_checksum = xbsd_dkcksum (label);
382
383 alpha_bootblock_checksum (bsd_specific->boot_code);
384
385 if (!ped_device_write (disk->dev, (void*) bsd_specific->boot_code,
386 0, 1))
387 goto error;
388 return ped_device_sync (disk->dev);
389
390 error:
391 return 0;
392 }
393 #endif /* !DISCOVER_ONLY */
394
395 static PedPartition*
bsd_partition_new(const PedDisk * disk,PedPartitionType part_type,const PedFileSystemType * fs_type,PedSector start,PedSector end)396 bsd_partition_new (const PedDisk* disk, PedPartitionType part_type,
397 const PedFileSystemType* fs_type,
398 PedSector start, PedSector end)
399 {
400 PedPartition* part;
401 BSDPartitionData* bsd_data;
402
403 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
404 if (!part)
405 goto error;
406
407 if (ped_partition_is_active (part)) {
408 part->disk_specific
409 = bsd_data = ped_malloc (sizeof (BSDPartitionData));
410 if (!bsd_data)
411 goto error_free_part;
412 bsd_data->type = 0;
413 } else {
414 part->disk_specific = NULL;
415 }
416 return part;
417
418 ped_free (bsd_data);
419 error_free_part:
420 ped_free (part);
421 error:
422 return 0;
423 }
424
425 static PedPartition*
bsd_partition_duplicate(const PedPartition * part)426 bsd_partition_duplicate (const PedPartition* part)
427 {
428 PedPartition* new_part;
429 BSDPartitionData* new_bsd_data;
430 BSDPartitionData* old_bsd_data;
431
432 new_part = ped_partition_new (part->disk, part->type,
433 part->fs_type, part->geom.start,
434 part->geom.end);
435 if (!new_part)
436 return NULL;
437 new_part->num = part->num;
438
439 old_bsd_data = (BSDPartitionData*) part->disk_specific;
440 new_bsd_data = (BSDPartitionData*) new_part->disk_specific;
441 new_bsd_data->type = old_bsd_data->type;
442 return new_part;
443 }
444
445 static void
bsd_partition_destroy(PedPartition * part)446 bsd_partition_destroy (PedPartition* part)
447 {
448 PED_ASSERT (part != NULL, return);
449
450 if (ped_partition_is_active (part))
451 ped_free (part->disk_specific);
452 _ped_partition_free (part);
453 }
454
455 static int
bsd_partition_set_system(PedPartition * part,const PedFileSystemType * fs_type)456 bsd_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
457 {
458 BSDPartitionData* bsd_data = part->disk_specific;
459
460 part->fs_type = fs_type;
461
462 if (!fs_type)
463 bsd_data->type = 0x8;
464 else if (!strcmp (fs_type->name, "linux-swap"))
465 bsd_data->type = 0x1;
466 else
467 bsd_data->type = 0x8;
468
469 return 1;
470 }
471
472 static int
bsd_partition_set_flag(PedPartition * part,PedPartitionFlag flag,int state)473 bsd_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
474 {
475 /* no flags for bsd */
476 return 0;
477 }
478
479 static int
bsd_partition_get_flag(const PedPartition * part,PedPartitionFlag flag)480 bsd_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
481 {
482 /* no flags for bsd */
483 return 0;
484 }
485
486 static int
bsd_partition_is_flag_available(const PedPartition * part,PedPartitionFlag flag)487 bsd_partition_is_flag_available (const PedPartition* part,
488 PedPartitionFlag flag)
489 {
490 /* no flags for bsd */
491 return 0;
492 }
493
494
495 static int
bsd_get_max_primary_partition_count(const PedDisk * disk)496 bsd_get_max_primary_partition_count (const PedDisk* disk)
497 {
498 return BSD_MAXPARTITIONS;
499 }
500
501 static PedConstraint*
_get_constraint(const PedDevice * dev)502 _get_constraint (const PedDevice* dev)
503 {
504 PedGeometry max;
505
506 ped_geometry_init (&max, dev, 1, dev->length - 1);
507 return ped_constraint_new_from_max (&max);
508 }
509
510 static int
bsd_partition_align(PedPartition * part,const PedConstraint * constraint)511 bsd_partition_align (PedPartition* part, const PedConstraint* constraint)
512 {
513 if (_ped_partition_attempt_align (part, constraint,
514 _get_constraint (part->disk->dev)))
515 return 1;
516
517 #ifndef DISCOVER_ONLY
518 ped_exception_throw (
519 PED_EXCEPTION_ERROR,
520 PED_EXCEPTION_CANCEL,
521 _("Unable to satisfy all constraints on the partition."));
522 #endif
523 return 0;
524 }
525
526 static int
bsd_partition_enumerate(PedPartition * part)527 bsd_partition_enumerate (PedPartition* part)
528 {
529 int i;
530 PedPartition* p;
531
532 /* never change the partition numbers */
533 if (part->num != -1)
534 return 1;
535 for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
536 p = ped_disk_get_partition (part->disk, i);
537 if (!p) {
538 part->num = i;
539 return 1;
540 }
541 }
542
543 /* failed to allocate a number */
544 #ifndef DISCOVER_ONLY
545 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
546 _("Unable to allocate a bsd disklabel slot."));
547 #endif
548 return 0;
549 }
550
551 static int
bsd_alloc_metadata(PedDisk * disk)552 bsd_alloc_metadata (PedDisk* disk)
553 {
554 PedPartition* new_part;
555 PedConstraint* constraint_any = NULL;
556
557 PED_ASSERT (disk != NULL, goto error);
558 PED_ASSERT (disk->dev != NULL, goto error);
559
560 constraint_any = ped_constraint_any (disk->dev);
561
562 /* allocate 1 sector for the disk label at the start */
563 new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL, 0, 0);
564 if (!new_part)
565 goto error;
566
567 if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
568 ped_partition_destroy (new_part);
569 goto error;
570 }
571
572 ped_constraint_destroy (constraint_any);
573 return 1;
574 error:
575 ped_constraint_destroy (constraint_any);
576 return 0;
577 }
578
579 static PedDiskOps bsd_disk_ops = {
580 .probe = bsd_probe,
581 #ifndef DISCOVER_ONLY
582 .clobber = bsd_clobber,
583 #else
584 .clobber = NULL,
585 #endif
586 .alloc = bsd_alloc,
587 .duplicate = bsd_duplicate,
588 .free = bsd_free,
589 .read = bsd_read,
590 #ifndef DISCOVER_ONLY
591 .write = bsd_write,
592 #else
593 .write = NULL,
594 #endif
595
596 .partition_new = bsd_partition_new,
597 .partition_duplicate = bsd_partition_duplicate,
598 .partition_destroy = bsd_partition_destroy,
599 .partition_set_system = bsd_partition_set_system,
600 .partition_set_flag = bsd_partition_set_flag,
601 .partition_get_flag = bsd_partition_get_flag,
602 .partition_is_flag_available = bsd_partition_is_flag_available,
603 .partition_set_name = NULL,
604 .partition_get_name = NULL,
605 .partition_align = bsd_partition_align,
606 .partition_enumerate = bsd_partition_enumerate,
607
608 .alloc_metadata = bsd_alloc_metadata,
609 .get_max_primary_partition_count =
610 bsd_get_max_primary_partition_count
611 };
612
613 static PedDiskType bsd_disk_type = {
614 .next = NULL,
615 .name = "bsd",
616 .ops = &bsd_disk_ops,
617 .features = 0
618 };
619
620 void
ped_disk_bsd_init()621 ped_disk_bsd_init ()
622 {
623 PED_ASSERT (sizeof (BSDRawPartition) == 16, return);
624 PED_ASSERT (sizeof (BSDRawLabel) == 276, return);
625
626 ped_disk_type_register (&bsd_disk_type);
627 }
628
629 void
ped_disk_bsd_done()630 ped_disk_bsd_done ()
631 {
632 ped_disk_type_unregister (&bsd_disk_type);
633 }
634