3 * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org>
4 * 2013 Karel Zak <kzak@redhat.com>
6 * This is a 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.
14 #include <libsmartcols.h>
27 * in-memory fdisk SGI stuff
29 struct fdisk_sgi_label
{
30 struct fdisk_label head
; /* generic fdisk part */
31 struct sgi_disklabel
*header
; /* on-disk data (pointer to cxt->firstsector) */
33 struct sgi_freeblocks
{
36 } freelist
[SGI_MAXPARTITIONS
+ 1];
39 static struct fdisk_parttype sgi_parttypes
[] =
41 {SGI_TYPE_VOLHDR
, N_("SGI volhdr")},
42 {SGI_TYPE_TRKREPL
, N_("SGI trkrepl")},
43 {SGI_TYPE_SECREPL
, N_("SGI secrepl")},
44 {SGI_TYPE_SWAP
, N_("SGI raw")},
45 {SGI_TYPE_BSD
, N_("SGI bsd")},
46 {SGI_TYPE_SYSV
, N_("SGI sysv")},
47 {SGI_TYPE_ENTIRE_DISK
, N_("SGI volume")},
48 {SGI_TYPE_EFS
, N_("SGI efs")},
49 {SGI_TYPE_LVOL
, N_("SGI lvol")},
50 {SGI_TYPE_RLVOL
, N_("SGI rlvol")},
51 {SGI_TYPE_XFS
, N_("SGI xfs")},
52 {SGI_TYPE_XFSLOG
, N_("SGI xfslog")},
53 {SGI_TYPE_XLV
, N_("SGI xlv")},
54 {SGI_TYPE_XVM
, N_("SGI xvm")},
55 {MBR_LINUX_SWAP_PARTITION
, N_("Linux swap")},
56 {MBR_LINUX_DATA_PARTITION
, N_("Linux native")},
57 {MBR_LINUX_LVM_PARTITION
, N_("Linux LVM")},
58 {MBR_LINUX_RAID_PARTITION
, N_("Linux RAID")},
62 static unsigned int sgi_get_start_sector(struct fdisk_context
*cxt
, int i
);
63 static unsigned int sgi_get_num_sectors(struct fdisk_context
*cxt
, int i
);
64 static int sgi_get_bootpartition(struct fdisk_context
*cxt
);
65 static int sgi_get_swappartition(struct fdisk_context
*cxt
);
67 /* Returns a pointer buffer with on-disk data. */
68 static inline struct sgi_disklabel
*self_disklabel(struct fdisk_context
*cxt
)
72 assert(fdisk_is_disklabel(cxt
, SGI
));
74 return ((struct fdisk_sgi_label
*) cxt
->label
)->header
;
77 /* Returns in-memory fdisk data. */
78 static inline struct fdisk_sgi_label
*self_label(struct fdisk_context
*cxt
)
82 assert(fdisk_is_disklabel(cxt
, SGI
));
84 return (struct fdisk_sgi_label
*) cxt
->label
;
88 * Information within second on-disk block
90 #define SGI_INFO_MAGIC 0x00072959
93 unsigned int magic
; /* looks like a magic number */
102 unsigned char scsi_string
[50];
103 unsigned char serial
[137];
104 unsigned short check1816
;
105 unsigned char installer
[225];
108 static struct sgi_info
*sgi_new_info(void)
110 struct sgi_info
*info
= calloc(1, sizeof(struct sgi_info
));
115 info
->magic
= cpu_to_be32(SGI_INFO_MAGIC
);
116 info
->b1
= cpu_to_be32(-1);
117 info
->b2
= cpu_to_be16(-1);
118 info
->b3
= cpu_to_be16(1);
120 /* You may want to replace this string !!!!!!! */
121 strcpy((char *) info
->scsi_string
, "IBM OEM 0662S12 3 30");
122 strcpy((char *) info
->serial
, "0000");
123 info
->check1816
= cpu_to_be16(18 * 256 + 16);
124 strcpy((char *) info
->installer
, "Sfx version 5.3, Oct 18, 1994");
129 static void sgi_free_info(struct sgi_info
*info
)
134 int fdisk_sgi_create_info(struct fdisk_context
*cxt
)
136 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
138 /* I keep SGI's habit to write the sgilabel to the second block */
139 sgilabel
->volume
[0].block_num
= cpu_to_be32(2);
140 sgilabel
->volume
[0].num_bytes
= cpu_to_be32(sizeof(struct sgi_info
));
141 strncpy((char *) sgilabel
->volume
[0].name
, "sgilabel", 8);
143 fdisk_info(cxt
, _("SGI info created on second sector"));
149 * only dealing with free blocks here
151 static void set_freelist(struct fdisk_context
*cxt
,
152 size_t i
, unsigned int f
, unsigned int l
)
154 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
156 if (i
< ARRAY_SIZE(sgi
->freelist
)) {
157 sgi
->freelist
[i
].first
= f
;
158 sgi
->freelist
[i
].last
= l
;
162 static void add_to_freelist(struct fdisk_context
*cxt
,
163 unsigned int f
, unsigned int l
)
165 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
168 for (i
= 0; i
< ARRAY_SIZE(sgi
->freelist
); i
++) {
169 if (sgi
->freelist
[i
].last
== 0)
172 set_freelist(cxt
, i
, f
, l
);
175 static void clear_freelist(struct fdisk_context
*cxt
)
177 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
179 memset(sgi
->freelist
, 0, sizeof(sgi
->freelist
));
182 static unsigned int is_in_freelist(struct fdisk_context
*cxt
, unsigned int b
)
184 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
187 for (i
= 0; i
< ARRAY_SIZE(sgi
->freelist
); i
++) {
188 if (sgi
->freelist
[i
].first
<= b
189 && sgi
->freelist
[i
].last
>= b
)
190 return sgi
->freelist
[i
].last
;
197 static int sgi_get_nsect(struct fdisk_context
*cxt
)
199 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
200 return be16_to_cpu(sgilabel
->devparam
.nsect
);
203 static int sgi_get_ntrks(struct fdisk_context
*cxt
)
205 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
206 return be16_to_cpu(sgilabel
->devparam
.ntrks
);
209 static size_t count_used_partitions(struct fdisk_context
*cxt
)
213 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++)
214 ct
+= sgi_get_num_sectors(cxt
, i
) > 0;
219 static int sgi_probe_label(struct fdisk_context
*cxt
)
221 struct fdisk_sgi_label
*sgi
;
222 struct sgi_disklabel
*sgilabel
;
226 assert(fdisk_is_disklabel(cxt
, SGI
));
227 assert(sizeof(struct sgi_disklabel
) <= 512);
229 /* map first sector to header */
230 sgi
= (struct fdisk_sgi_label
*) cxt
->label
;
231 sgi
->header
= (struct sgi_disklabel
*) cxt
->firstsector
;
232 sgilabel
= sgi
->header
;
234 if (be32_to_cpu(sgilabel
->magic
) != SGI_LABEL_MAGIC
) {
240 * test for correct checksum
242 if (sgi_pt_checksum(sgilabel
) != 0)
243 fdisk_warnx(cxt
, _("Detected an SGI disklabel with wrong checksum."));
246 cxt
->label
->nparts_max
= SGI_MAXPARTITIONS
;
247 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
251 static int sgi_list_table(struct fdisk_context
*cxt
)
253 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
254 struct sgi_device_parameter
*sgiparam
= &sgilabel
->devparam
;
257 if (fdisk_context_display_details(cxt
))
259 "Label geometry: %d heads, %llu sectors\n"
260 " %llu cylinders, %d physical cylinders\n"
261 " %d extra sects/cyl, interleave %d:1\n"),
262 cxt
->geom
.heads
, cxt
->geom
.sectors
,
263 cxt
->geom
.cylinders
, be16_to_cpu(sgiparam
->pcylcount
),
264 (int) sgiparam
->sparecyl
, be16_to_cpu(sgiparam
->ilfact
));
266 fdisk_info(cxt
, _("Bootfile: %s"), sgilabel
->boot_file
);
270 static unsigned int sgi_get_start_sector(struct fdisk_context
*cxt
, int i
)
272 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
273 return be32_to_cpu(sgilabel
->partitions
[i
].first_block
);
276 static unsigned int sgi_get_num_sectors(struct fdisk_context
*cxt
, int i
)
278 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
279 return be32_to_cpu(sgilabel
->partitions
[i
].num_blocks
);
282 static int sgi_get_sysid(struct fdisk_context
*cxt
, int i
)
284 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
285 return be32_to_cpu(sgilabel
->partitions
[i
].type
);
288 static int sgi_get_bootpartition(struct fdisk_context
*cxt
)
290 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
291 return be16_to_cpu(sgilabel
->root_part_num
);
294 static int sgi_get_swappartition(struct fdisk_context
*cxt
)
296 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
297 return be16_to_cpu(sgilabel
->swap_part_num
);
300 static unsigned int sgi_get_lastblock(struct fdisk_context
*cxt
)
302 return cxt
->geom
.heads
* cxt
->geom
.sectors
* cxt
->geom
.cylinders
;
305 static struct fdisk_parttype
*sgi_get_parttype(struct fdisk_context
*cxt
, size_t n
)
307 struct fdisk_parttype
*t
;
309 if (n
>= cxt
->label
->nparts_max
)
312 t
= fdisk_get_parttype_from_code(cxt
, sgi_get_sysid(cxt
, n
));
313 return t
? : fdisk_new_unknown_parttype(sgi_get_sysid(cxt
, n
), NULL
);
316 /* fdisk_get_partition() backend */
317 static int sgi_get_partition(struct fdisk_context
*cxt
, size_t n
, struct fdisk_partition
*pa
)
321 pa
->used
= sgi_get_num_sectors(cxt
, n
) > 0;
325 start
= sgi_get_start_sector(cxt
, n
);
326 len
= sgi_get_num_sectors(cxt
, n
);
328 pa
->type
= sgi_get_parttype(cxt
, n
);
331 pa
->end
= start
+ len
- (len
? 1 : 0);
333 if (pa
->type
&& pa
->type
->type
== SGI_TYPE_ENTIRE_DISK
)
336 pa
->attrs
= sgi_get_swappartition(cxt
) == (int) n
? "swap" :
337 sgi_get_bootpartition(cxt
) == (int) n
? "boot" : NULL
;
339 pa
->attrs
= strdup(pa
->attrs
);
345 static int sgi_check_bootfile(struct fdisk_context
*cxt
, const char *name
)
348 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
353 /* "/a\n" is minimum */
354 fdisk_warnx(cxt
, _("Invalid bootfile! The bootfile must "
355 "be an absolute non-zero pathname, "
356 "e.g. \"/unix\" or \"/unix.save\"."));
359 } else if (sz
> sizeof(sgilabel
->boot_file
)) {
360 fdisk_warnx(cxt
, P_("Name of bootfile is too long: %zu byte maximum.",
361 "Name of bootfile is too long: %zu bytes maximum.",
362 sizeof(sgilabel
->boot_file
)),
363 sizeof(sgilabel
->boot_file
));
366 } else if (*name
!= '/') {
367 fdisk_warnx(cxt
, _("Bootfile must have a fully qualified pathname."));
371 if (strncmp(name
, (char *) sgilabel
->boot_file
,
372 sizeof(sgilabel
->boot_file
))) {
373 fdisk_warnx(cxt
, _("Be aware that the bootfile is not checked "
374 "for existence. SGI's default is \"/unix\", "
375 "and for backup \"/unix.save\"."));
376 return 0; /* filename is correct and did change */
379 return 1; /* filename did not change */
382 int fdisk_sgi_set_bootfile(struct fdisk_context
*cxt
)
387 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
389 fdisk_info(cxt
, _("The current boot file is: %s"), sgilabel
->boot_file
);
391 rc
= fdisk_ask_string(cxt
, _("Enter of the new boot file"), &name
);
393 rc
= sgi_check_bootfile(cxt
, name
);
396 fdisk_info(cxt
, _("Boot file is unchanged."));
400 memset(sgilabel
->boot_file
, 0, sizeof(sgilabel
->boot_file
));
403 assert(sz
<= sizeof(sgilabel
->boot_file
)); /* see sgi_check_bootfile() */
405 memcpy(sgilabel
->boot_file
, name
, sz
);
407 fdisk_sinfo(cxt
, FDISK_INFO_SUCCESS
,
408 _("Bootfile has been changed to \"%s\"."), name
);
414 static int sgi_write_disklabel(struct fdisk_context
*cxt
)
416 struct sgi_disklabel
*sgilabel
;
417 struct sgi_info
*info
= NULL
;
421 assert(fdisk_is_disklabel(cxt
, SGI
));
423 sgilabel
= self_disklabel(cxt
);
425 sgilabel
->csum
= cpu_to_be32(sgi_pt_checksum(sgilabel
));
427 assert(sgi_pt_checksum(sgilabel
) == 0);
429 if (lseek(cxt
->dev_fd
, 0, SEEK_SET
) < 0)
431 if (write_all(cxt
->dev_fd
, sgilabel
, DEFAULT_SECTOR_SIZE
))
433 if (!strncmp((char *) sgilabel
->volume
[0].name
, "sgilabel", 8)) {
435 * Keep this habit of first writing the "sgilabel".
436 * I never tested whether it works without. (AN 1998-10-02)
439 = be32_to_cpu(sgilabel
->volume
[0].block_num
);
441 if (lseek(cxt
->dev_fd
, (off_t
) infostartblock
*
442 DEFAULT_SECTOR_SIZE
, SEEK_SET
) < 0)
444 info
= sgi_new_info();
447 if (write_all(cxt
->dev_fd
, info
, sizeof(*info
)))
458 static int compare_start(struct fdisk_context
*cxt
,
459 const void *x
, const void *y
)
462 * Sort according to start sectors and prefer the largest partition:
463 * entry zero is the entire-disk entry.
465 unsigned int i
= *(int *) x
;
466 unsigned int j
= *(int *) y
;
467 unsigned int a
= sgi_get_start_sector(cxt
, i
);
468 unsigned int b
= sgi_get_start_sector(cxt
, j
);
469 unsigned int c
= sgi_get_num_sectors(cxt
, i
);
470 unsigned int d
= sgi_get_num_sectors(cxt
, j
);
473 return (d
> c
) ? 1 : (d
== c
) ? 0 : -1;
474 return (a
> b
) ? 1 : -1;
477 static void generic_swap(void *a0
, void *b0
, int size
)
479 char *a
= a0
, *b
= b0
;
481 for (; size
> 0; --size
, a
++, b
++) {
489 /* heap sort, based on Matt Mackall's linux kernel version */
490 static void sort(void *base0
, size_t num
, size_t size
, struct fdisk_context
*cxt
,
491 int (*cmp_func
)(struct fdisk_context
*, const void *, const void *))
493 /* pre-scale counters for performance */
494 int i
= (num
/2 - 1) * size
;
495 size_t n
= num
* size
, c
, r
;
499 for ( ; i
>= 0; i
-= size
) {
500 for (r
= i
; r
* 2 + size
< n
; r
= c
) {
503 cmp_func(cxt
, base
+ c
, base
+ c
+ size
) < 0)
505 if (cmp_func(cxt
, base
+ r
, base
+ c
) >= 0)
507 generic_swap(base
+ r
, base
+ c
, size
);
512 for (i
= n
- size
; i
> 0; i
-= size
) {
513 generic_swap(base
, base
+ i
, size
);
514 for (r
= 0; r
* 2 + size
< (size_t) i
; r
= c
) {
517 cmp_func(cxt
, base
+ c
, base
+ c
+ size
) < 0)
519 if (cmp_func(cxt
, base
+ r
, base
+ c
) >= 0)
521 generic_swap(base
+ r
, base
+ c
, size
);
526 static int verify_disklabel(struct fdisk_context
*cxt
, int verbose
)
528 int Index
[SGI_MAXPARTITIONS
]; /* list of valid partitions */
529 int sortcount
= 0; /* number of used partitions, i.e. non-zero lengths */
530 int entire
= 0, i
= 0;
531 unsigned int start
= 0;
532 long long gap
= 0; /* count unused blocks */
533 unsigned int lastblock
= sgi_get_lastblock(cxt
);
537 assert(fdisk_is_disklabel(cxt
, SGI
));
540 memset(Index
, 0, sizeof(Index
));
542 for (i
=0; i
< SGI_MAXPARTITIONS
; i
++) {
543 if (sgi_get_num_sectors(cxt
, i
) != 0) {
544 Index
[sortcount
++] = i
;
545 if (sgi_get_sysid(cxt
, i
) == SGI_TYPE_ENTIRE_DISK
548 fdisk_info(cxt
, _("More than one entire "
549 "disk entry present."));
553 if (sortcount
== 0) {
555 fdisk_info(cxt
, _("No partitions defined."));
556 return (lastblock
> 0) ? 1 : (lastblock
== 0) ? 0 : -1;
559 sort(Index
, sortcount
, sizeof(Index
[0]), cxt
, compare_start
);
561 if (sgi_get_sysid(cxt
, Index
[0]) == SGI_TYPE_ENTIRE_DISK
) {
562 if (verbose
&& Index
[0] != 10)
563 fdisk_info(cxt
, _("IRIX likes it when partition 11 "
564 "covers the entire disk."));
566 if (verbose
&& sgi_get_start_sector(cxt
, Index
[0]) != 0)
567 fdisk_info(cxt
, _("The entire disk partition should "
568 "start at block 0, not at block %d."),
569 sgi_get_start_sector(cxt
, Index
[0]));
571 if (verbose
&& sgi_get_num_sectors(cxt
, Index
[0]) != lastblock
)
573 "entire disk partition=%ds, but disk=%ds",
574 sgi_get_num_sectors(cxt
, Index
[0]),
576 lastblock
= sgi_get_num_sectors(cxt
, Index
[0]);
577 } else if (verbose
) {
578 fdisk_info(cxt
, _("Partition 11 should cover the entire disk."));
579 DBG(LABEL
, ul_debug("sysid=%d\tpartition=%d",
580 sgi_get_sysid(cxt
, Index
[0]), Index
[0]+1));
582 for (i
=1, start
=0; i
<sortcount
; i
++) {
583 int cylsize
= sgi_get_nsect(cxt
) * sgi_get_ntrks(cxt
);
585 if (verbose
&& cylsize
586 && (sgi_get_start_sector(cxt
, Index
[i
]) % cylsize
) != 0)
587 DBG(LABEL
, ul_debug("partition %d does not start on "
588 "cylinder boundary.", Index
[i
]+1));
590 if (verbose
&& cylsize
591 && sgi_get_num_sectors(cxt
, Index
[i
]) % cylsize
!= 0)
592 DBG(LABEL
, ul_debug("partition %d does not end on "
593 "cylinder boundary.", Index
[i
]+1));
595 /* We cannot handle several "entire disk" entries. */
596 if (sgi_get_sysid(cxt
, Index
[i
]) == SGI_TYPE_ENTIRE_DISK
)
599 if (start
> sgi_get_start_sector(cxt
, Index
[i
])) {
602 P_("Partitions %d and %d overlap by %d sector.",
603 "Partitions %d and %d overlap by %d sectors.",
604 start
- sgi_get_start_sector(cxt
, Index
[i
])),
605 Index
[i
-1]+1, Index
[i
]+1,
606 start
- sgi_get_start_sector(cxt
, Index
[i
]));
607 if (gap
> 0) gap
= -gap
;
608 if (gap
== 0) gap
= -1;
610 if (start
< sgi_get_start_sector(cxt
, Index
[i
])) {
613 P_("Unused gap of %8u sector: sector %8u",
614 "Unused gap of %8u sectors: sectors %8u-%u",
615 sgi_get_start_sector(cxt
, Index
[i
]) - start
),
616 sgi_get_start_sector(cxt
, Index
[i
]) - start
,
617 start
, sgi_get_start_sector(cxt
, Index
[i
])-1);
618 gap
+= sgi_get_start_sector(cxt
, Index
[i
]) - start
;
619 add_to_freelist(cxt
, start
,
620 sgi_get_start_sector(cxt
, Index
[i
]));
622 start
= sgi_get_start_sector(cxt
, Index
[i
])
623 + sgi_get_num_sectors(cxt
, Index
[i
]);
624 /* Align free space on cylinder boundary. */
625 if (cylsize
&& start
% cylsize
)
626 start
+= cylsize
- (start
% cylsize
);
628 DBG(LABEL
, ul_debug("%2d:%12d\t%12d\t%12d", Index
[i
],
629 sgi_get_start_sector(cxt
, Index
[i
]),
630 sgi_get_num_sectors(cxt
, Index
[i
]),
631 sgi_get_sysid(cxt
, Index
[i
])));
633 if (start
< lastblock
) {
635 fdisk_info(cxt
, P_("Unused gap of %8u sector: sector %8u",
636 "Unused gap of %8u sectors: sectors %8u-%u",
638 lastblock
- start
, start
, lastblock
-1);
639 gap
+= lastblock
- start
;
640 add_to_freelist(cxt
, start
, lastblock
);
643 * Done with arithmetics. Go for details now.
646 if (sgi_get_bootpartition(cxt
) < 0
647 || !sgi_get_num_sectors(cxt
, sgi_get_bootpartition(cxt
)))
648 fdisk_info(cxt
, _("The boot partition does not exist."));
650 if (sgi_get_swappartition(cxt
) < 0
651 || !sgi_get_num_sectors(cxt
, sgi_get_swappartition(cxt
)))
652 fdisk_info(cxt
, _("The swap partition does not exist."));
654 else if (sgi_get_sysid(cxt
, sgi_get_swappartition(cxt
)) != SGI_TYPE_SWAP
655 && sgi_get_sysid(cxt
, sgi_get_swappartition(cxt
)) != MBR_LINUX_SWAP_PARTITION
)
656 fdisk_info(cxt
, _("The swap partition has no swap type."));
658 if (sgi_check_bootfile(cxt
, "/unix"))
659 fdisk_info(cxt
, _("You have chosen an unusual bootfile name."));
662 return (gap
> 0) ? 1 : (gap
== 0) ? 0 : -1;
665 static int sgi_verify_disklabel(struct fdisk_context
*cxt
)
667 return verify_disklabel(cxt
, 1);
670 static int sgi_gaps(struct fdisk_context
*cxt
)
674 * = 0 : disk is properly filled to the rim
675 * < 0 : there is an overlap
676 * > 0 : there is still some vacant space
678 return verify_disklabel(cxt
, 0);
681 /* Returns partition index of first entry marked as entire disk. */
682 static int sgi_entire(struct fdisk_context
*cxt
)
686 for (i
= 0; i
< SGI_MAXPARTITIONS
; i
++)
687 if (sgi_get_sysid(cxt
, i
) == SGI_TYPE_ENTIRE_DISK
)
692 static int sgi_set_partition(struct fdisk_context
*cxt
, size_t i
,
693 unsigned int start
, unsigned int length
, int sys
)
695 struct sgi_disklabel
*sgilabel
;
699 assert(fdisk_is_disklabel(cxt
, SGI
));
701 sgilabel
= self_disklabel(cxt
);
702 sgilabel
->partitions
[i
].type
= cpu_to_be32(sys
);
703 sgilabel
->partitions
[i
].num_blocks
= cpu_to_be32(length
);
704 sgilabel
->partitions
[i
].first_block
= cpu_to_be32(start
);
706 fdisk_label_set_changed(cxt
->label
, 1);
708 if (sgi_gaps(cxt
) < 0) /* rebuild freelist */
709 fdisk_warnx(cxt
, _("Partition overlap on the disk."));
711 struct fdisk_parttype
*t
= fdisk_get_parttype_from_code(cxt
, sys
);
712 fdisk_info_new_partition(cxt
, i
+ 1, start
, start
+ length
, t
);
718 static void sgi_set_entire(struct fdisk_context
*cxt
)
722 for (n
= 10; n
< cxt
->label
->nparts_max
; n
++) {
723 if (!sgi_get_num_sectors(cxt
, n
)) {
724 sgi_set_partition(cxt
, n
, 0, sgi_get_lastblock(cxt
), SGI_TYPE_ENTIRE_DISK
);
730 static void sgi_set_volhdr(struct fdisk_context
*cxt
)
734 for (n
= 8; n
< cxt
->label
->nparts_max
; n
++) {
735 if (!sgi_get_num_sectors(cxt
, n
)) {
736 /* Choose same default volume header size as IRIX fx uses. */
737 if (4096 < sgi_get_lastblock(cxt
))
738 sgi_set_partition(cxt
, n
, 0, 4096, SGI_TYPE_VOLHDR
);
744 static int sgi_delete_partition(struct fdisk_context
*cxt
, size_t partnum
)
751 if (partnum
> cxt
->label
->nparts_max
)
754 rc
= sgi_set_partition(cxt
, partnum
, 0, 0, 0);
756 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
761 static int sgi_add_partition(struct fdisk_context
*cxt
,
762 struct fdisk_partition
*pa
)
764 struct fdisk_sgi_label
*sgi
;
766 unsigned int first
= 0, last
= 0;
767 struct fdisk_ask
*ask
;
768 int sys
= pa
&& pa
->type
? pa
->type
->type
: SGI_TYPE_XFS
;
774 assert(fdisk_is_disklabel(cxt
, SGI
));
776 rc
= fdisk_partition_next_partno(pa
, cxt
, &n
);
780 sys
= SGI_TYPE_ENTIRE_DISK
;
784 sgi
= self_label(cxt
);
786 if (sgi_get_num_sectors(cxt
, n
)) {
787 fdisk_warnx(cxt
, _("Partition %zu is already defined. "
788 "Delete it before re-adding it."), n
+ 1);
791 if (sgi_entire(cxt
) == -1 && sys
!= SGI_TYPE_ENTIRE_DISK
) {
792 fdisk_info(cxt
, _("Attempting to generate entire disk entry automatically."));
796 if (sgi_gaps(cxt
) == 0 && sys
!= SGI_TYPE_ENTIRE_DISK
) {
797 fdisk_warnx(cxt
, _("The entire disk is already covered with partitions."));
800 if (sgi_gaps(cxt
) < 0) {
801 fdisk_warnx(cxt
, _("You got a partition overlap on the disk. Fix it first!"));
805 if (sys
== SGI_TYPE_ENTIRE_DISK
) {
807 last
= sgi_get_lastblock(cxt
);
809 first
= sgi
->freelist
[0].first
;
810 last
= sgi
->freelist
[0].last
;
814 if (pa
&& pa
->start_follow_default
)
816 else if (pa
&& pa
->start
) {
818 last
= is_in_freelist(cxt
, first
);
820 if (sys
!= SGI_TYPE_ENTIRE_DISK
&& !last
)
823 snprintf(mesg
, sizeof(mesg
), _("First %s"),
824 fdisk_context_get_unit(cxt
, SINGULAR
));
825 ask
= fdisk_new_ask();
829 fdisk_ask_set_query(ask
, mesg
);
830 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_NUMBER
);
832 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
833 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, first
)); /* default */
834 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, last
) - 1); /* maximal */
836 rc
= fdisk_do_ask(cxt
, ask
);
837 first
= fdisk_ask_number_get_result(ask
);
842 if (fdisk_context_use_cylinders(cxt
))
843 first
*= fdisk_context_get_units_per_sector(cxt
);
846 if (first
&& sys
== SGI_TYPE_ENTIRE_DISK
)
847 fdisk_info(cxt
, _("It is highly recommended that the "
848 "eleventh partition covers the entire "
849 "disk and is of type 'SGI volume'."));
851 last
= is_in_freelist(cxt
, first
);
854 if (pa
&& pa
->end_follow_default
)
856 else if (pa
&& pa
->size
) {
857 if (first
+ pa
->size
> last
)
859 last
= first
+ pa
->size
;
861 snprintf(mesg
, sizeof(mesg
),
862 _("Last %s or +%s or +size{K,M,G,T,P}"),
863 fdisk_context_get_unit(cxt
, SINGULAR
),
864 fdisk_context_get_unit(cxt
, PLURAL
));
866 ask
= fdisk_new_ask();
870 fdisk_ask_set_query(ask
, mesg
);
871 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_OFFSET
);
873 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
874 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, last
) - 1);/* default */
875 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, last
) - 1);/* maximal */
876 fdisk_ask_number_set_base(ask
, fdisk_scround(cxt
, first
));
878 if (fdisk_context_use_cylinders(cxt
))
879 fdisk_ask_number_set_unit(ask
,
881 fdisk_context_get_units_per_sector(cxt
));
883 fdisk_ask_number_set_unit(ask
,cxt
->sector_size
);
885 rc
= fdisk_do_ask(cxt
, ask
);
886 last
= fdisk_ask_number_get_result(ask
) + 1;
891 if (fdisk_context_use_cylinders(cxt
))
892 last
*= fdisk_context_get_units_per_sector(cxt
);
895 if (sys
== SGI_TYPE_ENTIRE_DISK
896 && (first
!= 0 || last
!= sgi_get_lastblock(cxt
)))
897 fdisk_info(cxt
, _("It is highly recommended that the "
898 "eleventh partition covers the entire "
899 "disk and is of type 'SGI volume'."));
901 sgi_set_partition(cxt
, n
, first
, last
- first
, sys
);
902 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
907 static int sgi_create_disklabel(struct fdisk_context
*cxt
)
909 struct fdisk_sgi_label
*sgi
;
910 struct sgi_disklabel
*sgilabel
;
915 assert(fdisk_is_disklabel(cxt
, SGI
));
918 if (cxt
->geom
.heads
&& cxt
->geom
.sectors
) {
921 if (blkdev_get_sectors(cxt
->dev_fd
, &llsectors
) == 0) {
922 /* the get device size ioctl was successful */
924 int sec_fac
= cxt
->sector_size
/ 512;
926 llcyls
= llsectors
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
* sec_fac
);
927 cxt
->geom
.cylinders
= llcyls
;
928 if (cxt
->geom
.cylinders
!= llcyls
) /* truncated? */
929 cxt
->geom
.cylinders
= ~0;
931 /* otherwise print error and use truncated version */
933 _("BLKGETSIZE ioctl failed on %s. "
934 "Using geometry cylinder value of %llu. "
935 "This value may be truncated for devices "
936 "> 33.8 GB."), cxt
->dev_path
, cxt
->geom
.cylinders
);
940 rc
= fdisk_init_firstsector_buffer(cxt
);
944 sgi
= (struct fdisk_sgi_label
*) cxt
->label
;
945 sgi
->header
= (struct sgi_disklabel
*) cxt
->firstsector
;
947 sgilabel
= sgi
->header
;
949 sgilabel
->magic
= cpu_to_be32(SGI_LABEL_MAGIC
);
950 sgilabel
->root_part_num
= cpu_to_be16(0);
951 sgilabel
->swap_part_num
= cpu_to_be16(1);
953 /* sizeof(sgilabel->boot_file) = 16 > 6 */
954 memset(sgilabel
->boot_file
, 0, 16);
955 strcpy((char *) sgilabel
->boot_file
, "/unix");
957 sgilabel
->devparam
.skew
= (0);
958 sgilabel
->devparam
.gap1
= (0);
959 sgilabel
->devparam
.gap2
= (0);
960 sgilabel
->devparam
.sparecyl
= (0);
961 sgilabel
->devparam
.pcylcount
= cpu_to_be16(cxt
->geom
.cylinders
);
962 sgilabel
->devparam
.head_vol0
= cpu_to_be16(0);
963 sgilabel
->devparam
.ntrks
= cpu_to_be16(cxt
->geom
.heads
);
964 /* tracks/cylinder (heads) */
965 sgilabel
->devparam
.cmd_tag_queue_depth
= (0);
966 sgilabel
->devparam
.unused0
= (0);
967 sgilabel
->devparam
.unused1
= cpu_to_be16(0);
968 sgilabel
->devparam
.nsect
= cpu_to_be16(cxt
->geom
.sectors
);
970 sgilabel
->devparam
.bytes
= cpu_to_be16(cxt
->sector_size
);
971 sgilabel
->devparam
.ilfact
= cpu_to_be16(1);
972 sgilabel
->devparam
.flags
= cpu_to_be32(
973 SGI_DEVPARAM_TRACK_FWD
974 | SGI_DEVPARAM_IGNORE_ERRORS
975 | SGI_DEVPARAM_RESEEK
);
976 sgilabel
->devparam
.datarate
= cpu_to_be32(0);
977 sgilabel
->devparam
.retries_on_error
= cpu_to_be32(1);
978 sgilabel
->devparam
.ms_per_word
= cpu_to_be32(0);
979 sgilabel
->devparam
.xylogics_gap1
= cpu_to_be16(0);
980 sgilabel
->devparam
.xylogics_syncdelay
= cpu_to_be16(0);
981 sgilabel
->devparam
.xylogics_readdelay
= cpu_to_be16(0);
982 sgilabel
->devparam
.xylogics_gap2
= cpu_to_be16(0);
983 sgilabel
->devparam
.xylogics_readgate
= cpu_to_be16(0);
984 sgilabel
->devparam
.xylogics_writecont
= cpu_to_be16(0);
986 memset(&(sgilabel
->volume
), 0,
987 sizeof(struct sgi_volume
) * SGI_MAXVOLUMES
);
988 memset(&(sgilabel
->partitions
), 0,
989 sizeof(struct sgi_partition
) * SGI_MAXPARTITIONS
);
990 cxt
->label
->nparts_max
= SGI_MAXPARTITIONS
;
994 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
996 fdisk_sinfo(cxt
, FDISK_INFO_SUCCESS
,
997 _("Created a new SGI disklabel."));
1001 static int sgi_set_parttype(struct fdisk_context
*cxt
,
1003 struct fdisk_parttype
*t
)
1005 struct sgi_disklabel
*sgilabel
;
1007 if (i
>= cxt
->label
->nparts_max
|| !t
|| t
->type
> UINT32_MAX
)
1010 if (sgi_get_num_sectors(cxt
, i
) == 0) /* caught already before, ... */ {
1011 fdisk_warnx(cxt
, _("Sorry, only for non-empty partitions you can change the tag."));
1015 if ((i
== 10 && t
->type
!= SGI_TYPE_ENTIRE_DISK
)
1016 || (i
== 8 && t
->type
!= 0))
1017 fdisk_info(cxt
, _("Consider leaving partition 9 as volume header (0), "
1018 "and partition 11 as entire volume (6), "
1019 "as IRIX expects it."));
1021 if (((t
->type
!= SGI_TYPE_ENTIRE_DISK
) && (t
->type
!= SGI_TYPE_VOLHDR
))
1022 && (sgi_get_start_sector(cxt
, i
) < 1)) {
1024 fdisk_ask_yesno(cxt
,
1025 _("It is highly recommended that the partition at offset 0 "
1026 "is of type \"SGI volhdr\", the IRIX system will rely on it to "
1027 "retrieve from its directory standalone tools like sash and fx. "
1028 "Only the \"SGI volume\" entire disk section may violate this. "
1029 "Are you sure about tagging this partition differently?"), &yes
);
1034 sgilabel
= self_disklabel(cxt
);
1035 sgilabel
->partitions
[i
].type
= cpu_to_be32(t
->type
);
1040 static int sgi_partition_is_used(
1041 struct fdisk_context
*cxt
,
1045 assert(fdisk_is_disklabel(cxt
, SGI
));
1047 if (i
>= cxt
->label
->nparts_max
)
1049 return sgi_get_num_sectors(cxt
, i
) ? 1 : 0;
1052 static int sgi_toggle_partition_flag(struct fdisk_context
*cxt
, size_t i
, unsigned long flag
)
1054 struct sgi_disklabel
*sgilabel
;
1057 assert(fdisk_is_disklabel(cxt
, SGI
));
1059 if (i
>= cxt
->label
->nparts_max
)
1062 sgilabel
= self_disklabel(cxt
);
1066 sgilabel
->root_part_num
=
1067 be16_to_cpu(sgilabel
->root_part_num
) == i
?
1069 fdisk_label_set_changed(cxt
->label
, 1);
1072 sgilabel
->swap_part_num
=
1073 be16_to_cpu(sgilabel
->swap_part_num
) == i
?
1075 fdisk_label_set_changed(cxt
->label
, 1);
1084 static const struct fdisk_column sgi_columns
[] =
1086 { FDISK_COL_DEVICE
, N_("Device"), 10, 0 },
1087 { FDISK_COL_START
, N_("Start"), 5, SCOLS_FL_RIGHT
},
1088 { FDISK_COL_END
, N_("End"), 5, SCOLS_FL_RIGHT
},
1089 { FDISK_COL_SECTORS
, N_("Sectors"), 5, SCOLS_FL_RIGHT
},
1090 { FDISK_COL_CYLINDERS
, N_("Cylinders"), 5, SCOLS_FL_RIGHT
},
1091 { FDISK_COL_SIZE
, N_("Size"), 5, SCOLS_FL_RIGHT
, FDISK_COLFL_EYECANDY
},
1092 { FDISK_COL_TYPEID
, N_("Id"), 2, SCOLS_FL_RIGHT
},
1093 { FDISK_COL_TYPE
, N_("Type"), 0.1, SCOLS_FL_TRUNC
, FDISK_COLFL_EYECANDY
},
1094 { FDISK_COL_ATTR
, N_("Attrs"), 0, SCOLS_FL_RIGHT
}
1097 static const struct fdisk_label_operations sgi_operations
=
1099 .probe
= sgi_probe_label
,
1100 .write
= sgi_write_disklabel
,
1101 .verify
= sgi_verify_disklabel
,
1102 .create
= sgi_create_disklabel
,
1103 .list
= sgi_list_table
,
1105 .get_part
= sgi_get_partition
,
1106 .add_part
= sgi_add_partition
,
1108 .part_delete
= sgi_delete_partition
,
1109 .part_set_type
= sgi_set_parttype
,
1111 .part_is_used
= sgi_partition_is_used
,
1112 .part_toggle_flag
= sgi_toggle_partition_flag
1115 /* Allocates an SGI label driver. */
1116 struct fdisk_label
*fdisk_new_sgi_label(struct fdisk_context
*cxt
)
1118 struct fdisk_label
*lb
;
1119 struct fdisk_sgi_label
*sgi
;
1123 sgi
= calloc(1, sizeof(*sgi
));
1127 /* initialize generic part of the driver */
1128 lb
= (struct fdisk_label
*) sgi
;
1130 lb
->id
= FDISK_DISKLABEL_SGI
;
1131 lb
->op
= &sgi_operations
;
1132 lb
->parttypes
= sgi_parttypes
;
1133 lb
->nparttypes
= ARRAY_SIZE(sgi_parttypes
);
1134 lb
->columns
= sgi_columns
;
1135 lb
->ncolumns
= ARRAY_SIZE(sgi_columns
);
1137 lb
->flags
|= FDISK_LABEL_FL_REQUIRE_GEOMETRY
;