3 * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org>
4 * 2013 Karel Zak <kzak@redhat.com>
6 * This is re-written version for libfdisk, the original was fdisksgilabel.c
7 * from util-linux fdisk, by:
9 * Andreas Neuper, Sep 1998.
10 * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, Mar 1999
11 * Phillip Kesling <pkesling@sgi.com>, Mar 2003
25 * in-memory fdisk SGI stuff
27 struct fdisk_sgi_label
{
28 struct fdisk_label head
; /* generic fdisk part */
29 struct sgi_disklabel
*header
; /* on-disk data (pointer to cxt->firstsector) */
31 struct sgi_freeblocks
{
34 } freelist
[SGI_MAXPARTITIONS
+ 1];
37 static struct fdisk_parttype sgi_parttypes
[] =
39 {SGI_TYPE_VOLHDR
, N_("SGI volhdr")},
40 {SGI_TYPE_TRKREPL
, N_("SGI trkrepl")},
41 {SGI_TYPE_SECREPL
, N_("SGI secrepl")},
42 {SGI_TYPE_SWAP
, N_("SGI raw")},
43 {SGI_TYPE_BSD
, N_("SGI bsd")},
44 {SGI_TYPE_SYSV
, N_("SGI sysv")},
45 {SGI_TYPE_ENTIRE_DISK
, N_("SGI volume")},
46 {SGI_TYPE_EFS
, N_("SGI efs")},
47 {SGI_TYPE_LVOL
, N_("SGI lvol")},
48 {SGI_TYPE_RLVOL
, N_("SGI rlvol")},
49 {SGI_TYPE_XFS
, N_("SGI xfs")},
50 {SGI_TYPE_XFSLOG
, N_("SGI xfslog")},
51 {SGI_TYPE_XLV
, N_("SGI xlv")},
52 {SGI_TYPE_XVM
, N_("SGI xvm")},
53 {MBR_LINUX_SWAP_PARTITION
, N_("Linux swap")},
54 {MBR_LINUX_DATA_PARTITION
, N_("Linux native")},
55 {MBR_LINUX_LVM_PARTITION
, N_("Linux LVM")},
56 {MBR_LINUX_RAID_PARTITION
, N_("Linux RAID")},
60 /* return poiter buffer with on-disk data */
61 static inline struct sgi_disklabel
*self_disklabel(struct fdisk_context
*cxt
)
65 assert(fdisk_is_disklabel(cxt
, SGI
));
67 return ((struct fdisk_sgi_label
*) cxt
->label
)->header
;
70 /* return in-memory fdisk data */
71 static inline struct fdisk_sgi_label
*self_label(struct fdisk_context
*cxt
)
75 assert(fdisk_is_disklabel(cxt
, SGI
));
77 return (struct fdisk_sgi_label
*) cxt
->label
;
81 * Information within second on-disk block
83 #define SGI_INFO_MAGIC 0x00072959
86 unsigned int magic
; /* looks like a magic number */
95 unsigned char scsi_string
[50];
96 unsigned char serial
[137];
97 unsigned short check1816
;
98 unsigned char installer
[225];
101 static struct sgi_info
*sgi_new_info(void)
103 struct sgi_info
*info
= calloc(1, sizeof(struct sgi_info
));
108 info
->magic
= cpu_to_be32(SGI_INFO_MAGIC
);
109 info
->b1
= cpu_to_be32(-1);
110 info
->b2
= cpu_to_be16(-1);
111 info
->b3
= cpu_to_be16(1);
113 /* You may want to replace this string !!!!!!! */
114 strcpy((char *) info
->scsi_string
, "IBM OEM 0662S12 3 30");
115 strcpy((char *) info
->serial
, "0000");
116 info
->check1816
= cpu_to_be16(18 * 256 + 16);
117 strcpy((char *) info
->installer
, "Sfx version 5.3, Oct 18, 1994");
122 static void sgi_free_info(struct sgi_info
*info
)
127 int sgi_create_info(struct fdisk_context
*cxt
)
129 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
131 /* I keep SGI's habit to write the sgilabel to the second block */
132 sgilabel
->volume
[0].block_num
= cpu_to_be32(2);
133 sgilabel
->volume
[0].num_bytes
= cpu_to_be32(sizeof(struct sgi_info
));
134 strncpy((char *) sgilabel
->volume
[0].name
, "sgilabel", 8);
140 * only dealing with free blocks here
142 static void set_freelist(struct fdisk_context
*cxt
,
143 size_t i
, unsigned int f
, unsigned int l
)
145 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
147 if (i
< ARRAY_SIZE(sgi
->freelist
)) {
148 sgi
->freelist
[i
].first
= f
;
149 sgi
->freelist
[i
].last
= l
;
153 static void add_to_freelist(struct fdisk_context
*cxt
,
154 unsigned int f
, unsigned int l
)
156 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
159 for (i
= 0; i
< ARRAY_SIZE(sgi
->freelist
); i
++) {
160 if (sgi
->freelist
[i
].last
== 0)
163 set_freelist(cxt
, i
, f
, l
);
166 static void clear_freelist(struct fdisk_context
*cxt
)
168 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
170 memset(sgi
->freelist
, 0, sizeof(sgi
->freelist
));
173 static unsigned int is_in_freelist(struct fdisk_context
*cxt
, unsigned int b
)
175 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
178 for (i
= 0; i
< ARRAY_SIZE(sgi
->freelist
); i
++) {
179 if (sgi
->freelist
[i
].first
<= b
180 && sgi
->freelist
[i
].last
>= b
)
181 return sgi
->freelist
[i
].last
;
188 static int sgi_get_nsect(struct fdisk_context
*cxt
)
190 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
191 return be16_to_cpu(sgilabel
->devparam
.nsect
);
194 static int sgi_get_ntrks(struct fdisk_context
*cxt
)
196 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
197 return be16_to_cpu(sgilabel
->devparam
.ntrks
);
200 static size_t count_used_partitions(struct fdisk_context
*cxt
)
204 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++)
205 ct
+= sgi_get_num_sectors(cxt
, i
) > 0;
210 static int sgi_probe_label(struct fdisk_context
*cxt
)
212 struct fdisk_sgi_label
*sgi
;
213 struct sgi_disklabel
*sgilabel
;
217 assert(fdisk_is_disklabel(cxt
, SGI
));
218 assert(sizeof(struct sgi_disklabel
) <= 512);
220 /* map first sector to header */
221 sgi
= (struct fdisk_sgi_label
*) cxt
->label
;
222 sgi
->header
= (struct sgi_disklabel
*) cxt
->firstsector
;
223 sgilabel
= sgi
->header
;
225 if (be32_to_cpu(sgilabel
->magic
) != SGI_LABEL_MAGIC
) {
231 * test for correct checksum
233 if (sgi_pt_checksum(sgilabel
) != 0)
234 fdisk_warnx(cxt
, _("Detected sgi disklabel with wrong checksum."));
237 cxt
->label
->nparts_max
= SGI_MAXPARTITIONS
;
238 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
242 static int sgi_list_table(struct fdisk_context
*cxt
)
244 struct tt
*tb
= NULL
;
245 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
246 struct sgi_device_parameter
*sgiparam
= &sgilabel
->devparam
;
251 if (fdisk_context_display_details(cxt
))
253 "Label geometry: %d heads, %llu sectors\n"
254 " %llu cylinders, %d physical cylinders\n"
255 " %d extra sects/cyl, interleave %d:1\n"),
256 cxt
->geom
.heads
, cxt
->geom
.sectors
,
257 cxt
->geom
.cylinders
, be16_to_cpu(sgiparam
->pcylcount
),
258 (int) sgiparam
->sparecyl
, be16_to_cpu(sgiparam
->ilfact
));
263 tb
= tt_new_table(TT_FL_FREEDATA
);
267 tt_define_column(tb
, _("Pt#"), 3, TT_FL_RIGHT
);
268 tt_define_column(tb
, _("Device"), 0.2, 0);
269 tt_define_column(tb
, _("Info"), 2, 0);
270 tt_define_column(tb
, _("Start"), 9, TT_FL_RIGHT
);
271 tt_define_column(tb
, _("End"), 9, TT_FL_RIGHT
);
272 tt_define_column(tb
, _("Sectors"), 9, TT_FL_RIGHT
);
273 tt_define_column(tb
, _("Id"), 2, TT_FL_RIGHT
);
274 tt_define_column(tb
, _("System"), 0.2, TT_FL_TRUNC
);
276 for (i
= 0, used
= 1; i
< cxt
->label
->nparts_max
; i
++) {
278 struct fdisk_parttype
*t
;
281 if (sgi_get_num_sectors(cxt
, i
) == 0)
284 ln
= tt_add_line(tb
, NULL
);
287 start
= sgi_get_start_sector(cxt
, i
);
288 len
= sgi_get_num_sectors(cxt
, i
);
289 t
= fdisk_get_partition_type(cxt
, i
);
291 if (asprintf(&p
, "%zu:", i
+ 1) > 0)
292 tt_line_set_data(ln
, 0, p
); /* # */
293 p
= fdisk_partname(cxt
->dev_path
, used
++);
295 tt_line_set_data(ln
, 1, p
); /* Device */
297 p
= sgi_get_swappartition(cxt
) == (int) i
? "swap" :
298 sgi_get_bootpartition(cxt
) == (int) i
? "boot" : NULL
;
300 tt_line_set_data(ln
, 2, strdup(p
)); /* Info */
302 if (asprintf(&p
, "%ju", (uintmax_t) fdisk_scround(cxt
, start
)) > 0)
303 tt_line_set_data(ln
, 3, p
); /* Start */
304 if (asprintf(&p
, "%ju", (uintmax_t) fdisk_scround(cxt
, start
+ len
) - 1) > 0)
305 tt_line_set_data(ln
, 4, p
); /* End */
306 if (asprintf(&p
, "%ju", (uintmax_t) len
) > 0)
307 tt_line_set_data(ln
, 5, p
); /* Sectors*/
308 if (asprintf(&p
, "%2x", t
->type
) > 0)
309 tt_line_set_data(ln
, 6, p
); /* type ID */
311 tt_line_set_data(ln
, 7, strdup(t
->name
)); /* type Name */
312 fdisk_free_parttype(t
);
315 rc
= fdisk_print_table(cxt
, tb
);
323 tb
= tt_new_table(TT_FL_FREEDATA
);
327 tt_define_column(tb
, _("#"), 3, TT_FL_RIGHT
);
328 tt_define_column(tb
, _("Name"), 0.2, 0);
329 tt_define_column(tb
, _("Sector"), 2, TT_FL_RIGHT
);
330 tt_define_column(tb
, _("Size"), 9, TT_FL_RIGHT
);
332 for (i
= 0, used
= 0; i
< SGI_MAXVOLUMES
; i
++) {
334 uint32_t start
= be32_to_cpu(sgilabel
->volume
[i
].block_num
),
335 len
= be32_to_cpu(sgilabel
->volume
[i
].num_bytes
);
338 ln
= tt_add_line(tb
, NULL
);
341 if (asprintf(&p
, "%zu:", i
) > 0)
342 tt_line_set_data(ln
, 0, p
); /* # */
343 if (*sgilabel
->volume
[i
].name
)
344 tt_line_set_data(ln
, 1,
345 strndup((char *) sgilabel
->volume
[i
].name
,
346 sizeof(sgilabel
->volume
[i
].name
))); /* Name */
347 if (asprintf(&p
, "%ju", (uintmax_t) start
) > 0)
348 tt_line_set_data(ln
, 2, p
); /* Sector */
349 if (asprintf(&p
, "%ju", (uintmax_t) len
) > 0)
350 tt_line_set_data(ln
, 3, p
); /* Size */
355 rc
= fdisk_print_table(cxt
, tb
);
358 fdisk_info(cxt
, _("Bootfile: %s"), sgilabel
->boot_file
);
363 unsigned int sgi_get_start_sector(struct fdisk_context
*cxt
, int i
)
365 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
366 return be32_to_cpu(sgilabel
->partitions
[i
].first_block
);
369 unsigned int sgi_get_num_sectors(struct fdisk_context
*cxt
, int i
)
371 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
372 return be32_to_cpu(sgilabel
->partitions
[i
].num_blocks
);
375 static int sgi_get_sysid(struct fdisk_context
*cxt
, int i
)
377 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
378 return be32_to_cpu(sgilabel
->partitions
[i
].type
);
381 int sgi_get_bootpartition(struct fdisk_context
*cxt
)
383 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
384 return be16_to_cpu(sgilabel
->root_part_num
);
387 int sgi_get_swappartition(struct fdisk_context
*cxt
)
389 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
390 return be16_to_cpu(sgilabel
->swap_part_num
);
393 static unsigned int sgi_get_lastblock(struct fdisk_context
*cxt
)
395 return cxt
->geom
.heads
* cxt
->geom
.sectors
* cxt
->geom
.cylinders
;
398 static int sgi_check_bootfile(struct fdisk_context
*cxt
, const char *name
)
401 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
406 /* "/a\n" is minimum */
407 fdisk_warnx(cxt
, _("Invalid Bootfile! "
408 "The bootfile must be an absolute non-zero pathname,"
409 "e.g. \"/unix\" or \"/unix.save\"."));
412 } else if (sz
> sizeof(sgilabel
->boot_file
)) {
413 fdisk_warnx(cxt
, _("Name of Bootfile too long: %zu bytes maximum."),
414 sizeof(sgilabel
->boot_file
));
417 } else if (*name
!= '/') {
418 fdisk_warnx(cxt
, _("Bootfile must have a fully qualified pathname."));
422 if (strncmp(name
, (char *) sgilabel
->boot_file
,
423 sizeof(sgilabel
->boot_file
))) {
424 fdisk_warnx(cxt
, _("Be aware, that the bootfile is not checked "
425 "for existence. SGI's default is \"/unix\" and for "
426 "backup \"/unix.save\"."));
427 /* filename is correct and did change */
431 return 1; /* filename did not change */
434 int sgi_set_bootfile(struct fdisk_context
*cxt
)
439 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
441 fdisk_info(cxt
, _("The current boot file is: %s"), sgilabel
->boot_file
);
443 rc
= fdisk_ask_string(cxt
, _("Enter of the new boot file"), &name
);
445 rc
= sgi_check_bootfile(cxt
, name
);
448 fdisk_info(cxt
, _("Boot file unchanged"));
452 memset(sgilabel
->boot_file
, 0, sizeof(sgilabel
->boot_file
));
455 assert(sz
<= sizeof(sgilabel
->boot_file
)); /* see sgi_check_bootfile() */
457 memcpy(sgilabel
->boot_file
, name
, sz
);
459 fdisk_info(cxt
,_("Bootfile is changed to \"%s\"."), name
);
465 static int sgi_write_disklabel(struct fdisk_context
*cxt
)
467 struct sgi_disklabel
*sgilabel
;
468 struct sgi_info
*info
= NULL
;
472 assert(fdisk_is_disklabel(cxt
, SGI
));
474 sgilabel
= self_disklabel(cxt
);
476 sgilabel
->csum
= cpu_to_be32(sgi_pt_checksum(sgilabel
));
478 assert(sgi_pt_checksum(sgilabel
) == 0);
480 if (lseek(cxt
->dev_fd
, 0, SEEK_SET
) < 0)
482 if (write_all(cxt
->dev_fd
, sgilabel
, DEFAULT_SECTOR_SIZE
))
484 if (!strncmp((char *) sgilabel
->volume
[0].name
, "sgilabel", 8)) {
486 * keep this habit of first writing the "sgilabel".
487 * I never tested whether it works without (AN 981002).
490 = be32_to_cpu(sgilabel
->volume
[0].block_num
);
492 if (lseek(cxt
->dev_fd
, (off_t
) infostartblock
*
493 DEFAULT_SECTOR_SIZE
, SEEK_SET
) < 0)
495 info
= sgi_new_info();
498 if (write_all(cxt
->dev_fd
, info
, sizeof(*info
)))
509 static int compare_start(struct fdisk_context
*cxt
,
510 const void *x
, const void *y
)
513 * sort according to start sectors and prefers largest partition: entry
514 * zero is entire disk entry
516 unsigned int i
= *(int *) x
;
517 unsigned int j
= *(int *) y
;
518 unsigned int a
= sgi_get_start_sector(cxt
, i
);
519 unsigned int b
= sgi_get_start_sector(cxt
, j
);
520 unsigned int c
= sgi_get_num_sectors(cxt
, i
);
521 unsigned int d
= sgi_get_num_sectors(cxt
, j
);
524 return (d
> c
) ? 1 : (d
== c
) ? 0 : -1;
525 return (a
> b
) ? 1 : -1;
528 static void generic_swap(void *a0
, void *b0
, int size
)
530 char *a
= a0
, *b
= b0
;
532 for (; size
> 0; --size
, a
++, b
++) {
540 /* heap sort, based on Matt Mackall's linux kernel version */
541 static void sort(void *base0
, size_t num
, size_t size
, struct fdisk_context
*cxt
,
542 int (*cmp_func
)(struct fdisk_context
*, const void *, const void *))
544 /* pre-scale counters for performance */
545 int i
= (num
/2 - 1) * size
;
546 size_t n
= num
* size
, c
, r
;
550 for ( ; i
>= 0; i
-= size
) {
551 for (r
= i
; r
* 2 + size
< n
; r
= c
) {
554 cmp_func(cxt
, base
+ c
, base
+ c
+ size
) < 0)
556 if (cmp_func(cxt
, base
+ r
, base
+ c
) >= 0)
558 generic_swap(base
+ r
, base
+ c
, size
);
563 for (i
= n
- size
; i
> 0; i
-= size
) {
564 generic_swap(base
, base
+ i
, size
);
565 for (r
= 0; r
* 2 + size
< (size_t) i
; r
= c
) {
568 cmp_func(cxt
, base
+ c
, base
+ c
+ size
) < 0)
570 if (cmp_func(cxt
, base
+ r
, base
+ c
) >= 0)
572 generic_swap(base
+ r
, base
+ c
, size
);
577 static int verify_disklabel(struct fdisk_context
*cxt
, int verbose
)
579 int Index
[SGI_MAXPARTITIONS
]; /* list of valid partitions */
580 int sortcount
= 0; /* number of used partitions, i.e. non-zero lengths */
581 int entire
= 0, i
= 0;
582 unsigned int start
= 0;
583 long long gap
= 0; /* count unused blocks */
584 unsigned int lastblock
= sgi_get_lastblock(cxt
);
588 assert(fdisk_is_disklabel(cxt
, SGI
));
591 memset(Index
, 0, sizeof(Index
));
593 for (i
=0; i
< SGI_MAXPARTITIONS
; i
++) {
594 if (sgi_get_num_sectors(cxt
, i
) != 0) {
595 Index
[sortcount
++] = i
;
596 if (sgi_get_sysid(cxt
, i
) == SGI_TYPE_ENTIRE_DISK
599 fdisk_info(cxt
, _("More than one entire "
600 "disk entry present."));
604 if (sortcount
== 0) {
606 fdisk_info(cxt
, _("No partitions defined"));
607 return (lastblock
> 0) ? 1 : (lastblock
== 0) ? 0 : -1;
610 sort(Index
, sortcount
, sizeof(Index
[0]), cxt
, compare_start
);
612 if (sgi_get_sysid(cxt
, Index
[0]) == SGI_TYPE_ENTIRE_DISK
) {
613 if (verbose
&& Index
[0] != 10)
614 fdisk_info(cxt
, _("IRIX likes when Partition 11 "
615 "covers the entire disk."));
617 if (verbose
&& sgi_get_start_sector(cxt
, Index
[0]) != 0)
618 fdisk_info(cxt
, _("The entire disk partition should "
619 "start at block 0, not at diskblock %d."),
620 sgi_get_start_sector(cxt
, Index
[0]));
622 if (verbose
&& sgi_get_num_sectors(cxt
, Index
[0]) != lastblock
)
624 "entire disk partition=%ds, but disk=%ds",
625 sgi_get_num_sectors(cxt
, Index
[0]),
627 lastblock
= sgi_get_num_sectors(cxt
, Index
[0]);
628 } else if (verbose
) {
629 fdisk_info(cxt
, _("Partition 11 should cover the entire disk."));
630 DBG(LABEL
, dbgprint("sysid=%d\tpartition=%d",
631 sgi_get_sysid(cxt
, Index
[0]), Index
[0]+1));
633 for (i
=1, start
=0; i
<sortcount
; i
++) {
634 int cylsize
= sgi_get_nsect(cxt
) * sgi_get_ntrks(cxt
);
636 if (verbose
&& cylsize
637 && (sgi_get_start_sector(cxt
, Index
[i
]) % cylsize
) != 0)
638 DBG(LABEL
, dbgprint("partition %d does not start on "
639 "cylinder boundary.", Index
[i
]+1));
641 if (verbose
&& cylsize
642 && sgi_get_num_sectors(cxt
, Index
[i
]) % cylsize
!= 0)
643 DBG(LABEL
, dbgprint("partition %d does not end on "
644 "cylinder boundary.", Index
[i
]+1));
646 /* We cannot handle several "entire disk" entries. */
647 if (sgi_get_sysid(cxt
, Index
[i
]) == SGI_TYPE_ENTIRE_DISK
)
649 if (start
> sgi_get_start_sector(cxt
, Index
[i
])) {
651 fdisk_info(cxt
, _("The Partition %d and %d overlap "
653 Index
[i
-1]+1, Index
[i
]+1,
654 start
- sgi_get_start_sector(cxt
, Index
[i
]));
655 if (gap
> 0) gap
= -gap
;
656 if (gap
== 0) gap
= -1;
658 if (start
< sgi_get_start_sector(cxt
, Index
[i
])) {
660 fdisk_info(cxt
, _("Unused gap of %8u sectors "
662 sgi_get_start_sector(cxt
, Index
[i
]) - start
,
663 start
, sgi_get_start_sector(cxt
, Index
[i
])-1);
664 gap
+= sgi_get_start_sector(cxt
, Index
[i
]) - start
;
665 add_to_freelist(cxt
, start
,
666 sgi_get_start_sector(cxt
, Index
[i
]));
668 start
= sgi_get_start_sector(cxt
, Index
[i
])
669 + sgi_get_num_sectors(cxt
, Index
[i
]);
670 /* Align free space on cylinder boundary */
671 if (cylsize
&& start
% cylsize
)
672 start
+= cylsize
- (start
% cylsize
);
674 DBG(LABEL
, dbgprint("%2d:%12d\t%12d\t%12d", Index
[i
],
675 sgi_get_start_sector(cxt
, Index
[i
]),
676 sgi_get_num_sectors(cxt
, Index
[i
]),
677 sgi_get_sysid(cxt
, Index
[i
])));
679 if (start
< lastblock
) {
681 fdisk_info(cxt
, _("Unused gap of %8u sectors - sectors %8u-%u"),
682 lastblock
- start
, start
, lastblock
-1);
683 gap
+= lastblock
- start
;
684 add_to_freelist(cxt
, start
, lastblock
);
687 * Done with arithmetics. Go for details now
690 if (sgi_get_bootpartition(cxt
) < 0
691 || !sgi_get_num_sectors(cxt
, sgi_get_bootpartition(cxt
)))
692 fdisk_info(cxt
, _("The boot partition does not exist."));
694 if (sgi_get_swappartition(cxt
) < 0
695 || !sgi_get_num_sectors(cxt
, sgi_get_swappartition(cxt
)))
696 fdisk_info(cxt
, _("The swap partition does not exist."));
698 else if (sgi_get_sysid(cxt
, sgi_get_swappartition(cxt
)) != SGI_TYPE_SWAP
699 && sgi_get_sysid(cxt
, sgi_get_swappartition(cxt
)) != MBR_LINUX_SWAP_PARTITION
)
700 fdisk_info(cxt
, _("The swap partition has no swap type."));
702 if (sgi_check_bootfile(cxt
, "/unix"))
703 fdisk_info(cxt
, _("You have chosen an unusual boot "
707 return (gap
> 0) ? 1 : (gap
== 0) ? 0 : -1;
710 static int sgi_verify_disklabel(struct fdisk_context
*cxt
)
712 return verify_disklabel(cxt
, 1);
715 static int sgi_gaps(struct fdisk_context
*cxt
)
719 * = 0 : disk is properly filled to the rim
720 * < 0 : there is an overlap
721 * > 0 : there is still some vacant space
723 return verify_disklabel(cxt
, 0);
726 /* returns partition index of first entry marked as entire disk */
727 static int sgi_entire(struct fdisk_context
*cxt
)
731 for (i
= 0; i
< SGI_MAXPARTITIONS
; i
++)
732 if (sgi_get_sysid(cxt
, i
) == SGI_TYPE_ENTIRE_DISK
)
737 static int sgi_set_partition(struct fdisk_context
*cxt
, size_t i
,
738 unsigned int start
, unsigned int length
, int sys
)
740 struct sgi_disklabel
*sgilabel
;
744 assert(fdisk_is_disklabel(cxt
, SGI
));
746 sgilabel
= self_disklabel(cxt
);
747 sgilabel
->partitions
[i
].type
= cpu_to_be32(sys
);
748 sgilabel
->partitions
[i
].num_blocks
= cpu_to_be32(length
);
749 sgilabel
->partitions
[i
].first_block
= cpu_to_be32(start
);
751 fdisk_label_set_changed(cxt
->label
, 1);
753 if (sgi_gaps(cxt
) < 0) /* rebuild freelist */
754 fdisk_warnx(cxt
, _("Partition overlap on the disk."));
756 struct fdisk_parttype
*t
= fdisk_get_parttype_from_code(cxt
, sys
);
757 fdisk_info_new_partition(cxt
, i
+ 1, start
, start
+ length
, t
);
763 static void sgi_set_entire(struct fdisk_context
*cxt
)
767 for (n
= 10; n
< cxt
->label
->nparts_max
; n
++) {
768 if (!sgi_get_num_sectors(cxt
, n
)) {
769 sgi_set_partition(cxt
, n
, 0, sgi_get_lastblock(cxt
), SGI_TYPE_ENTIRE_DISK
);
775 static void sgi_set_volhdr(struct fdisk_context
*cxt
)
779 for (n
= 8; n
< cxt
->label
->nparts_max
; n
++) {
780 if (!sgi_get_num_sectors(cxt
, n
)) {
782 * Choose same default volume header size
785 if (4096 < sgi_get_lastblock(cxt
))
786 sgi_set_partition(cxt
, n
, 0, 4096, SGI_TYPE_VOLHDR
);
792 static int sgi_delete_partition(struct fdisk_context
*cxt
, size_t partnum
)
799 if (partnum
> cxt
->label
->nparts_max
)
802 rc
= sgi_set_partition(cxt
, partnum
, 0, 0, 0);
804 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
809 static int sgi_add_partition(struct fdisk_context
*cxt
,
811 struct fdisk_parttype
*t
)
813 struct fdisk_sgi_label
*sgi
;
815 unsigned int first
= 0, last
= 0;
816 struct fdisk_ask
*ask
;
817 int sys
= t
? t
->type
: SGI_TYPE_XFS
;
822 assert(fdisk_is_disklabel(cxt
, SGI
));
825 sys
= SGI_TYPE_ENTIRE_DISK
;
829 sgi
= self_label(cxt
);
831 if (sgi_get_num_sectors(cxt
, n
)) {
832 fdisk_warnx(cxt
, _("Partition %zd is already defined. Delete "
833 "it before re-adding it."), n
+ 1);
836 if (sgi_entire(cxt
) == -1 && sys
!= SGI_TYPE_ENTIRE_DISK
) {
837 fdisk_info(cxt
, _("Attempting to generate entire disk entry automatically."));
841 if (sgi_gaps(cxt
) == 0 && sys
!= SGI_TYPE_ENTIRE_DISK
) {
842 fdisk_warnx(cxt
, _("The entire disk is already covered with partitions."));
845 if (sgi_gaps(cxt
) < 0) {
846 fdisk_warnx(cxt
, _("You got a partition overlap on the disk. Fix it first!"));
850 snprintf(mesg
, sizeof(mesg
), _("First %s"),
851 fdisk_context_get_unit(cxt
, SINGULAR
));
853 ask
= fdisk_new_ask();
857 fdisk_ask_set_query(ask
, mesg
);
858 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_NUMBER
);
860 if (sys
== SGI_TYPE_ENTIRE_DISK
) {
861 last
= sgi_get_lastblock(cxt
);
862 fdisk_ask_number_set_low(ask
, 0); /* minimal */
863 fdisk_ask_number_set_default(ask
, 0); /* default */
864 fdisk_ask_number_set_high(ask
, last
- 1); /* maximal */
866 first
= sgi
->freelist
[0].first
;
867 last
= sgi
->freelist
[0].last
;
868 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
869 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, first
)); /* default */
870 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, last
) - 1); /* maximal */
872 rc
= fdisk_do_ask(cxt
, ask
);
873 first
= fdisk_ask_number_get_result(ask
);
879 if (first
&& sys
== SGI_TYPE_ENTIRE_DISK
)
880 fdisk_info(cxt
, _("It is highly recommended that "
881 "eleventh partition covers the entire "
882 "disk and is of type `SGI volume'"));
884 if (fdisk_context_use_cylinders(cxt
))
885 first
*= fdisk_context_get_units_per_sector(cxt
);
887 first = first; * align to cylinder if you know how ... */
889 last
= is_in_freelist(cxt
, first
);
891 fdisk_warnx(cxt
, _("You will get a partition overlap "
892 "on the disk. Fix it first!"));
897 snprintf(mesg
, sizeof(mesg
),
898 _("Last %s or +%s or +size{K,M,G,T,P}"),
899 fdisk_context_get_unit(cxt
, SINGULAR
),
900 fdisk_context_get_unit(cxt
, PLURAL
));
902 ask
= fdisk_new_ask();
906 fdisk_ask_set_query(ask
, mesg
);
907 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_OFFSET
);
909 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
910 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, last
) - 1);/* default */
911 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, last
) - 1);/* maximal */
912 fdisk_ask_number_set_base(ask
, fdisk_scround(cxt
, first
));
914 if (fdisk_context_use_cylinders(cxt
))
915 fdisk_ask_number_set_unit(ask
,
917 fdisk_context_get_units_per_sector(cxt
));
919 fdisk_ask_number_set_unit(ask
,cxt
->sector_size
);
921 rc
= fdisk_do_ask(cxt
, ask
);
922 last
= fdisk_ask_number_get_result(ask
) + 1;
928 if (sys
== SGI_TYPE_ENTIRE_DISK
929 && (first
!= 0 || last
!= sgi_get_lastblock(cxt
)))
930 fdisk_info(cxt
, _("It is highly recommended that eleventh "
931 "partition covers the entire disk and is of type "
934 sgi_set_partition(cxt
, n
, first
, last
- first
, sys
);
935 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
940 static int sgi_create_disklabel(struct fdisk_context
*cxt
)
942 struct fdisk_sgi_label
*sgi
;
943 struct sgi_disklabel
*sgilabel
;
944 struct hd_geometry geometry
;
946 int res
; /* the result from the ioctl */
947 int sec_fac
; /* the sector factor */
951 assert(fdisk_is_disklabel(cxt
, SGI
));
953 sec_fac
= cxt
->sector_size
/ 512; /* determine the sector factor */
955 fdisk_info(cxt
, _("Building a new SGI disklabel."));
957 res
= blkdev_get_sectors(cxt
->dev_fd
, &llsectors
);
960 /* TODO: it seems unnecessary, geometry is already set in the context */
961 if (ioctl(cxt
->dev_fd
, HDIO_GETGEO
, &geometry
) < 0) {
962 fdisk_warn(cxt
, _("HDIO_GETGEO ioctl failed on %s"), cxt
->dev_path
);
965 cxt
->geom
.heads
= geometry
.heads
;
966 cxt
->geom
.sectors
= geometry
.sectors
;
968 /* the get device size ioctl was successful */
970 llcyls
= llsectors
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
* sec_fac
);
971 cxt
->geom
.cylinders
= llcyls
;
972 if (cxt
->geom
.cylinders
!= llcyls
) /* truncated? */
973 cxt
->geom
.cylinders
= ~0;
975 /* otherwise print error and use truncated version */
976 cxt
->geom
.cylinders
= geometry
.cylinders
;
978 _("Warning: BLKGETSIZE ioctl failed on %s. "
979 "Using geometry cylinder value of %llu."
980 "This value may be truncated for devices"
981 " > 33.8 GB."), cxt
->dev_path
, cxt
->geom
.cylinders
);
984 fdisk_zeroize_firstsector(cxt
);
985 sgi
= (struct fdisk_sgi_label
*) cxt
->label
;
986 sgi
->header
= (struct sgi_disklabel
*) cxt
->firstsector
;
988 sgilabel
= sgi
->header
;
990 sgilabel
->magic
= cpu_to_be32(SGI_LABEL_MAGIC
);
991 sgilabel
->root_part_num
= cpu_to_be16(0);
992 sgilabel
->swap_part_num
= cpu_to_be16(1);
994 /* sizeof(sgilabel->boot_file) = 16 > 6 */
995 memset(sgilabel
->boot_file
, 0, 16);
996 strcpy((char *) sgilabel
->boot_file
, "/unix");
998 sgilabel
->devparam
.skew
= (0);
999 sgilabel
->devparam
.gap1
= (0);
1000 sgilabel
->devparam
.gap2
= (0);
1001 sgilabel
->devparam
.sparecyl
= (0);
1002 sgilabel
->devparam
.pcylcount
= cpu_to_be16(geometry
.cylinders
);
1003 sgilabel
->devparam
.head_vol0
= cpu_to_be16(0);
1004 sgilabel
->devparam
.ntrks
= cpu_to_be16(geometry
.heads
);
1005 /* tracks/cylinder (heads) */
1006 sgilabel
->devparam
.cmd_tag_queue_depth
= (0);
1007 sgilabel
->devparam
.unused0
= (0);
1008 sgilabel
->devparam
.unused1
= cpu_to_be16(0);
1009 sgilabel
->devparam
.nsect
= cpu_to_be16(geometry
.sectors
);
1011 sgilabel
->devparam
.bytes
= cpu_to_be16(cxt
->sector_size
);
1012 sgilabel
->devparam
.ilfact
= cpu_to_be16(1);
1013 sgilabel
->devparam
.flags
= cpu_to_be32(
1014 SGI_DEVPARAM_TRACK_FWD
1015 | SGI_DEVPARAM_IGNORE_ERRORS
1016 | SGI_DEVPARAM_RESEEK
);
1017 sgilabel
->devparam
.datarate
= cpu_to_be32(0);
1018 sgilabel
->devparam
.retries_on_error
= cpu_to_be32(1);
1019 sgilabel
->devparam
.ms_per_word
= cpu_to_be32(0);
1020 sgilabel
->devparam
.xylogics_gap1
= cpu_to_be16(0);
1021 sgilabel
->devparam
.xylogics_syncdelay
= cpu_to_be16(0);
1022 sgilabel
->devparam
.xylogics_readdelay
= cpu_to_be16(0);
1023 sgilabel
->devparam
.xylogics_gap2
= cpu_to_be16(0);
1024 sgilabel
->devparam
.xylogics_readgate
= cpu_to_be16(0);
1025 sgilabel
->devparam
.xylogics_writecont
= cpu_to_be16(0);
1027 memset(&(sgilabel
->volume
), 0,
1028 sizeof(struct sgi_volume
) * SGI_MAXVOLUMES
);
1029 memset(&(sgilabel
->partitions
), 0,
1030 sizeof(struct sgi_partition
) * SGI_MAXPARTITIONS
);
1031 cxt
->label
->nparts_max
= SGI_MAXPARTITIONS
;
1032 sgi_set_entire(cxt
);
1033 sgi_set_volhdr(cxt
);
1035 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
1039 static struct fdisk_parttype
*sgi_get_parttype(struct fdisk_context
*cxt
, size_t n
)
1041 struct fdisk_parttype
*t
;
1043 if (n
>= cxt
->label
->nparts_max
)
1046 t
= fdisk_get_parttype_from_code(cxt
, sgi_get_sysid(cxt
, n
));
1048 t
= fdisk_new_unknown_parttype(sgi_get_sysid(cxt
, n
), NULL
);
1052 static int sgi_set_parttype(struct fdisk_context
*cxt
,
1054 struct fdisk_parttype
*t
)
1056 struct sgi_disklabel
*sgilabel
;
1058 if (i
>= cxt
->label
->nparts_max
|| !t
|| t
->type
> UINT32_MAX
)
1061 if (sgi_get_num_sectors(cxt
, i
) == 0) /* caught already before, ... */ {
1062 fdisk_warnx(cxt
, _("Sorry, only for non-empty partitions you can change the tag."));
1066 if ((i
== 10 && t
->type
!= SGI_TYPE_ENTIRE_DISK
)
1067 || (i
== 8 && t
->type
!= 0))
1068 fdisk_info(cxt
, _("Consider leaving partition 9 as volume header (0), "
1069 "and partition 11 as entire volume (6), as IRIX "
1072 if (((t
->type
!= SGI_TYPE_ENTIRE_DISK
) && (t
->type
!= SGI_TYPE_VOLHDR
))
1073 && (sgi_get_start_sector(cxt
, i
) < 1)) {
1075 fdisk_ask_yesno(cxt
,
1076 _("It is highly recommended that the partition at offset 0 "
1077 "is of type \"SGI volhdr\", the IRIX system will rely on it to "
1078 "retrieve from its directory standalone tools like sash and fx. "
1079 "Only the \"SGI volume\" entire disk section may violate this. "
1080 "Are you sure about tagging this partition differently?"), &yes
);
1085 sgilabel
= self_disklabel(cxt
);
1086 sgilabel
->partitions
[i
].type
= cpu_to_be32(t
->type
);
1091 static int sgi_get_partition_status(
1092 struct fdisk_context
*cxt
,
1098 assert(fdisk_is_disklabel(cxt
, SGI
));
1100 if (!status
|| i
>= cxt
->label
->nparts_max
)
1103 *status
= FDISK_PARTSTAT_NONE
;
1105 if (sgi_get_num_sectors(cxt
, i
))
1106 *status
= FDISK_PARTSTAT_USED
;
1111 static int sgi_toggle_partition_flag(struct fdisk_context
*cxt
, size_t i
, unsigned long flag
)
1113 struct sgi_disklabel
*sgilabel
;
1116 assert(fdisk_is_disklabel(cxt
, SGI
));
1118 if (i
>= cxt
->label
->nparts_max
)
1121 sgilabel
= self_disklabel(cxt
);
1125 sgilabel
->root_part_num
=
1126 be16_to_cpu(sgilabel
->root_part_num
) == i
?
1128 fdisk_label_set_changed(cxt
->label
, 1);
1131 sgilabel
->swap_part_num
=
1132 be16_to_cpu(sgilabel
->swap_part_num
) == i
?
1134 fdisk_label_set_changed(cxt
->label
, 1);
1143 static const struct fdisk_label_operations sgi_operations
=
1145 .probe
= sgi_probe_label
,
1146 .write
= sgi_write_disklabel
,
1147 .verify
= sgi_verify_disklabel
,
1148 .create
= sgi_create_disklabel
,
1149 .list
= sgi_list_table
,
1150 .part_add
= sgi_add_partition
,
1151 .part_delete
= sgi_delete_partition
,
1152 .part_get_type
= sgi_get_parttype
,
1153 .part_set_type
= sgi_set_parttype
,
1155 .part_get_status
= sgi_get_partition_status
,
1156 .part_toggle_flag
= sgi_toggle_partition_flag
1160 * allocates SGI label driver
1162 struct fdisk_label
*fdisk_new_sgi_label(struct fdisk_context
*cxt
)
1164 struct fdisk_label
*lb
;
1165 struct fdisk_sgi_label
*sgi
;
1169 sgi
= calloc(1, sizeof(*sgi
));
1173 /* initialize generic part of the driver */
1174 lb
= (struct fdisk_label
*) sgi
;
1176 lb
->id
= FDISK_DISKLABEL_SGI
;
1177 lb
->op
= &sgi_operations
;
1178 lb
->parttypes
= sgi_parttypes
;
1179 lb
->nparttypes
= ARRAY_SIZE(sgi_parttypes
);
1181 lb
->flags
|= FDISK_LABEL_FL_REQUIRE_GEOMETRY
;