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.
26 * in-memory fdisk SGI stuff
28 struct fdisk_sgi_label
{
29 struct fdisk_label head
; /* generic fdisk part */
30 struct sgi_disklabel
*header
; /* on-disk data (pointer to cxt->firstsector) */
32 struct sgi_freeblocks
{
35 } freelist
[SGI_MAXPARTITIONS
+ 1];
38 static struct fdisk_parttype sgi_parttypes
[] =
40 {SGI_TYPE_VOLHDR
, N_("SGI volhdr")},
41 {SGI_TYPE_TRKREPL
, N_("SGI trkrepl")},
42 {SGI_TYPE_SECREPL
, N_("SGI secrepl")},
43 {SGI_TYPE_SWAP
, N_("SGI raw")},
44 {SGI_TYPE_BSD
, N_("SGI bsd")},
45 {SGI_TYPE_SYSV
, N_("SGI sysv")},
46 {SGI_TYPE_ENTIRE_DISK
, N_("SGI volume")},
47 {SGI_TYPE_EFS
, N_("SGI efs")},
48 {SGI_TYPE_LVOL
, N_("SGI lvol")},
49 {SGI_TYPE_RLVOL
, N_("SGI rlvol")},
50 {SGI_TYPE_XFS
, N_("SGI xfs")},
51 {SGI_TYPE_XFSLOG
, N_("SGI xfslog")},
52 {SGI_TYPE_XLV
, N_("SGI xlv")},
53 {SGI_TYPE_XVM
, N_("SGI xvm")},
54 {MBR_LINUX_SWAP_PARTITION
, N_("Linux swap")},
55 {MBR_LINUX_DATA_PARTITION
, N_("Linux native")},
56 {MBR_LINUX_LVM_PARTITION
, N_("Linux LVM")},
57 {MBR_LINUX_RAID_PARTITION
, N_("Linux RAID")},
61 static unsigned int sgi_get_start_sector(struct fdisk_context
*cxt
, int i
);
62 static unsigned int sgi_get_num_sectors(struct fdisk_context
*cxt
, int i
);
63 static int sgi_get_bootpartition(struct fdisk_context
*cxt
);
64 static int sgi_get_swappartition(struct fdisk_context
*cxt
);
66 /* Returns a pointer buffer with on-disk data. */
67 static inline struct sgi_disklabel
*self_disklabel(struct fdisk_context
*cxt
)
71 assert(fdisk_is_label(cxt
, SGI
));
73 return ((struct fdisk_sgi_label
*) cxt
->label
)->header
;
76 /* Returns in-memory fdisk data. */
77 static inline struct fdisk_sgi_label
*self_label(struct fdisk_context
*cxt
)
81 assert(fdisk_is_label(cxt
, SGI
));
83 return (struct fdisk_sgi_label
*) cxt
->label
;
87 * Information within second on-disk block
89 #define SGI_INFO_MAGIC 0x00072959
92 unsigned int magic
; /* looks like a magic number */
101 unsigned char scsi_string
[50];
102 unsigned char serial
[137];
103 unsigned short check1816
;
104 unsigned char installer
[225];
107 static struct sgi_info
*sgi_new_info(void)
109 struct sgi_info
*info
= calloc(1, sizeof(struct sgi_info
));
114 info
->magic
= cpu_to_be32(SGI_INFO_MAGIC
);
115 info
->b1
= cpu_to_be32(-1);
116 info
->b2
= cpu_to_be16(-1);
117 info
->b3
= cpu_to_be16(1);
119 /* You may want to replace this string !!!!!!! */
120 strcpy((char *) info
->scsi_string
, "IBM OEM 0662S12 3 30");
121 strcpy((char *) info
->serial
, "0000");
122 info
->check1816
= cpu_to_be16(18 * 256 + 16);
123 strcpy((char *) info
->installer
, "Sfx version 5.3, Oct 18, 1994");
128 static void sgi_free_info(struct sgi_info
*info
)
133 int fdisk_sgi_create_info(struct fdisk_context
*cxt
)
135 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
137 /* I keep SGI's habit to write the sgilabel to the second block */
138 sgilabel
->volume
[0].block_num
= cpu_to_be32(2);
139 sgilabel
->volume
[0].num_bytes
= cpu_to_be32(sizeof(struct sgi_info
));
140 strncpy((char *) sgilabel
->volume
[0].name
, "sgilabel", 8);
142 fdisk_info(cxt
, _("SGI info created on second sector."));
148 * only dealing with free blocks here
150 static void set_freelist(struct fdisk_context
*cxt
,
151 size_t i
, unsigned int f
, unsigned int l
)
153 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
155 if (i
< ARRAY_SIZE(sgi
->freelist
)) {
156 sgi
->freelist
[i
].first
= f
;
157 sgi
->freelist
[i
].last
= l
;
161 static void add_to_freelist(struct fdisk_context
*cxt
,
162 unsigned int f
, unsigned int l
)
164 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
167 for (i
= 0; i
< ARRAY_SIZE(sgi
->freelist
); i
++) {
168 if (sgi
->freelist
[i
].last
== 0)
171 set_freelist(cxt
, i
, f
, l
);
174 static void clear_freelist(struct fdisk_context
*cxt
)
176 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
178 memset(sgi
->freelist
, 0, sizeof(sgi
->freelist
));
181 static unsigned int is_in_freelist(struct fdisk_context
*cxt
, unsigned int b
)
183 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
186 for (i
= 0; i
< ARRAY_SIZE(sgi
->freelist
); i
++) {
187 if (sgi
->freelist
[i
].first
<= b
188 && sgi
->freelist
[i
].last
>= b
)
189 return sgi
->freelist
[i
].last
;
196 static int sgi_get_nsect(struct fdisk_context
*cxt
)
198 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
199 return be16_to_cpu(sgilabel
->devparam
.nsect
);
202 static int sgi_get_ntrks(struct fdisk_context
*cxt
)
204 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
205 return be16_to_cpu(sgilabel
->devparam
.ntrks
);
208 static size_t count_used_partitions(struct fdisk_context
*cxt
)
212 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++)
213 ct
+= sgi_get_num_sectors(cxt
, i
) > 0;
218 static int sgi_probe_label(struct fdisk_context
*cxt
)
220 struct fdisk_sgi_label
*sgi
;
221 struct sgi_disklabel
*sgilabel
;
225 assert(fdisk_is_label(cxt
, SGI
));
226 assert(sizeof(struct sgi_disklabel
) <= 512);
228 /* map first sector to header */
229 sgi
= (struct fdisk_sgi_label
*) cxt
->label
;
230 sgi
->header
= (struct sgi_disklabel
*) cxt
->firstsector
;
231 sgilabel
= sgi
->header
;
233 if (be32_to_cpu(sgilabel
->magic
) != SGI_LABEL_MAGIC
) {
239 * test for correct checksum
241 if (sgi_pt_checksum(sgilabel
) != 0)
242 fdisk_warnx(cxt
, _("Detected an SGI disklabel with wrong checksum."));
245 cxt
->label
->nparts_max
= SGI_MAXPARTITIONS
;
246 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
250 static int sgi_list_table(struct fdisk_context
*cxt
)
252 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
253 struct sgi_device_parameter
*sgiparam
= &sgilabel
->devparam
;
256 if (fdisk_is_details(cxt
))
258 "Label geometry: %d heads, %llu sectors\n"
259 " %llu cylinders, %d physical cylinders\n"
260 " %d extra sects/cyl, interleave %d:1\n"),
261 cxt
->geom
.heads
, cxt
->geom
.sectors
,
262 cxt
->geom
.cylinders
, be16_to_cpu(sgiparam
->pcylcount
),
263 (int) sgiparam
->sparecyl
, be16_to_cpu(sgiparam
->ilfact
));
265 fdisk_info(cxt
, _("Bootfile: %s"), sgilabel
->boot_file
);
269 static unsigned int sgi_get_start_sector(struct fdisk_context
*cxt
, int i
)
271 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
272 return be32_to_cpu(sgilabel
->partitions
[i
].first_block
);
275 static unsigned int sgi_get_num_sectors(struct fdisk_context
*cxt
, int i
)
277 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
278 return be32_to_cpu(sgilabel
->partitions
[i
].num_blocks
);
281 static int sgi_get_sysid(struct fdisk_context
*cxt
, int i
)
283 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
284 return be32_to_cpu(sgilabel
->partitions
[i
].type
);
287 static int sgi_get_bootpartition(struct fdisk_context
*cxt
)
289 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
290 return be16_to_cpu(sgilabel
->root_part_num
);
293 static int sgi_get_swappartition(struct fdisk_context
*cxt
)
295 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
296 return be16_to_cpu(sgilabel
->swap_part_num
);
299 static unsigned int sgi_get_lastblock(struct fdisk_context
*cxt
)
301 return cxt
->geom
.heads
* cxt
->geom
.sectors
* cxt
->geom
.cylinders
;
304 static struct fdisk_parttype
*sgi_get_parttype(struct fdisk_context
*cxt
, size_t n
)
306 struct fdisk_parttype
*t
;
308 if (n
>= cxt
->label
->nparts_max
)
311 t
= fdisk_label_get_parttype_from_code(cxt
->label
, sgi_get_sysid(cxt
, n
));
312 return t
? : fdisk_new_unknown_parttype(sgi_get_sysid(cxt
, n
), NULL
);
315 /* fdisk_get_partition() backend */
316 static int sgi_get_partition(struct fdisk_context
*cxt
, size_t n
, struct fdisk_partition
*pa
)
320 pa
->used
= sgi_get_num_sectors(cxt
, n
) > 0;
324 start
= sgi_get_start_sector(cxt
, n
);
325 len
= sgi_get_num_sectors(cxt
, n
);
327 pa
->type
= sgi_get_parttype(cxt
, n
);
330 pa
->end
= start
+ len
- (len
? 1 : 0);
332 if (pa
->type
&& pa
->type
->code
== SGI_TYPE_ENTIRE_DISK
)
335 pa
->attrs
= sgi_get_swappartition(cxt
) == (int) n
? "swap" :
336 sgi_get_bootpartition(cxt
) == (int) n
? "boot" : NULL
;
338 pa
->attrs
= strdup(pa
->attrs
);
344 static int sgi_check_bootfile(struct fdisk_context
*cxt
, const char *name
)
347 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
352 /* "/a\n" is minimum */
353 fdisk_warnx(cxt
, _("Invalid bootfile! The bootfile must "
354 "be an absolute non-zero pathname, "
355 "e.g. \"/unix\" or \"/unix.save\"."));
358 } else if (sz
> sizeof(sgilabel
->boot_file
)) {
359 fdisk_warnx(cxt
, P_("Name of bootfile is too long: %zu byte maximum.",
360 "Name of bootfile is too long: %zu bytes maximum.",
361 sizeof(sgilabel
->boot_file
)),
362 sizeof(sgilabel
->boot_file
));
365 } else if (*name
!= '/') {
366 fdisk_warnx(cxt
, _("Bootfile must have a fully qualified pathname."));
370 if (strncmp(name
, (char *) sgilabel
->boot_file
,
371 sizeof(sgilabel
->boot_file
))) {
372 fdisk_warnx(cxt
, _("Be aware that the bootfile is not checked "
373 "for existence. SGI's default is \"/unix\", "
374 "and for backup \"/unix.save\"."));
375 return 0; /* filename is correct and did change */
378 return 1; /* filename did not change */
381 int fdisk_sgi_set_bootfile(struct fdisk_context
*cxt
)
386 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
388 fdisk_info(cxt
, _("The current boot file is: %s"), sgilabel
->boot_file
);
390 rc
= fdisk_ask_string(cxt
, _("Enter of the new boot file"), &name
);
392 rc
= sgi_check_bootfile(cxt
, name
);
395 fdisk_info(cxt
, _("Boot file is unchanged."));
399 memset(sgilabel
->boot_file
, 0, sizeof(sgilabel
->boot_file
));
402 assert(sz
<= sizeof(sgilabel
->boot_file
)); /* see sgi_check_bootfile() */
404 memcpy(sgilabel
->boot_file
, name
, sz
);
406 fdisk_sinfo(cxt
, FDISK_INFO_SUCCESS
,
407 _("Bootfile has been changed to \"%s\"."), name
);
413 static int sgi_write_disklabel(struct fdisk_context
*cxt
)
415 struct sgi_disklabel
*sgilabel
;
416 struct sgi_info
*info
= NULL
;
420 assert(fdisk_is_label(cxt
, SGI
));
422 sgilabel
= self_disklabel(cxt
);
424 sgilabel
->csum
= cpu_to_be32(sgi_pt_checksum(sgilabel
));
426 assert(sgi_pt_checksum(sgilabel
) == 0);
428 if (lseek(cxt
->dev_fd
, 0, SEEK_SET
) < 0)
430 if (write_all(cxt
->dev_fd
, sgilabel
, DEFAULT_SECTOR_SIZE
))
432 if (!strncmp((char *) sgilabel
->volume
[0].name
, "sgilabel", 8)) {
434 * Keep this habit of first writing the "sgilabel".
435 * I never tested whether it works without. (AN 1998-10-02)
438 = be32_to_cpu(sgilabel
->volume
[0].block_num
);
440 if (lseek(cxt
->dev_fd
, (off_t
) infostartblock
*
441 DEFAULT_SECTOR_SIZE
, SEEK_SET
) < 0)
443 info
= sgi_new_info();
446 if (write_all(cxt
->dev_fd
, info
, sizeof(*info
)))
457 static int compare_start(struct fdisk_context
*cxt
,
458 const void *x
, const void *y
)
461 * Sort according to start sectors and prefer the largest partition:
462 * entry zero is the entire-disk entry.
464 unsigned int i
= *(int *) x
;
465 unsigned int j
= *(int *) y
;
466 unsigned int a
= sgi_get_start_sector(cxt
, i
);
467 unsigned int b
= sgi_get_start_sector(cxt
, j
);
468 unsigned int c
= sgi_get_num_sectors(cxt
, i
);
469 unsigned int d
= sgi_get_num_sectors(cxt
, j
);
472 return (d
> c
) ? 1 : (d
== c
) ? 0 : -1;
473 return (a
> b
) ? 1 : -1;
476 static void generic_swap(void *a0
, void *b0
, int size
)
478 char *a
= a0
, *b
= b0
;
480 for (; size
> 0; --size
, a
++, b
++) {
488 /* heap sort, based on Matt Mackall's linux kernel version */
489 static void sort(void *base0
, size_t num
, size_t size
, struct fdisk_context
*cxt
,
490 int (*cmp_func
)(struct fdisk_context
*, const void *, const void *))
492 /* pre-scale counters for performance */
493 int i
= (num
/2 - 1) * size
;
494 size_t n
= num
* size
, c
, r
;
498 for ( ; i
>= 0; i
-= size
) {
499 for (r
= i
; r
* 2 + size
< n
; r
= c
) {
502 cmp_func(cxt
, base
+ c
, base
+ c
+ size
) < 0)
504 if (cmp_func(cxt
, base
+ r
, base
+ c
) >= 0)
506 generic_swap(base
+ r
, base
+ c
, size
);
511 for (i
= n
- size
; i
> 0; i
-= size
) {
512 generic_swap(base
, base
+ i
, size
);
513 for (r
= 0; r
* 2 + size
< (size_t) i
; r
= c
) {
516 cmp_func(cxt
, base
+ c
, base
+ c
+ size
) < 0)
518 if (cmp_func(cxt
, base
+ r
, base
+ c
) >= 0)
520 generic_swap(base
+ r
, base
+ c
, size
);
525 static int verify_disklabel(struct fdisk_context
*cxt
, int verbose
)
527 int Index
[SGI_MAXPARTITIONS
]; /* list of valid partitions */
528 int sortcount
= 0; /* number of used partitions, i.e. non-zero lengths */
529 int entire
= 0, i
= 0;
530 unsigned int start
= 0;
531 long long gap
= 0; /* count unused blocks */
532 unsigned int lastblock
= sgi_get_lastblock(cxt
);
536 assert(fdisk_is_label(cxt
, SGI
));
539 memset(Index
, 0, sizeof(Index
));
541 for (i
=0; i
< SGI_MAXPARTITIONS
; i
++) {
542 if (sgi_get_num_sectors(cxt
, i
) != 0) {
543 Index
[sortcount
++] = i
;
544 if (sgi_get_sysid(cxt
, i
) == SGI_TYPE_ENTIRE_DISK
547 fdisk_info(cxt
, _("More than one entire "
548 "disk entry present."));
552 if (sortcount
== 0) {
554 fdisk_info(cxt
, _("No partitions defined."));
556 add_to_freelist(cxt
, 0, lastblock
);
557 return (lastblock
> 0) ? 1 : (lastblock
== 0) ? 0 : -1;
560 sort(Index
, sortcount
, sizeof(Index
[0]), cxt
, compare_start
);
562 if (sgi_get_sysid(cxt
, Index
[0]) == SGI_TYPE_ENTIRE_DISK
) {
563 if (verbose
&& Index
[0] != 10)
564 fdisk_info(cxt
, _("IRIX likes it when partition 11 "
565 "covers the entire disk."));
567 if (verbose
&& sgi_get_start_sector(cxt
, Index
[0]) != 0)
568 fdisk_info(cxt
, _("The entire disk partition should "
569 "start at block 0, not at block %d."),
570 sgi_get_start_sector(cxt
, Index
[0]));
572 if (verbose
&& sgi_get_num_sectors(cxt
, Index
[0]) != lastblock
)
574 "entire disk partition=%ds, but disk=%ds",
575 sgi_get_num_sectors(cxt
, Index
[0]),
577 lastblock
= sgi_get_num_sectors(cxt
, Index
[0]);
578 } else if (verbose
) {
579 fdisk_info(cxt
, _("Partition 11 should cover the entire disk."));
580 DBG(LABEL
, ul_debug("sysid=%d\tpartition=%d",
581 sgi_get_sysid(cxt
, Index
[0]), Index
[0]+1));
583 for (i
=1, start
=0; i
<sortcount
; i
++) {
584 int cylsize
= sgi_get_nsect(cxt
) * sgi_get_ntrks(cxt
);
586 if (verbose
&& cylsize
587 && (sgi_get_start_sector(cxt
, Index
[i
]) % cylsize
) != 0)
588 DBG(LABEL
, ul_debug("partition %d does not start on "
589 "cylinder boundary.", Index
[i
]+1));
591 if (verbose
&& cylsize
592 && sgi_get_num_sectors(cxt
, Index
[i
]) % cylsize
!= 0)
593 DBG(LABEL
, ul_debug("partition %d does not end on "
594 "cylinder boundary.", Index
[i
]+1));
596 /* We cannot handle several "entire disk" entries. */
597 if (sgi_get_sysid(cxt
, Index
[i
]) == SGI_TYPE_ENTIRE_DISK
)
600 if (start
> sgi_get_start_sector(cxt
, Index
[i
])) {
603 P_("Partitions %d and %d overlap by %d sector.",
604 "Partitions %d and %d overlap by %d sectors.",
605 start
- sgi_get_start_sector(cxt
, Index
[i
])),
606 Index
[i
-1]+1, Index
[i
]+1,
607 start
- sgi_get_start_sector(cxt
, Index
[i
]));
608 if (gap
> 0) gap
= -gap
;
609 if (gap
== 0) gap
= -1;
611 if (start
< sgi_get_start_sector(cxt
, Index
[i
])) {
614 P_("Unused gap of %8u sector: sector %8u",
615 "Unused gap of %8u sectors: sectors %8u-%u",
616 sgi_get_start_sector(cxt
, Index
[i
]) - start
),
617 sgi_get_start_sector(cxt
, Index
[i
]) - start
,
618 start
, sgi_get_start_sector(cxt
, Index
[i
])-1);
619 gap
+= sgi_get_start_sector(cxt
, Index
[i
]) - start
;
620 add_to_freelist(cxt
, start
,
621 sgi_get_start_sector(cxt
, Index
[i
]));
623 start
= sgi_get_start_sector(cxt
, Index
[i
])
624 + sgi_get_num_sectors(cxt
, Index
[i
]);
625 /* Align free space on cylinder boundary. */
626 if (cylsize
&& start
% cylsize
)
627 start
+= cylsize
- (start
% cylsize
);
629 DBG(LABEL
, ul_debug("%2d:%12d\t%12d\t%12d", Index
[i
],
630 sgi_get_start_sector(cxt
, Index
[i
]),
631 sgi_get_num_sectors(cxt
, Index
[i
]),
632 sgi_get_sysid(cxt
, Index
[i
])));
634 if (start
< lastblock
) {
636 fdisk_info(cxt
, P_("Unused gap of %8u sector: sector %8u",
637 "Unused gap of %8u sectors: sectors %8u-%u",
639 lastblock
- start
, start
, lastblock
-1);
640 gap
+= lastblock
- start
;
641 add_to_freelist(cxt
, start
, lastblock
);
644 * Done with arithmetics. Go for details now.
647 if (sgi_get_bootpartition(cxt
) < 0
648 || !sgi_get_num_sectors(cxt
, sgi_get_bootpartition(cxt
)))
649 fdisk_info(cxt
, _("The boot partition does not exist."));
651 if (sgi_get_swappartition(cxt
) < 0
652 || !sgi_get_num_sectors(cxt
, sgi_get_swappartition(cxt
)))
653 fdisk_info(cxt
, _("The swap partition does not exist."));
655 else if (sgi_get_sysid(cxt
, sgi_get_swappartition(cxt
)) != SGI_TYPE_SWAP
656 && sgi_get_sysid(cxt
, sgi_get_swappartition(cxt
)) != MBR_LINUX_SWAP_PARTITION
)
657 fdisk_info(cxt
, _("The swap partition has no swap type."));
659 if (sgi_check_bootfile(cxt
, "/unix"))
660 fdisk_info(cxt
, _("You have chosen an unusual bootfile name."));
663 return (gap
> 0) ? 1 : (gap
== 0) ? 0 : -1;
666 static int sgi_verify_disklabel(struct fdisk_context
*cxt
)
668 return verify_disklabel(cxt
, 1);
671 static int sgi_gaps(struct fdisk_context
*cxt
)
675 * = 0 : disk is properly filled to the rim
676 * < 0 : there is an overlap
677 * > 0 : there is still some vacant space
679 return verify_disklabel(cxt
, 0);
682 /* Returns partition index of first entry marked as entire disk. */
683 static int sgi_entire(struct fdisk_context
*cxt
)
687 for (i
= 0; i
< SGI_MAXPARTITIONS
; i
++)
688 if (sgi_get_sysid(cxt
, i
) == SGI_TYPE_ENTIRE_DISK
)
693 static int set_partition(struct fdisk_context
*cxt
, size_t i
,
694 unsigned int start
, unsigned int length
, int sys
)
696 struct sgi_disklabel
*sgilabel
;
700 assert(fdisk_is_label(cxt
, SGI
));
702 sgilabel
= self_disklabel(cxt
);
703 sgilabel
->partitions
[i
].type
= cpu_to_be32(sys
);
704 sgilabel
->partitions
[i
].num_blocks
= cpu_to_be32(length
);
705 sgilabel
->partitions
[i
].first_block
= cpu_to_be32(start
);
707 fdisk_label_set_changed(cxt
->label
, 1);
709 if (sgi_gaps(cxt
) < 0) /* rebuild freelist */
710 fdisk_warnx(cxt
, _("Partition overlap on the disk."));
712 struct fdisk_parttype
*t
=
713 fdisk_label_get_parttype_from_code(cxt
->label
, sys
);
714 fdisk_info_new_partition(cxt
, i
+ 1, start
, start
+ length
, t
);
720 static void sgi_set_entire(struct fdisk_context
*cxt
)
724 for (n
= 10; n
< cxt
->label
->nparts_max
; n
++) {
725 if (!sgi_get_num_sectors(cxt
, n
)) {
726 set_partition(cxt
, n
, 0, sgi_get_lastblock(cxt
), SGI_TYPE_ENTIRE_DISK
);
732 static void sgi_set_volhdr(struct fdisk_context
*cxt
)
736 for (n
= 8; n
< cxt
->label
->nparts_max
; n
++) {
737 if (!sgi_get_num_sectors(cxt
, n
)) {
738 /* Choose same default volume header size as IRIX fx uses. */
739 if (4096 < sgi_get_lastblock(cxt
))
740 set_partition(cxt
, n
, 0, 4096, SGI_TYPE_VOLHDR
);
746 static int sgi_delete_partition(struct fdisk_context
*cxt
, size_t partnum
)
753 if (partnum
> cxt
->label
->nparts_max
)
756 rc
= set_partition(cxt
, partnum
, 0, 0, 0);
758 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
763 static int sgi_add_partition(struct fdisk_context
*cxt
,
764 struct fdisk_partition
*pa
,
767 struct fdisk_sgi_label
*sgi
;
769 unsigned int first
= 0, last
= 0;
770 struct fdisk_ask
*ask
;
771 int sys
= pa
&& pa
->type
? pa
->type
->code
: SGI_TYPE_XFS
;
777 assert(fdisk_is_label(cxt
, SGI
));
779 rc
= fdisk_partition_next_partno(pa
, cxt
, &n
);
783 sys
= SGI_TYPE_ENTIRE_DISK
;
787 sgi
= self_label(cxt
);
789 if (sgi_get_num_sectors(cxt
, n
)) {
790 fdisk_warnx(cxt
, _("Partition %zu is already defined. "
791 "Delete it before re-adding it."), n
+ 1);
794 if (!cxt
->script
&& sgi_entire(cxt
) == -1 && sys
!= SGI_TYPE_ENTIRE_DISK
) {
795 fdisk_info(cxt
, _("Attempting to generate entire disk entry automatically."));
799 if (sgi_gaps(cxt
) == 0 && sys
!= SGI_TYPE_ENTIRE_DISK
) {
800 fdisk_warnx(cxt
, _("The entire disk is already covered with partitions."));
803 if (sgi_gaps(cxt
) < 0) {
804 fdisk_warnx(cxt
, _("You got a partition overlap on the disk. Fix it first!"));
808 if (sys
== SGI_TYPE_ENTIRE_DISK
) {
810 last
= sgi_get_lastblock(cxt
);
812 first
= sgi
->freelist
[0].first
;
813 last
= sgi
->freelist
[0].last
;
817 if (pa
&& pa
->start_follow_default
)
819 else if (pa
&& fdisk_partition_has_start(pa
)) {
821 last
= is_in_freelist(cxt
, first
);
823 if (sys
!= SGI_TYPE_ENTIRE_DISK
&& !last
)
826 snprintf(mesg
, sizeof(mesg
), _("First %s"),
827 fdisk_get_unit(cxt
, FDISK_SINGULAR
));
828 ask
= fdisk_new_ask();
832 fdisk_ask_set_query(ask
, mesg
);
833 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_NUMBER
);
835 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
836 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, first
)); /* default */
837 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, last
) - 1); /* maximal */
839 rc
= fdisk_do_ask(cxt
, ask
);
840 first
= fdisk_ask_number_get_result(ask
);
845 if (fdisk_use_cylinders(cxt
))
846 first
*= fdisk_get_units_per_sector(cxt
);
849 if (first
&& sys
== SGI_TYPE_ENTIRE_DISK
)
850 fdisk_info(cxt
, _("It is highly recommended that the "
851 "eleventh partition covers the entire "
852 "disk and is of type 'SGI volume'."));
854 last
= is_in_freelist(cxt
, first
);
857 if (pa
&& pa
->end_follow_default
)
859 else if (pa
&& fdisk_partition_has_size(pa
)) {
860 if (first
+ pa
->size
- 1ULL > last
)
862 last
= first
+ pa
->size
- 1ULL;
864 snprintf(mesg
, sizeof(mesg
),
865 _("Last %s or +%s or +size{K,M,G,T,P}"),
866 fdisk_get_unit(cxt
, FDISK_SINGULAR
),
867 fdisk_get_unit(cxt
, FDISK_PLURAL
));
869 ask
= fdisk_new_ask();
873 fdisk_ask_set_query(ask
, mesg
);
874 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_OFFSET
);
876 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
877 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, last
) - 1);/* default */
878 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, last
) - 1);/* maximal */
879 fdisk_ask_number_set_base(ask
, fdisk_scround(cxt
, first
));
881 if (fdisk_use_cylinders(cxt
))
882 fdisk_ask_number_set_unit(ask
,
884 fdisk_get_units_per_sector(cxt
));
886 fdisk_ask_number_set_unit(ask
,cxt
->sector_size
);
888 rc
= fdisk_do_ask(cxt
, ask
);
889 last
= fdisk_ask_number_get_result(ask
) + 1;
894 if (fdisk_use_cylinders(cxt
))
895 last
*= fdisk_get_units_per_sector(cxt
);
898 if (sys
== SGI_TYPE_ENTIRE_DISK
899 && (first
!= 0 || last
!= sgi_get_lastblock(cxt
)))
900 fdisk_info(cxt
, _("It is highly recommended that the "
901 "eleventh partition covers the entire "
902 "disk and is of type 'SGI volume'."));
904 set_partition(cxt
, n
, first
, last
- first
, sys
);
905 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
911 static int sgi_create_disklabel(struct fdisk_context
*cxt
)
913 struct fdisk_sgi_label
*sgi
;
914 struct sgi_disklabel
*sgilabel
;
919 assert(fdisk_is_label(cxt
, SGI
));
922 if (cxt
->geom
.heads
&& cxt
->geom
.sectors
) {
925 if (blkdev_get_sectors(cxt
->dev_fd
, &llsectors
) == 0) {
926 /* the get device size ioctl was successful */
928 int sec_fac
= cxt
->sector_size
/ 512;
930 llcyls
= llsectors
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
* sec_fac
);
931 cxt
->geom
.cylinders
= llcyls
;
932 if (cxt
->geom
.cylinders
!= llcyls
) /* truncated? */
933 cxt
->geom
.cylinders
= ~0;
935 /* otherwise print error and use truncated version */
937 _("BLKGETSIZE ioctl failed on %s. "
938 "Using geometry cylinder value of %llu. "
939 "This value may be truncated for devices "
940 "> 33.8 GB."), cxt
->dev_path
, cxt
->geom
.cylinders
);
944 rc
= fdisk_init_firstsector_buffer(cxt
);
948 sgi
= (struct fdisk_sgi_label
*) cxt
->label
;
949 sgi
->header
= (struct sgi_disklabel
*) cxt
->firstsector
;
951 sgilabel
= sgi
->header
;
953 sgilabel
->magic
= cpu_to_be32(SGI_LABEL_MAGIC
);
954 sgilabel
->root_part_num
= cpu_to_be16(0);
955 sgilabel
->swap_part_num
= cpu_to_be16(1);
957 /* sizeof(sgilabel->boot_file) = 16 > 6 */
958 memset(sgilabel
->boot_file
, 0, 16);
959 strcpy((char *) sgilabel
->boot_file
, "/unix");
961 sgilabel
->devparam
.skew
= (0);
962 sgilabel
->devparam
.gap1
= (0);
963 sgilabel
->devparam
.gap2
= (0);
964 sgilabel
->devparam
.sparecyl
= (0);
965 sgilabel
->devparam
.pcylcount
= cpu_to_be16(cxt
->geom
.cylinders
);
966 sgilabel
->devparam
.head_vol0
= cpu_to_be16(0);
967 sgilabel
->devparam
.ntrks
= cpu_to_be16(cxt
->geom
.heads
);
968 /* tracks/cylinder (heads) */
969 sgilabel
->devparam
.cmd_tag_queue_depth
= (0);
970 sgilabel
->devparam
.unused0
= (0);
971 sgilabel
->devparam
.unused1
= cpu_to_be16(0);
972 sgilabel
->devparam
.nsect
= cpu_to_be16(cxt
->geom
.sectors
);
974 sgilabel
->devparam
.bytes
= cpu_to_be16(cxt
->sector_size
);
975 sgilabel
->devparam
.ilfact
= cpu_to_be16(1);
976 sgilabel
->devparam
.flags
= cpu_to_be32(
977 SGI_DEVPARAM_TRACK_FWD
978 | SGI_DEVPARAM_IGNORE_ERRORS
979 | SGI_DEVPARAM_RESEEK
);
980 sgilabel
->devparam
.datarate
= cpu_to_be32(0);
981 sgilabel
->devparam
.retries_on_error
= cpu_to_be32(1);
982 sgilabel
->devparam
.ms_per_word
= cpu_to_be32(0);
983 sgilabel
->devparam
.xylogics_gap1
= cpu_to_be16(0);
984 sgilabel
->devparam
.xylogics_syncdelay
= cpu_to_be16(0);
985 sgilabel
->devparam
.xylogics_readdelay
= cpu_to_be16(0);
986 sgilabel
->devparam
.xylogics_gap2
= cpu_to_be16(0);
987 sgilabel
->devparam
.xylogics_readgate
= cpu_to_be16(0);
988 sgilabel
->devparam
.xylogics_writecont
= cpu_to_be16(0);
990 memset(&(sgilabel
->volume
), 0,
991 sizeof(struct sgi_volume
) * SGI_MAXVOLUMES
);
992 memset(&(sgilabel
->partitions
), 0,
993 sizeof(struct sgi_partition
) * SGI_MAXPARTITIONS
);
994 cxt
->label
->nparts_max
= SGI_MAXPARTITIONS
;
996 /* don't create default layout when a script defined */
1001 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
1003 fdisk_sinfo(cxt
, FDISK_INFO_SUCCESS
,
1004 _("Created a new SGI disklabel."));
1008 static int sgi_set_partition(struct fdisk_context
*cxt
,
1010 struct fdisk_partition
*pa
)
1012 struct sgi_disklabel
*sgilabel
;
1014 if (i
>= cxt
->label
->nparts_max
)
1017 sgilabel
= self_disklabel(cxt
);
1020 struct fdisk_parttype
*t
= pa
->type
;
1022 if (t
->code
> UINT32_MAX
)
1025 if (sgi_get_num_sectors(cxt
, i
) == 0) /* caught already before, ... */ {
1026 fdisk_warnx(cxt
, _("Sorry, only for non-empty partitions you can change the tag."));
1030 if ((i
== 10 && t
->code
!= SGI_TYPE_ENTIRE_DISK
)
1031 || (i
== 8 && t
->code
!= 0))
1032 fdisk_info(cxt
, _("Consider leaving partition 9 as volume header (0), "
1033 "and partition 11 as entire volume (6), "
1034 "as IRIX expects it."));
1036 if (cxt
->script
== NULL
1037 && ((t
->code
!= SGI_TYPE_ENTIRE_DISK
) && (t
->code
!= SGI_TYPE_VOLHDR
))
1038 && (sgi_get_start_sector(cxt
, i
) < 1)) {
1040 fdisk_ask_yesno(cxt
,
1041 _("It is highly recommended that the partition at offset 0 "
1042 "is of type \"SGI volhdr\", the IRIX system will rely on it to "
1043 "retrieve from its directory standalone tools like sash and fx. "
1044 "Only the \"SGI volume\" entire disk section may violate this. "
1045 "Are you sure about tagging this partition differently?"), &yes
);
1050 sgilabel
->partitions
[i
].type
= cpu_to_be32(t
->code
);
1053 if (fdisk_partition_has_start(pa
))
1054 sgilabel
->partitions
[i
].first_block
= cpu_to_be32(pa
->start
);
1055 if (fdisk_partition_has_size(pa
))
1056 sgilabel
->partitions
[i
].num_blocks
= cpu_to_be32(pa
->size
);
1058 fdisk_label_set_changed(cxt
->label
, 1);
1063 static int sgi_partition_is_used(
1064 struct fdisk_context
*cxt
,
1068 assert(fdisk_is_label(cxt
, SGI
));
1070 if (i
>= cxt
->label
->nparts_max
)
1072 return sgi_get_num_sectors(cxt
, i
) ? 1 : 0;
1075 static int sgi_toggle_partition_flag(struct fdisk_context
*cxt
, size_t i
, unsigned long flag
)
1077 struct sgi_disklabel
*sgilabel
;
1080 assert(fdisk_is_label(cxt
, SGI
));
1082 if (i
>= cxt
->label
->nparts_max
)
1085 sgilabel
= self_disklabel(cxt
);
1089 sgilabel
->root_part_num
=
1090 be16_to_cpu(sgilabel
->root_part_num
) == i
?
1092 fdisk_label_set_changed(cxt
->label
, 1);
1095 sgilabel
->swap_part_num
=
1096 be16_to_cpu(sgilabel
->swap_part_num
) == i
?
1098 fdisk_label_set_changed(cxt
->label
, 1);
1107 static const struct fdisk_field sgi_fields
[] =
1109 { FDISK_FIELD_DEVICE
, N_("Device"), 10, 0 },
1110 { FDISK_FIELD_START
, N_("Start"), 5, FDISK_FIELDFL_NUMBER
},
1111 { FDISK_FIELD_END
, N_("End"), 5, FDISK_FIELDFL_NUMBER
},
1112 { FDISK_FIELD_SECTORS
, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER
},
1113 { FDISK_FIELD_CYLINDERS
,N_("Cylinders"), 5, FDISK_FIELDFL_NUMBER
},
1114 { FDISK_FIELD_SIZE
, N_("Size"), 5, FDISK_FIELDFL_NUMBER
| FDISK_FIELDFL_EYECANDY
},
1115 { FDISK_FIELD_TYPEID
, N_("Id"), 2, FDISK_FIELDFL_NUMBER
},
1116 { FDISK_FIELD_TYPE
, N_("Type"), 0.1, FDISK_FIELDFL_EYECANDY
},
1117 { FDISK_FIELD_ATTR
, N_("Attrs"), 0, FDISK_FIELDFL_NUMBER
}
1120 static const struct fdisk_label_operations sgi_operations
=
1122 .probe
= sgi_probe_label
,
1123 .write
= sgi_write_disklabel
,
1124 .verify
= sgi_verify_disklabel
,
1125 .create
= sgi_create_disklabel
,
1126 .list
= sgi_list_table
,
1128 .get_part
= sgi_get_partition
,
1129 .set_part
= sgi_set_partition
,
1130 .add_part
= sgi_add_partition
,
1131 .del_part
= sgi_delete_partition
,
1133 .part_is_used
= sgi_partition_is_used
,
1134 .part_toggle_flag
= sgi_toggle_partition_flag
1137 /* Allocates an SGI label driver. */
1138 struct fdisk_label
*fdisk_new_sgi_label(struct fdisk_context
*cxt
)
1140 struct fdisk_label
*lb
;
1141 struct fdisk_sgi_label
*sgi
;
1145 sgi
= calloc(1, sizeof(*sgi
));
1149 /* initialize generic part of the driver */
1150 lb
= (struct fdisk_label
*) sgi
;
1152 lb
->id
= FDISK_DISKLABEL_SGI
;
1153 lb
->op
= &sgi_operations
;
1154 lb
->parttypes
= sgi_parttypes
;
1155 lb
->nparttypes
= ARRAY_SIZE(sgi_parttypes
) - 1;
1156 lb
->fields
= sgi_fields
;
1157 lb
->nfields
= ARRAY_SIZE(sgi_fields
);
1159 lb
->flags
|= FDISK_LABEL_FL_REQUIRE_GEOMETRY
;