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.
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 static unsigned int sgi_get_start_sector(struct fdisk_context
*cxt
, int i
);
61 static unsigned int sgi_get_num_sectors(struct fdisk_context
*cxt
, int i
);
62 static int sgi_get_bootpartition(struct fdisk_context
*cxt
);
63 static int sgi_get_swappartition(struct fdisk_context
*cxt
);
65 /* Returns a pointer buffer with on-disk data. */
66 static inline struct sgi_disklabel
*self_disklabel(struct fdisk_context
*cxt
)
70 assert(fdisk_is_disklabel(cxt
, SGI
));
72 return ((struct fdisk_sgi_label
*) cxt
->label
)->header
;
75 /* Returns in-memory fdisk data. */
76 static inline struct fdisk_sgi_label
*self_label(struct fdisk_context
*cxt
)
80 assert(fdisk_is_disklabel(cxt
, SGI
));
82 return (struct fdisk_sgi_label
*) cxt
->label
;
86 * Information within second on-disk block
88 #define SGI_INFO_MAGIC 0x00072959
91 unsigned int magic
; /* looks like a magic number */
100 unsigned char scsi_string
[50];
101 unsigned char serial
[137];
102 unsigned short check1816
;
103 unsigned char installer
[225];
106 static struct sgi_info
*sgi_new_info(void)
108 struct sgi_info
*info
= calloc(1, sizeof(struct sgi_info
));
113 info
->magic
= cpu_to_be32(SGI_INFO_MAGIC
);
114 info
->b1
= cpu_to_be32(-1);
115 info
->b2
= cpu_to_be16(-1);
116 info
->b3
= cpu_to_be16(1);
118 /* You may want to replace this string !!!!!!! */
119 strcpy((char *) info
->scsi_string
, "IBM OEM 0662S12 3 30");
120 strcpy((char *) info
->serial
, "0000");
121 info
->check1816
= cpu_to_be16(18 * 256 + 16);
122 strcpy((char *) info
->installer
, "Sfx version 5.3, Oct 18, 1994");
127 static void sgi_free_info(struct sgi_info
*info
)
132 int fdisk_sgi_create_info(struct fdisk_context
*cxt
)
134 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
136 /* I keep SGI's habit to write the sgilabel to the second block */
137 sgilabel
->volume
[0].block_num
= cpu_to_be32(2);
138 sgilabel
->volume
[0].num_bytes
= cpu_to_be32(sizeof(struct sgi_info
));
139 strncpy((char *) sgilabel
->volume
[0].name
, "sgilabel", 8);
141 fdisk_info(cxt
, _("SGI info created on second sector"));
147 * only dealing with free blocks here
149 static void set_freelist(struct fdisk_context
*cxt
,
150 size_t i
, unsigned int f
, unsigned int l
)
152 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
154 if (i
< ARRAY_SIZE(sgi
->freelist
)) {
155 sgi
->freelist
[i
].first
= f
;
156 sgi
->freelist
[i
].last
= l
;
160 static void add_to_freelist(struct fdisk_context
*cxt
,
161 unsigned int f
, unsigned int l
)
163 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
166 for (i
= 0; i
< ARRAY_SIZE(sgi
->freelist
); i
++) {
167 if (sgi
->freelist
[i
].last
== 0)
170 set_freelist(cxt
, i
, f
, l
);
173 static void clear_freelist(struct fdisk_context
*cxt
)
175 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
177 memset(sgi
->freelist
, 0, sizeof(sgi
->freelist
));
180 static unsigned int is_in_freelist(struct fdisk_context
*cxt
, unsigned int b
)
182 struct fdisk_sgi_label
*sgi
= self_label(cxt
);
185 for (i
= 0; i
< ARRAY_SIZE(sgi
->freelist
); i
++) {
186 if (sgi
->freelist
[i
].first
<= b
187 && sgi
->freelist
[i
].last
>= b
)
188 return sgi
->freelist
[i
].last
;
195 static int sgi_get_nsect(struct fdisk_context
*cxt
)
197 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
198 return be16_to_cpu(sgilabel
->devparam
.nsect
);
201 static int sgi_get_ntrks(struct fdisk_context
*cxt
)
203 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
204 return be16_to_cpu(sgilabel
->devparam
.ntrks
);
207 static size_t count_used_partitions(struct fdisk_context
*cxt
)
211 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++)
212 ct
+= sgi_get_num_sectors(cxt
, i
) > 0;
217 static int sgi_probe_label(struct fdisk_context
*cxt
)
219 struct fdisk_sgi_label
*sgi
;
220 struct sgi_disklabel
*sgilabel
;
224 assert(fdisk_is_disklabel(cxt
, SGI
));
225 assert(sizeof(struct sgi_disklabel
) <= 512);
227 /* map first sector to header */
228 sgi
= (struct fdisk_sgi_label
*) cxt
->label
;
229 sgi
->header
= (struct sgi_disklabel
*) cxt
->firstsector
;
230 sgilabel
= sgi
->header
;
232 if (be32_to_cpu(sgilabel
->magic
) != SGI_LABEL_MAGIC
) {
238 * test for correct checksum
240 if (sgi_pt_checksum(sgilabel
) != 0)
241 fdisk_warnx(cxt
, _("Detected an SGI disklabel with wrong checksum."));
244 cxt
->label
->nparts_max
= SGI_MAXPARTITIONS
;
245 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
249 static int sgi_list_table(struct fdisk_context
*cxt
)
251 struct tt
*tb
= NULL
;
252 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
253 struct sgi_device_parameter
*sgiparam
= &sgilabel
->devparam
;
258 if (fdisk_context_display_details(cxt
))
260 "Label geometry: %d heads, %llu sectors\n"
261 " %llu cylinders, %d physical cylinders\n"
262 " %d extra sects/cyl, interleave %d:1\n"),
263 cxt
->geom
.heads
, cxt
->geom
.sectors
,
264 cxt
->geom
.cylinders
, be16_to_cpu(sgiparam
->pcylcount
),
265 (int) sgiparam
->sparecyl
, be16_to_cpu(sgiparam
->ilfact
));
268 fdisk_list_partitions(cxt
, NULL
, 0);
273 tb
= tt_new_table(TT_FL_FREEDATA
);
277 tt_define_column(tb
, _("#"), 3, TT_FL_RIGHT
);
278 tt_define_column(tb
, _("Name"), 0.2, 0);
279 tt_define_column(tb
, _("Sector"), 2, TT_FL_RIGHT
);
280 tt_define_column(tb
, _("Size"), 9, TT_FL_RIGHT
);
282 for (i
= 0, used
= 0; i
< SGI_MAXVOLUMES
; i
++) {
284 uint32_t start
= be32_to_cpu(sgilabel
->volume
[i
].block_num
),
285 len
= be32_to_cpu(sgilabel
->volume
[i
].num_bytes
);
288 ln
= tt_add_line(tb
, NULL
);
291 if (asprintf(&p
, "%zu:", i
) > 0)
292 tt_line_set_data(ln
, 0, p
); /* # */
293 if (*sgilabel
->volume
[i
].name
)
294 tt_line_set_data(ln
, 1,
295 strndup((char *) sgilabel
->volume
[i
].name
,
296 sizeof(sgilabel
->volume
[i
].name
))); /* Name */
297 if (asprintf(&p
, "%ju", (uintmax_t) start
) > 0)
298 tt_line_set_data(ln
, 2, p
); /* Sector */
299 if (asprintf(&p
, "%ju", (uintmax_t) len
) > 0)
300 tt_line_set_data(ln
, 3, p
); /* Size */
305 rc
= fdisk_print_table(cxt
, tb
);
308 fdisk_colon(cxt
, _("Bootfile: %s"), sgilabel
->boot_file
);
313 static unsigned int sgi_get_start_sector(struct fdisk_context
*cxt
, int i
)
315 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
316 return be32_to_cpu(sgilabel
->partitions
[i
].first_block
);
319 static unsigned int sgi_get_num_sectors(struct fdisk_context
*cxt
, int i
)
321 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
322 return be32_to_cpu(sgilabel
->partitions
[i
].num_blocks
);
325 static int sgi_get_sysid(struct fdisk_context
*cxt
, int i
)
327 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
328 return be32_to_cpu(sgilabel
->partitions
[i
].type
);
331 static int sgi_get_bootpartition(struct fdisk_context
*cxt
)
333 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
334 return be16_to_cpu(sgilabel
->root_part_num
);
337 static int sgi_get_swappartition(struct fdisk_context
*cxt
)
339 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
340 return be16_to_cpu(sgilabel
->swap_part_num
);
343 static unsigned int sgi_get_lastblock(struct fdisk_context
*cxt
)
345 return cxt
->geom
.heads
* cxt
->geom
.sectors
* cxt
->geom
.cylinders
;
348 static struct fdisk_parttype
*sgi_get_parttype(struct fdisk_context
*cxt
, size_t n
)
350 struct fdisk_parttype
*t
;
352 if (n
>= cxt
->label
->nparts_max
)
355 t
= fdisk_get_parttype_from_code(cxt
, sgi_get_sysid(cxt
, n
));
356 return t
? : fdisk_new_unknown_parttype(sgi_get_sysid(cxt
, n
), NULL
);
359 /* fdisk_get_partition() backend */
360 static int sgi_get_partition(struct fdisk_context
*cxt
, size_t n
, struct fdisk_partition
*pa
)
364 pa
->used
= sgi_get_num_sectors(cxt
, n
) > 0;
368 start
= sgi_get_start_sector(cxt
, n
);
369 len
= sgi_get_num_sectors(cxt
, n
);
371 pa
->type
= sgi_get_parttype(cxt
, n
);
374 pa
->end
= start
+ len
- (len
? 1 : 0);
376 pa
->attrs
= sgi_get_swappartition(cxt
) == (int) n
? "swap" :
377 sgi_get_bootpartition(cxt
) == (int) n
? "boot" : NULL
;
379 pa
->attrs
= strdup(pa
->attrs
);
385 static int sgi_check_bootfile(struct fdisk_context
*cxt
, const char *name
)
388 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
393 /* "/a\n" is minimum */
394 fdisk_warnx(cxt
, _("Invalid bootfile! The bootfile must "
395 "be an absolute non-zero pathname, "
396 "e.g. \"/unix\" or \"/unix.save\"."));
399 } else if (sz
> sizeof(sgilabel
->boot_file
)) {
400 fdisk_warnx(cxt
, P_("Name of bootfile is too long: %zu byte maximum.",
401 "Name of bootfile is too long: %zu bytes maximum.",
402 sizeof(sgilabel
->boot_file
)),
403 sizeof(sgilabel
->boot_file
));
406 } else if (*name
!= '/') {
407 fdisk_warnx(cxt
, _("Bootfile must have a fully qualified pathname."));
411 if (strncmp(name
, (char *) sgilabel
->boot_file
,
412 sizeof(sgilabel
->boot_file
))) {
413 fdisk_warnx(cxt
, _("Be aware that the bootfile is not checked "
414 "for existence. SGI's default is \"/unix\", "
415 "and for backup \"/unix.save\"."));
416 return 0; /* filename is correct and did change */
419 return 1; /* filename did not change */
422 int fdisk_sgi_set_bootfile(struct fdisk_context
*cxt
)
427 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
429 fdisk_info(cxt
, _("The current boot file is: %s"), sgilabel
->boot_file
);
431 rc
= fdisk_ask_string(cxt
, _("Enter of the new boot file"), &name
);
433 rc
= sgi_check_bootfile(cxt
, name
);
436 fdisk_info(cxt
, _("Boot file is unchanged."));
440 memset(sgilabel
->boot_file
, 0, sizeof(sgilabel
->boot_file
));
443 assert(sz
<= sizeof(sgilabel
->boot_file
)); /* see sgi_check_bootfile() */
445 memcpy(sgilabel
->boot_file
, name
, sz
);
447 fdisk_sinfo(cxt
, FDISK_INFO_SUCCESS
,
448 _("Bootfile has been changed to \"%s\"."), name
);
454 static int sgi_write_disklabel(struct fdisk_context
*cxt
)
456 struct sgi_disklabel
*sgilabel
;
457 struct sgi_info
*info
= NULL
;
461 assert(fdisk_is_disklabel(cxt
, SGI
));
463 sgilabel
= self_disklabel(cxt
);
465 sgilabel
->csum
= cpu_to_be32(sgi_pt_checksum(sgilabel
));
467 assert(sgi_pt_checksum(sgilabel
) == 0);
469 if (lseek(cxt
->dev_fd
, 0, SEEK_SET
) < 0)
471 if (write_all(cxt
->dev_fd
, sgilabel
, DEFAULT_SECTOR_SIZE
))
473 if (!strncmp((char *) sgilabel
->volume
[0].name
, "sgilabel", 8)) {
475 * Keep this habit of first writing the "sgilabel".
476 * I never tested whether it works without. (AN 1998-10-02)
479 = be32_to_cpu(sgilabel
->volume
[0].block_num
);
481 if (lseek(cxt
->dev_fd
, (off_t
) infostartblock
*
482 DEFAULT_SECTOR_SIZE
, SEEK_SET
) < 0)
484 info
= sgi_new_info();
487 if (write_all(cxt
->dev_fd
, info
, sizeof(*info
)))
498 static int compare_start(struct fdisk_context
*cxt
,
499 const void *x
, const void *y
)
502 * Sort according to start sectors and prefer the largest partition:
503 * entry zero is the entire-disk entry.
505 unsigned int i
= *(int *) x
;
506 unsigned int j
= *(int *) y
;
507 unsigned int a
= sgi_get_start_sector(cxt
, i
);
508 unsigned int b
= sgi_get_start_sector(cxt
, j
);
509 unsigned int c
= sgi_get_num_sectors(cxt
, i
);
510 unsigned int d
= sgi_get_num_sectors(cxt
, j
);
513 return (d
> c
) ? 1 : (d
== c
) ? 0 : -1;
514 return (a
> b
) ? 1 : -1;
517 static void generic_swap(void *a0
, void *b0
, int size
)
519 char *a
= a0
, *b
= b0
;
521 for (; size
> 0; --size
, a
++, b
++) {
529 /* heap sort, based on Matt Mackall's linux kernel version */
530 static void sort(void *base0
, size_t num
, size_t size
, struct fdisk_context
*cxt
,
531 int (*cmp_func
)(struct fdisk_context
*, const void *, const void *))
533 /* pre-scale counters for performance */
534 int i
= (num
/2 - 1) * size
;
535 size_t n
= num
* size
, c
, r
;
539 for ( ; i
>= 0; i
-= size
) {
540 for (r
= i
; r
* 2 + size
< n
; r
= c
) {
543 cmp_func(cxt
, base
+ c
, base
+ c
+ size
) < 0)
545 if (cmp_func(cxt
, base
+ r
, base
+ c
) >= 0)
547 generic_swap(base
+ r
, base
+ c
, size
);
552 for (i
= n
- size
; i
> 0; i
-= size
) {
553 generic_swap(base
, base
+ i
, size
);
554 for (r
= 0; r
* 2 + size
< (size_t) i
; r
= c
) {
557 cmp_func(cxt
, base
+ c
, base
+ c
+ size
) < 0)
559 if (cmp_func(cxt
, base
+ r
, base
+ c
) >= 0)
561 generic_swap(base
+ r
, base
+ c
, size
);
566 static int verify_disklabel(struct fdisk_context
*cxt
, int verbose
)
568 int Index
[SGI_MAXPARTITIONS
]; /* list of valid partitions */
569 int sortcount
= 0; /* number of used partitions, i.e. non-zero lengths */
570 int entire
= 0, i
= 0;
571 unsigned int start
= 0;
572 long long gap
= 0; /* count unused blocks */
573 unsigned int lastblock
= sgi_get_lastblock(cxt
);
577 assert(fdisk_is_disklabel(cxt
, SGI
));
580 memset(Index
, 0, sizeof(Index
));
582 for (i
=0; i
< SGI_MAXPARTITIONS
; i
++) {
583 if (sgi_get_num_sectors(cxt
, i
) != 0) {
584 Index
[sortcount
++] = i
;
585 if (sgi_get_sysid(cxt
, i
) == SGI_TYPE_ENTIRE_DISK
588 fdisk_info(cxt
, _("More than one entire "
589 "disk entry present."));
593 if (sortcount
== 0) {
595 fdisk_info(cxt
, _("No partitions defined."));
596 return (lastblock
> 0) ? 1 : (lastblock
== 0) ? 0 : -1;
599 sort(Index
, sortcount
, sizeof(Index
[0]), cxt
, compare_start
);
601 if (sgi_get_sysid(cxt
, Index
[0]) == SGI_TYPE_ENTIRE_DISK
) {
602 if (verbose
&& Index
[0] != 10)
603 fdisk_info(cxt
, _("IRIX likes it when partition 11 "
604 "covers the entire disk."));
606 if (verbose
&& sgi_get_start_sector(cxt
, Index
[0]) != 0)
607 fdisk_info(cxt
, _("The entire disk partition should "
608 "start at block 0, not at block %d."),
609 sgi_get_start_sector(cxt
, Index
[0]));
611 if (verbose
&& sgi_get_num_sectors(cxt
, Index
[0]) != lastblock
)
613 "entire disk partition=%ds, but disk=%ds",
614 sgi_get_num_sectors(cxt
, Index
[0]),
616 lastblock
= sgi_get_num_sectors(cxt
, Index
[0]);
617 } else if (verbose
) {
618 fdisk_info(cxt
, _("Partition 11 should cover the entire disk."));
619 DBG(LABEL
, dbgprint("sysid=%d\tpartition=%d",
620 sgi_get_sysid(cxt
, Index
[0]), Index
[0]+1));
622 for (i
=1, start
=0; i
<sortcount
; i
++) {
623 int cylsize
= sgi_get_nsect(cxt
) * sgi_get_ntrks(cxt
);
625 if (verbose
&& cylsize
626 && (sgi_get_start_sector(cxt
, Index
[i
]) % cylsize
) != 0)
627 DBG(LABEL
, dbgprint("partition %d does not start on "
628 "cylinder boundary.", Index
[i
]+1));
630 if (verbose
&& cylsize
631 && sgi_get_num_sectors(cxt
, Index
[i
]) % cylsize
!= 0)
632 DBG(LABEL
, dbgprint("partition %d does not end on "
633 "cylinder boundary.", Index
[i
]+1));
635 /* We cannot handle several "entire disk" entries. */
636 if (sgi_get_sysid(cxt
, Index
[i
]) == SGI_TYPE_ENTIRE_DISK
)
639 if (start
> sgi_get_start_sector(cxt
, Index
[i
])) {
642 P_("Partitions %d and %d overlap by %d sector.",
643 "Partitions %d and %d overlap by %d sectors.",
644 start
- sgi_get_start_sector(cxt
, Index
[i
])),
645 Index
[i
-1]+1, Index
[i
]+1,
646 start
- sgi_get_start_sector(cxt
, Index
[i
]));
647 if (gap
> 0) gap
= -gap
;
648 if (gap
== 0) gap
= -1;
650 if (start
< sgi_get_start_sector(cxt
, Index
[i
])) {
653 P_("Unused gap of %8u sector: sector %8u",
654 "Unused gap of %8u sectors: sectors %8u-%u",
655 sgi_get_start_sector(cxt
, Index
[i
]) - start
),
656 sgi_get_start_sector(cxt
, Index
[i
]) - start
,
657 start
, sgi_get_start_sector(cxt
, Index
[i
])-1);
658 gap
+= sgi_get_start_sector(cxt
, Index
[i
]) - start
;
659 add_to_freelist(cxt
, start
,
660 sgi_get_start_sector(cxt
, Index
[i
]));
662 start
= sgi_get_start_sector(cxt
, Index
[i
])
663 + sgi_get_num_sectors(cxt
, Index
[i
]);
664 /* Align free space on cylinder boundary. */
665 if (cylsize
&& start
% cylsize
)
666 start
+= cylsize
- (start
% cylsize
);
668 DBG(LABEL
, dbgprint("%2d:%12d\t%12d\t%12d", Index
[i
],
669 sgi_get_start_sector(cxt
, Index
[i
]),
670 sgi_get_num_sectors(cxt
, Index
[i
]),
671 sgi_get_sysid(cxt
, Index
[i
])));
673 if (start
< lastblock
) {
675 fdisk_info(cxt
, P_("Unused gap of %8u sector: sector %8u",
676 "Unused gap of %8u sectors: sectors %8u-%u",
678 lastblock
- start
, start
, lastblock
-1);
679 gap
+= lastblock
- start
;
680 add_to_freelist(cxt
, start
, lastblock
);
683 * Done with arithmetics. Go for details now.
686 if (sgi_get_bootpartition(cxt
) < 0
687 || !sgi_get_num_sectors(cxt
, sgi_get_bootpartition(cxt
)))
688 fdisk_info(cxt
, _("The boot partition does not exist."));
690 if (sgi_get_swappartition(cxt
) < 0
691 || !sgi_get_num_sectors(cxt
, sgi_get_swappartition(cxt
)))
692 fdisk_info(cxt
, _("The swap partition does not exist."));
694 else if (sgi_get_sysid(cxt
, sgi_get_swappartition(cxt
)) != SGI_TYPE_SWAP
695 && sgi_get_sysid(cxt
, sgi_get_swappartition(cxt
)) != MBR_LINUX_SWAP_PARTITION
)
696 fdisk_info(cxt
, _("The swap partition has no swap type."));
698 if (sgi_check_bootfile(cxt
, "/unix"))
699 fdisk_info(cxt
, _("You have chosen an unusual bootfile name."));
702 return (gap
> 0) ? 1 : (gap
== 0) ? 0 : -1;
705 static int sgi_verify_disklabel(struct fdisk_context
*cxt
)
707 return verify_disklabel(cxt
, 1);
710 static int sgi_gaps(struct fdisk_context
*cxt
)
714 * = 0 : disk is properly filled to the rim
715 * < 0 : there is an overlap
716 * > 0 : there is still some vacant space
718 return verify_disklabel(cxt
, 0);
721 /* Returns partition index of first entry marked as entire disk. */
722 static int sgi_entire(struct fdisk_context
*cxt
)
726 for (i
= 0; i
< SGI_MAXPARTITIONS
; i
++)
727 if (sgi_get_sysid(cxt
, i
) == SGI_TYPE_ENTIRE_DISK
)
732 static int sgi_set_partition(struct fdisk_context
*cxt
, size_t i
,
733 unsigned int start
, unsigned int length
, int sys
)
735 struct sgi_disklabel
*sgilabel
;
739 assert(fdisk_is_disklabel(cxt
, SGI
));
741 sgilabel
= self_disklabel(cxt
);
742 sgilabel
->partitions
[i
].type
= cpu_to_be32(sys
);
743 sgilabel
->partitions
[i
].num_blocks
= cpu_to_be32(length
);
744 sgilabel
->partitions
[i
].first_block
= cpu_to_be32(start
);
746 fdisk_label_set_changed(cxt
->label
, 1);
748 if (sgi_gaps(cxt
) < 0) /* rebuild freelist */
749 fdisk_warnx(cxt
, _("Partition overlap on the disk."));
751 struct fdisk_parttype
*t
= fdisk_get_parttype_from_code(cxt
, sys
);
752 fdisk_info_new_partition(cxt
, i
+ 1, start
, start
+ length
, t
);
758 static void sgi_set_entire(struct fdisk_context
*cxt
)
762 for (n
= 10; n
< cxt
->label
->nparts_max
; n
++) {
763 if (!sgi_get_num_sectors(cxt
, n
)) {
764 sgi_set_partition(cxt
, n
, 0, sgi_get_lastblock(cxt
), SGI_TYPE_ENTIRE_DISK
);
770 static void sgi_set_volhdr(struct fdisk_context
*cxt
)
774 for (n
= 8; n
< cxt
->label
->nparts_max
; n
++) {
775 if (!sgi_get_num_sectors(cxt
, n
)) {
776 /* Choose same default volume header size as IRIX fx uses. */
777 if (4096 < sgi_get_lastblock(cxt
))
778 sgi_set_partition(cxt
, n
, 0, 4096, SGI_TYPE_VOLHDR
);
784 static int sgi_delete_partition(struct fdisk_context
*cxt
, size_t partnum
)
791 if (partnum
> cxt
->label
->nparts_max
)
794 rc
= sgi_set_partition(cxt
, partnum
, 0, 0, 0);
796 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
801 static int sgi_add_partition(struct fdisk_context
*cxt
,
802 struct fdisk_partition
*pa
)
804 struct fdisk_sgi_label
*sgi
;
806 unsigned int first
= 0, last
= 0;
807 struct fdisk_ask
*ask
;
808 int sys
= pa
&& pa
->type
? pa
->type
->type
: SGI_TYPE_XFS
;
814 assert(fdisk_is_disklabel(cxt
, SGI
));
816 rc
= fdisk_partition_next_partno(cxt
, pa
, &n
);
820 sys
= SGI_TYPE_ENTIRE_DISK
;
824 sgi
= self_label(cxt
);
826 if (sgi_get_num_sectors(cxt
, n
)) {
827 fdisk_warnx(cxt
, _("Partition %zu is already defined. "
828 "Delete it before re-adding it."), n
+ 1);
831 if (sgi_entire(cxt
) == -1 && sys
!= SGI_TYPE_ENTIRE_DISK
) {
832 fdisk_info(cxt
, _("Attempting to generate entire disk entry automatically."));
836 if (sgi_gaps(cxt
) == 0 && sys
!= SGI_TYPE_ENTIRE_DISK
) {
837 fdisk_warnx(cxt
, _("The entire disk is already covered with partitions."));
840 if (sgi_gaps(cxt
) < 0) {
841 fdisk_warnx(cxt
, _("You got a partition overlap on the disk. Fix it first!"));
845 if (sys
== SGI_TYPE_ENTIRE_DISK
) {
847 last
= sgi_get_lastblock(cxt
);
849 first
= sgi
->freelist
[0].first
;
850 last
= sgi
->freelist
[0].last
;
854 if (pa
&& pa
->start_follow_default
)
856 else if (pa
&& pa
->start
) {
858 last
= is_in_freelist(cxt
, first
);
860 if (sys
!= SGI_TYPE_ENTIRE_DISK
&& !last
)
863 snprintf(mesg
, sizeof(mesg
), _("First %s"),
864 fdisk_context_get_unit(cxt
, SINGULAR
));
865 ask
= fdisk_new_ask();
869 fdisk_ask_set_query(ask
, mesg
);
870 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_NUMBER
);
872 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
873 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, first
)); /* default */
874 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, last
) - 1); /* maximal */
876 rc
= fdisk_do_ask(cxt
, ask
);
877 first
= fdisk_ask_number_get_result(ask
);
882 if (fdisk_context_use_cylinders(cxt
))
883 first
*= fdisk_context_get_units_per_sector(cxt
);
886 if (first
&& sys
== SGI_TYPE_ENTIRE_DISK
)
887 fdisk_info(cxt
, _("It is highly recommended that the "
888 "eleventh partition covers the entire "
889 "disk and is of type 'SGI volume'."));
891 last
= is_in_freelist(cxt
, first
);
894 if (pa
&& pa
->end_follow_default
)
896 else if (pa
&& pa
->size
) {
897 if (first
+ pa
->size
> last
)
899 last
= first
+ pa
->size
;
901 snprintf(mesg
, sizeof(mesg
),
902 _("Last %s or +%s or +size{K,M,G,T,P}"),
903 fdisk_context_get_unit(cxt
, SINGULAR
),
904 fdisk_context_get_unit(cxt
, PLURAL
));
906 ask
= fdisk_new_ask();
910 fdisk_ask_set_query(ask
, mesg
);
911 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_OFFSET
);
913 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
914 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, last
) - 1);/* default */
915 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, last
) - 1);/* maximal */
916 fdisk_ask_number_set_base(ask
, fdisk_scround(cxt
, first
));
918 if (fdisk_context_use_cylinders(cxt
))
919 fdisk_ask_number_set_unit(ask
,
921 fdisk_context_get_units_per_sector(cxt
));
923 fdisk_ask_number_set_unit(ask
,cxt
->sector_size
);
925 rc
= fdisk_do_ask(cxt
, ask
);
926 last
= fdisk_ask_number_get_result(ask
) + 1;
931 if (fdisk_context_use_cylinders(cxt
))
932 last
*= fdisk_context_get_units_per_sector(cxt
);
935 if (sys
== SGI_TYPE_ENTIRE_DISK
936 && (first
!= 0 || last
!= sgi_get_lastblock(cxt
)))
937 fdisk_info(cxt
, _("It is highly recommended that the "
938 "eleventh partition covers the entire "
939 "disk and is of type 'SGI volume'."));
941 sgi_set_partition(cxt
, n
, first
, last
- first
, sys
);
942 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
947 static int sgi_create_disklabel(struct fdisk_context
*cxt
)
949 struct fdisk_sgi_label
*sgi
;
950 struct sgi_disklabel
*sgilabel
;
954 assert(fdisk_is_disklabel(cxt
, SGI
));
957 if (cxt
->geom
.heads
&& cxt
->geom
.sectors
) {
960 if (blkdev_get_sectors(cxt
->dev_fd
, &llsectors
) == 0) {
961 /* the get device size ioctl was successful */
963 int sec_fac
= cxt
->sector_size
/ 512;
965 llcyls
= llsectors
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
* sec_fac
);
966 cxt
->geom
.cylinders
= llcyls
;
967 if (cxt
->geom
.cylinders
!= llcyls
) /* truncated? */
968 cxt
->geom
.cylinders
= ~0;
970 /* otherwise print error and use truncated version */
972 _("BLKGETSIZE ioctl failed on %s. "
973 "Using geometry cylinder value of %llu. "
974 "This value may be truncated for devices "
975 "> 33.8 GB."), cxt
->dev_path
, cxt
->geom
.cylinders
);
979 fdisk_zeroize_firstsector(cxt
);
980 sgi
= (struct fdisk_sgi_label
*) cxt
->label
;
981 sgi
->header
= (struct sgi_disklabel
*) cxt
->firstsector
;
983 sgilabel
= sgi
->header
;
985 sgilabel
->magic
= cpu_to_be32(SGI_LABEL_MAGIC
);
986 sgilabel
->root_part_num
= cpu_to_be16(0);
987 sgilabel
->swap_part_num
= cpu_to_be16(1);
989 /* sizeof(sgilabel->boot_file) = 16 > 6 */
990 memset(sgilabel
->boot_file
, 0, 16);
991 strcpy((char *) sgilabel
->boot_file
, "/unix");
993 sgilabel
->devparam
.skew
= (0);
994 sgilabel
->devparam
.gap1
= (0);
995 sgilabel
->devparam
.gap2
= (0);
996 sgilabel
->devparam
.sparecyl
= (0);
997 sgilabel
->devparam
.pcylcount
= cpu_to_be16(cxt
->geom
.cylinders
);
998 sgilabel
->devparam
.head_vol0
= cpu_to_be16(0);
999 sgilabel
->devparam
.ntrks
= cpu_to_be16(cxt
->geom
.heads
);
1000 /* tracks/cylinder (heads) */
1001 sgilabel
->devparam
.cmd_tag_queue_depth
= (0);
1002 sgilabel
->devparam
.unused0
= (0);
1003 sgilabel
->devparam
.unused1
= cpu_to_be16(0);
1004 sgilabel
->devparam
.nsect
= cpu_to_be16(cxt
->geom
.sectors
);
1006 sgilabel
->devparam
.bytes
= cpu_to_be16(cxt
->sector_size
);
1007 sgilabel
->devparam
.ilfact
= cpu_to_be16(1);
1008 sgilabel
->devparam
.flags
= cpu_to_be32(
1009 SGI_DEVPARAM_TRACK_FWD
1010 | SGI_DEVPARAM_IGNORE_ERRORS
1011 | SGI_DEVPARAM_RESEEK
);
1012 sgilabel
->devparam
.datarate
= cpu_to_be32(0);
1013 sgilabel
->devparam
.retries_on_error
= cpu_to_be32(1);
1014 sgilabel
->devparam
.ms_per_word
= cpu_to_be32(0);
1015 sgilabel
->devparam
.xylogics_gap1
= cpu_to_be16(0);
1016 sgilabel
->devparam
.xylogics_syncdelay
= cpu_to_be16(0);
1017 sgilabel
->devparam
.xylogics_readdelay
= cpu_to_be16(0);
1018 sgilabel
->devparam
.xylogics_gap2
= cpu_to_be16(0);
1019 sgilabel
->devparam
.xylogics_readgate
= cpu_to_be16(0);
1020 sgilabel
->devparam
.xylogics_writecont
= cpu_to_be16(0);
1022 memset(&(sgilabel
->volume
), 0,
1023 sizeof(struct sgi_volume
) * SGI_MAXVOLUMES
);
1024 memset(&(sgilabel
->partitions
), 0,
1025 sizeof(struct sgi_partition
) * SGI_MAXPARTITIONS
);
1026 cxt
->label
->nparts_max
= SGI_MAXPARTITIONS
;
1027 sgi_set_entire(cxt
);
1028 sgi_set_volhdr(cxt
);
1030 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
1032 fdisk_sinfo(cxt
, FDISK_INFO_SUCCESS
,
1033 _("Created a new SGI disklabel."));
1037 static int sgi_set_parttype(struct fdisk_context
*cxt
,
1039 struct fdisk_parttype
*t
)
1041 struct sgi_disklabel
*sgilabel
;
1043 if (i
>= cxt
->label
->nparts_max
|| !t
|| t
->type
> UINT32_MAX
)
1046 if (sgi_get_num_sectors(cxt
, i
) == 0) /* caught already before, ... */ {
1047 fdisk_warnx(cxt
, _("Sorry, only for non-empty partitions you can change the tag."));
1051 if ((i
== 10 && t
->type
!= SGI_TYPE_ENTIRE_DISK
)
1052 || (i
== 8 && t
->type
!= 0))
1053 fdisk_info(cxt
, _("Consider leaving partition 9 as volume header (0), "
1054 "and partition 11 as entire volume (6), "
1055 "as IRIX expects it."));
1057 if (((t
->type
!= SGI_TYPE_ENTIRE_DISK
) && (t
->type
!= SGI_TYPE_VOLHDR
))
1058 && (sgi_get_start_sector(cxt
, i
) < 1)) {
1060 fdisk_ask_yesno(cxt
,
1061 _("It is highly recommended that the partition at offset 0 "
1062 "is of type \"SGI volhdr\", the IRIX system will rely on it to "
1063 "retrieve from its directory standalone tools like sash and fx. "
1064 "Only the \"SGI volume\" entire disk section may violate this. "
1065 "Are you sure about tagging this partition differently?"), &yes
);
1070 sgilabel
= self_disklabel(cxt
);
1071 sgilabel
->partitions
[i
].type
= cpu_to_be32(t
->type
);
1076 static int sgi_partition_is_used(
1077 struct fdisk_context
*cxt
,
1081 assert(fdisk_is_disklabel(cxt
, SGI
));
1083 if (i
>= cxt
->label
->nparts_max
)
1085 return sgi_get_num_sectors(cxt
, i
) ? 1 : 0;
1088 static int sgi_toggle_partition_flag(struct fdisk_context
*cxt
, size_t i
, unsigned long flag
)
1090 struct sgi_disklabel
*sgilabel
;
1093 assert(fdisk_is_disklabel(cxt
, SGI
));
1095 if (i
>= cxt
->label
->nparts_max
)
1098 sgilabel
= self_disklabel(cxt
);
1102 sgilabel
->root_part_num
=
1103 be16_to_cpu(sgilabel
->root_part_num
) == i
?
1105 fdisk_label_set_changed(cxt
->label
, 1);
1108 sgilabel
->swap_part_num
=
1109 be16_to_cpu(sgilabel
->swap_part_num
) == i
?
1111 fdisk_label_set_changed(cxt
->label
, 1);
1120 static const struct fdisk_column sgi_columns
[] =
1122 { FDISK_COL_DEVICE
, N_("Device"), 10, 0 },
1123 { FDISK_COL_START
, N_("Start"), 5, TT_FL_RIGHT
},
1124 { FDISK_COL_END
, N_("End"), 5, TT_FL_RIGHT
},
1125 { FDISK_COL_SECTORS
, N_("Sectors"), 5, TT_FL_RIGHT
},
1126 { FDISK_COL_SIZE
, N_("Size"), 5, TT_FL_RIGHT
, FDISK_COLFL_EYECANDY
},
1127 { FDISK_COL_TYPEID
, N_("Id"), 2, TT_FL_RIGHT
},
1128 { FDISK_COL_TYPE
, N_("Type"), 0.1, TT_FL_TRUNC
, FDISK_COLFL_EYECANDY
},
1129 { FDISK_COL_ATTR
, N_("Attrs"), 0, TT_FL_RIGHT
}
1132 static const struct fdisk_label_operations sgi_operations
=
1134 .probe
= sgi_probe_label
,
1135 .write
= sgi_write_disklabel
,
1136 .verify
= sgi_verify_disklabel
,
1137 .create
= sgi_create_disklabel
,
1138 .list
= sgi_list_table
,
1140 .get_part
= sgi_get_partition
,
1141 .add_part
= sgi_add_partition
,
1143 .part_delete
= sgi_delete_partition
,
1144 .part_set_type
= sgi_set_parttype
,
1146 .part_is_used
= sgi_partition_is_used
,
1147 .part_toggle_flag
= sgi_toggle_partition_flag
1150 /* Allocates an SGI label driver. */
1151 struct fdisk_label
*fdisk_new_sgi_label(struct fdisk_context
*cxt
)
1153 struct fdisk_label
*lb
;
1154 struct fdisk_sgi_label
*sgi
;
1158 sgi
= calloc(1, sizeof(*sgi
));
1162 /* initialize generic part of the driver */
1163 lb
= (struct fdisk_label
*) sgi
;
1165 lb
->id
= FDISK_DISKLABEL_SGI
;
1166 lb
->op
= &sgi_operations
;
1167 lb
->parttypes
= sgi_parttypes
;
1168 lb
->nparttypes
= ARRAY_SIZE(sgi_parttypes
);
1169 lb
->columns
= sgi_columns
;
1170 lb
->ncolumns
= ARRAY_SIZE(sgi_columns
);
1172 lb
->flags
|= FDISK_LABEL_FL_REQUIRE_GEOMETRY
;