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 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
));
270 tb
= tt_new_table(TT_FL_FREEDATA
);
274 tt_define_column(tb
, _("Pt#"), 3, TT_FL_RIGHT
);
275 tt_define_column(tb
, _("Device"), 0.2, 0);
276 tt_define_column(tb
, _("Info"), 2, 0);
277 tt_define_column(tb
, _("Start"), 9, TT_FL_RIGHT
);
278 tt_define_column(tb
, _("End"), 9, TT_FL_RIGHT
);
279 tt_define_column(tb
, _("Sectors"), 9, TT_FL_RIGHT
);
280 tt_define_column(tb
, _("Id"), 2, TT_FL_RIGHT
);
281 tt_define_column(tb
, _("System"), 0.2, TT_FL_TRUNC
);
283 for (i
= 0, used
= 1; i
< cxt
->label
->nparts_max
; i
++) {
285 struct fdisk_parttype
*t
;
288 if (sgi_get_num_sectors(cxt
, i
) == 0)
291 ln
= tt_add_line(tb
, NULL
);
294 start
= sgi_get_start_sector(cxt
, i
);
295 len
= sgi_get_num_sectors(cxt
, i
);
296 t
= fdisk_get_partition_type(cxt
, i
);
298 if (asprintf(&p
, "%zu:", i
+ 1) > 0)
299 tt_line_set_data(ln
, 0, p
); /* # */
300 p
= fdisk_partname(cxt
->dev_path
, used
++);
302 tt_line_set_data(ln
, 1, p
); /* Device */
304 p
= sgi_get_swappartition(cxt
) == (int) i
? "swap" :
305 sgi_get_bootpartition(cxt
) == (int) i
? "boot" : NULL
;
307 tt_line_set_data(ln
, 2, strdup(p
)); /* Info */
309 if (asprintf(&p
, "%ju", (uintmax_t) fdisk_scround(cxt
, start
)) > 0)
310 tt_line_set_data(ln
, 3, p
); /* Start */
311 if (asprintf(&p
, "%ju", (uintmax_t) fdisk_scround(cxt
, start
+ len
) - 1) > 0)
312 tt_line_set_data(ln
, 4, p
); /* End */
313 if (asprintf(&p
, "%ju", (uintmax_t) len
) > 0)
314 tt_line_set_data(ln
, 5, p
); /* Sectors*/
315 if (asprintf(&p
, "%2x", t
->type
) > 0)
316 tt_line_set_data(ln
, 6, p
); /* type ID */
318 tt_line_set_data(ln
, 7, strdup(t
->name
)); /* type Name */
319 fdisk_free_parttype(t
);
322 rc
= fdisk_print_table(cxt
, tb
);
330 tb
= tt_new_table(TT_FL_FREEDATA
);
334 tt_define_column(tb
, _("#"), 3, TT_FL_RIGHT
);
335 tt_define_column(tb
, _("Name"), 0.2, 0);
336 tt_define_column(tb
, _("Sector"), 2, TT_FL_RIGHT
);
337 tt_define_column(tb
, _("Size"), 9, TT_FL_RIGHT
);
339 for (i
= 0, used
= 0; i
< SGI_MAXVOLUMES
; i
++) {
341 uint32_t start
= be32_to_cpu(sgilabel
->volume
[i
].block_num
),
342 len
= be32_to_cpu(sgilabel
->volume
[i
].num_bytes
);
345 ln
= tt_add_line(tb
, NULL
);
348 if (asprintf(&p
, "%zu:", i
) > 0)
349 tt_line_set_data(ln
, 0, p
); /* # */
350 if (*sgilabel
->volume
[i
].name
)
351 tt_line_set_data(ln
, 1,
352 strndup((char *) sgilabel
->volume
[i
].name
,
353 sizeof(sgilabel
->volume
[i
].name
))); /* Name */
354 if (asprintf(&p
, "%ju", (uintmax_t) start
) > 0)
355 tt_line_set_data(ln
, 2, p
); /* Sector */
356 if (asprintf(&p
, "%ju", (uintmax_t) len
) > 0)
357 tt_line_set_data(ln
, 3, p
); /* Size */
362 rc
= fdisk_print_table(cxt
, tb
);
365 fdisk_colon(cxt
, _("Bootfile: %s"), sgilabel
->boot_file
);
370 static unsigned int sgi_get_start_sector(struct fdisk_context
*cxt
, int i
)
372 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
373 return be32_to_cpu(sgilabel
->partitions
[i
].first_block
);
376 static unsigned int sgi_get_num_sectors(struct fdisk_context
*cxt
, int i
)
378 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
379 return be32_to_cpu(sgilabel
->partitions
[i
].num_blocks
);
382 static int sgi_get_sysid(struct fdisk_context
*cxt
, int i
)
384 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
385 return be32_to_cpu(sgilabel
->partitions
[i
].type
);
388 static int sgi_get_bootpartition(struct fdisk_context
*cxt
)
390 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
391 return be16_to_cpu(sgilabel
->root_part_num
);
394 static int sgi_get_swappartition(struct fdisk_context
*cxt
)
396 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
397 return be16_to_cpu(sgilabel
->swap_part_num
);
400 static unsigned int sgi_get_lastblock(struct fdisk_context
*cxt
)
402 return cxt
->geom
.heads
* cxt
->geom
.sectors
* cxt
->geom
.cylinders
;
405 static int sgi_check_bootfile(struct fdisk_context
*cxt
, const char *name
)
408 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
413 /* "/a\n" is minimum */
414 fdisk_warnx(cxt
, _("Invalid Bootfile! "
415 "The bootfile must be an absolute non-zero pathname,"
416 "e.g. \"/unix\" or \"/unix.save\"."));
419 } else if (sz
> sizeof(sgilabel
->boot_file
)) {
420 fdisk_warnx(cxt
, P_("Name of bootfile is too long: %zu byte maximum.",
421 "Name of bootfile is too long: %zu bytes maximum.",
422 sizeof(sgilabel
->boot_file
)),
423 sizeof(sgilabel
->boot_file
));
426 } else if (*name
!= '/') {
427 fdisk_warnx(cxt
, _("Bootfile must have a fully qualified pathname."));
431 if (strncmp(name
, (char *) sgilabel
->boot_file
,
432 sizeof(sgilabel
->boot_file
))) {
433 fdisk_warnx(cxt
, _("Be aware, that the bootfile is not checked "
434 "for existence. SGI's default is \"/unix\" and for "
435 "backup \"/unix.save\"."));
436 return 0; /* filename is correct and did change */
439 return 1; /* filename did not change */
442 int fdisk_sgi_set_bootfile(struct fdisk_context
*cxt
)
447 struct sgi_disklabel
*sgilabel
= self_disklabel(cxt
);
449 fdisk_info(cxt
, _("The current boot file is: %s"), sgilabel
->boot_file
);
451 rc
= fdisk_ask_string(cxt
, _("Enter of the new boot file"), &name
);
453 rc
= sgi_check_bootfile(cxt
, name
);
456 fdisk_info(cxt
, _("Boot file unchanged"));
460 memset(sgilabel
->boot_file
, 0, sizeof(sgilabel
->boot_file
));
463 assert(sz
<= sizeof(sgilabel
->boot_file
)); /* see sgi_check_bootfile() */
465 memcpy(sgilabel
->boot_file
, name
, sz
);
467 fdisk_sinfo(cxt
, FDISK_INFO_SUCCESS
,
468 _("Bootfile is changed to \"%s\"."), name
);
474 static int sgi_write_disklabel(struct fdisk_context
*cxt
)
476 struct sgi_disklabel
*sgilabel
;
477 struct sgi_info
*info
= NULL
;
481 assert(fdisk_is_disklabel(cxt
, SGI
));
483 sgilabel
= self_disklabel(cxt
);
485 sgilabel
->csum
= cpu_to_be32(sgi_pt_checksum(sgilabel
));
487 assert(sgi_pt_checksum(sgilabel
) == 0);
489 if (lseek(cxt
->dev_fd
, 0, SEEK_SET
) < 0)
491 if (write_all(cxt
->dev_fd
, sgilabel
, DEFAULT_SECTOR_SIZE
))
493 if (!strncmp((char *) sgilabel
->volume
[0].name
, "sgilabel", 8)) {
495 * Keep this habit of first writing the "sgilabel".
496 * I never tested whether it works without. (AN 1998-10-02)
499 = be32_to_cpu(sgilabel
->volume
[0].block_num
);
501 if (lseek(cxt
->dev_fd
, (off_t
) infostartblock
*
502 DEFAULT_SECTOR_SIZE
, SEEK_SET
) < 0)
504 info
= sgi_new_info();
507 if (write_all(cxt
->dev_fd
, info
, sizeof(*info
)))
518 static int compare_start(struct fdisk_context
*cxt
,
519 const void *x
, const void *y
)
522 * Sort according to start sectors and prefer the largest partition:
523 * entry zero is the entire-disk entry.
525 unsigned int i
= *(int *) x
;
526 unsigned int j
= *(int *) y
;
527 unsigned int a
= sgi_get_start_sector(cxt
, i
);
528 unsigned int b
= sgi_get_start_sector(cxt
, j
);
529 unsigned int c
= sgi_get_num_sectors(cxt
, i
);
530 unsigned int d
= sgi_get_num_sectors(cxt
, j
);
533 return (d
> c
) ? 1 : (d
== c
) ? 0 : -1;
534 return (a
> b
) ? 1 : -1;
537 static void generic_swap(void *a0
, void *b0
, int size
)
539 char *a
= a0
, *b
= b0
;
541 for (; size
> 0; --size
, a
++, b
++) {
549 /* heap sort, based on Matt Mackall's linux kernel version */
550 static void sort(void *base0
, size_t num
, size_t size
, struct fdisk_context
*cxt
,
551 int (*cmp_func
)(struct fdisk_context
*, const void *, const void *))
553 /* pre-scale counters for performance */
554 int i
= (num
/2 - 1) * size
;
555 size_t n
= num
* size
, c
, r
;
559 for ( ; i
>= 0; i
-= size
) {
560 for (r
= i
; r
* 2 + size
< n
; r
= c
) {
563 cmp_func(cxt
, base
+ c
, base
+ c
+ size
) < 0)
565 if (cmp_func(cxt
, base
+ r
, base
+ c
) >= 0)
567 generic_swap(base
+ r
, base
+ c
, size
);
572 for (i
= n
- size
; i
> 0; i
-= size
) {
573 generic_swap(base
, base
+ i
, size
);
574 for (r
= 0; r
* 2 + size
< (size_t) i
; r
= c
) {
577 cmp_func(cxt
, base
+ c
, base
+ c
+ size
) < 0)
579 if (cmp_func(cxt
, base
+ r
, base
+ c
) >= 0)
581 generic_swap(base
+ r
, base
+ c
, size
);
586 static int verify_disklabel(struct fdisk_context
*cxt
, int verbose
)
588 int Index
[SGI_MAXPARTITIONS
]; /* list of valid partitions */
589 int sortcount
= 0; /* number of used partitions, i.e. non-zero lengths */
590 int entire
= 0, i
= 0;
591 unsigned int start
= 0;
592 long long gap
= 0; /* count unused blocks */
593 unsigned int lastblock
= sgi_get_lastblock(cxt
);
597 assert(fdisk_is_disklabel(cxt
, SGI
));
600 memset(Index
, 0, sizeof(Index
));
602 for (i
=0; i
< SGI_MAXPARTITIONS
; i
++) {
603 if (sgi_get_num_sectors(cxt
, i
) != 0) {
604 Index
[sortcount
++] = i
;
605 if (sgi_get_sysid(cxt
, i
) == SGI_TYPE_ENTIRE_DISK
608 fdisk_info(cxt
, _("More than one entire "
609 "disk entry present."));
613 if (sortcount
== 0) {
615 fdisk_info(cxt
, _("No partitions defined"));
616 return (lastblock
> 0) ? 1 : (lastblock
== 0) ? 0 : -1;
619 sort(Index
, sortcount
, sizeof(Index
[0]), cxt
, compare_start
);
621 if (sgi_get_sysid(cxt
, Index
[0]) == SGI_TYPE_ENTIRE_DISK
) {
622 if (verbose
&& Index
[0] != 10)
623 fdisk_info(cxt
, _("IRIX likes when Partition 11 "
624 "covers the entire disk."));
626 if (verbose
&& sgi_get_start_sector(cxt
, Index
[0]) != 0)
627 fdisk_info(cxt
, _("The entire disk partition should "
628 "start at block 0, not at diskblock %d."),
629 sgi_get_start_sector(cxt
, Index
[0]));
631 if (verbose
&& sgi_get_num_sectors(cxt
, Index
[0]) != lastblock
)
633 "entire disk partition=%ds, but disk=%ds",
634 sgi_get_num_sectors(cxt
, Index
[0]),
636 lastblock
= sgi_get_num_sectors(cxt
, Index
[0]);
637 } else if (verbose
) {
638 fdisk_info(cxt
, _("Partition 11 should cover the entire disk."));
639 DBG(LABEL
, dbgprint("sysid=%d\tpartition=%d",
640 sgi_get_sysid(cxt
, Index
[0]), Index
[0]+1));
642 for (i
=1, start
=0; i
<sortcount
; i
++) {
643 int cylsize
= sgi_get_nsect(cxt
) * sgi_get_ntrks(cxt
);
645 if (verbose
&& cylsize
646 && (sgi_get_start_sector(cxt
, Index
[i
]) % cylsize
) != 0)
647 DBG(LABEL
, dbgprint("partition %d does not start on "
648 "cylinder boundary.", Index
[i
]+1));
650 if (verbose
&& cylsize
651 && sgi_get_num_sectors(cxt
, Index
[i
]) % cylsize
!= 0)
652 DBG(LABEL
, dbgprint("partition %d does not end on "
653 "cylinder boundary.", Index
[i
]+1));
655 /* We cannot handle several "entire disk" entries. */
656 if (sgi_get_sysid(cxt
, Index
[i
]) == SGI_TYPE_ENTIRE_DISK
)
659 if (start
> sgi_get_start_sector(cxt
, Index
[i
])) {
662 P_("Partitions %d and %d overlap by %d sector.",
663 "Partitions %d and %d overlap by %d sectors.",
664 start
- sgi_get_start_sector(cxt
, Index
[i
])),
665 Index
[i
-1]+1, Index
[i
]+1,
666 start
- sgi_get_start_sector(cxt
, Index
[i
]));
667 if (gap
> 0) gap
= -gap
;
668 if (gap
== 0) gap
= -1;
670 if (start
< sgi_get_start_sector(cxt
, Index
[i
])) {
673 P_("Unused gap of %8u sector: sector %8u",
674 "Unused gap of %8u sectors: sectors %8u-%u",
675 sgi_get_start_sector(cxt
, Index
[i
]) - start
),
676 sgi_get_start_sector(cxt
, Index
[i
]) - start
,
677 start
, sgi_get_start_sector(cxt
, Index
[i
])-1);
678 gap
+= sgi_get_start_sector(cxt
, Index
[i
]) - start
;
679 add_to_freelist(cxt
, start
,
680 sgi_get_start_sector(cxt
, Index
[i
]));
682 start
= sgi_get_start_sector(cxt
, Index
[i
])
683 + sgi_get_num_sectors(cxt
, Index
[i
]);
684 /* Align free space on cylinder boundary. */
685 if (cylsize
&& start
% cylsize
)
686 start
+= cylsize
- (start
% cylsize
);
688 DBG(LABEL
, dbgprint("%2d:%12d\t%12d\t%12d", Index
[i
],
689 sgi_get_start_sector(cxt
, Index
[i
]),
690 sgi_get_num_sectors(cxt
, Index
[i
]),
691 sgi_get_sysid(cxt
, Index
[i
])));
693 if (start
< lastblock
) {
695 fdisk_info(cxt
, P_("Unused gap of %8u sector: sector %8u",
696 "Unused gap of %8u sectors: sectors %8u-%u",
698 lastblock
- start
, start
, lastblock
-1);
699 gap
+= lastblock
- start
;
700 add_to_freelist(cxt
, start
, lastblock
);
703 * Done with arithmetics. Go for details now.
706 if (sgi_get_bootpartition(cxt
) < 0
707 || !sgi_get_num_sectors(cxt
, sgi_get_bootpartition(cxt
)))
708 fdisk_info(cxt
, _("The boot partition does not exist."));
710 if (sgi_get_swappartition(cxt
) < 0
711 || !sgi_get_num_sectors(cxt
, sgi_get_swappartition(cxt
)))
712 fdisk_info(cxt
, _("The swap partition does not exist."));
714 else if (sgi_get_sysid(cxt
, sgi_get_swappartition(cxt
)) != SGI_TYPE_SWAP
715 && sgi_get_sysid(cxt
, sgi_get_swappartition(cxt
)) != MBR_LINUX_SWAP_PARTITION
)
716 fdisk_info(cxt
, _("The swap partition has no swap type."));
718 if (sgi_check_bootfile(cxt
, "/unix"))
719 fdisk_info(cxt
, _("You have chosen an unusual boot "
723 return (gap
> 0) ? 1 : (gap
== 0) ? 0 : -1;
726 static int sgi_verify_disklabel(struct fdisk_context
*cxt
)
728 return verify_disklabel(cxt
, 1);
731 static int sgi_gaps(struct fdisk_context
*cxt
)
735 * = 0 : disk is properly filled to the rim
736 * < 0 : there is an overlap
737 * > 0 : there is still some vacant space
739 return verify_disklabel(cxt
, 0);
742 /* Returns partition index of first entry marked as entire disk. */
743 static int sgi_entire(struct fdisk_context
*cxt
)
747 for (i
= 0; i
< SGI_MAXPARTITIONS
; i
++)
748 if (sgi_get_sysid(cxt
, i
) == SGI_TYPE_ENTIRE_DISK
)
753 static int sgi_set_partition(struct fdisk_context
*cxt
, size_t i
,
754 unsigned int start
, unsigned int length
, int sys
)
756 struct sgi_disklabel
*sgilabel
;
760 assert(fdisk_is_disklabel(cxt
, SGI
));
762 sgilabel
= self_disklabel(cxt
);
763 sgilabel
->partitions
[i
].type
= cpu_to_be32(sys
);
764 sgilabel
->partitions
[i
].num_blocks
= cpu_to_be32(length
);
765 sgilabel
->partitions
[i
].first_block
= cpu_to_be32(start
);
767 fdisk_label_set_changed(cxt
->label
, 1);
769 if (sgi_gaps(cxt
) < 0) /* rebuild freelist */
770 fdisk_warnx(cxt
, _("Partition overlap on the disk."));
772 struct fdisk_parttype
*t
= fdisk_get_parttype_from_code(cxt
, sys
);
773 fdisk_info_new_partition(cxt
, i
+ 1, start
, start
+ length
, t
);
779 static void sgi_set_entire(struct fdisk_context
*cxt
)
783 for (n
= 10; n
< cxt
->label
->nparts_max
; n
++) {
784 if (!sgi_get_num_sectors(cxt
, n
)) {
785 sgi_set_partition(cxt
, n
, 0, sgi_get_lastblock(cxt
), SGI_TYPE_ENTIRE_DISK
);
791 static void sgi_set_volhdr(struct fdisk_context
*cxt
)
795 for (n
= 8; n
< cxt
->label
->nparts_max
; n
++) {
796 if (!sgi_get_num_sectors(cxt
, n
)) {
797 /* Choose same default volume header size as IRIX fx uses. */
798 if (4096 < sgi_get_lastblock(cxt
))
799 sgi_set_partition(cxt
, n
, 0, 4096, SGI_TYPE_VOLHDR
);
805 static int sgi_delete_partition(struct fdisk_context
*cxt
, size_t partnum
)
812 if (partnum
> cxt
->label
->nparts_max
)
815 rc
= sgi_set_partition(cxt
, partnum
, 0, 0, 0);
817 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
822 static int sgi_add_partition(struct fdisk_context
*cxt
,
824 struct fdisk_parttype
*t
)
826 struct fdisk_sgi_label
*sgi
;
828 unsigned int first
= 0, last
= 0;
829 struct fdisk_ask
*ask
;
830 int sys
= t
? t
->type
: SGI_TYPE_XFS
;
835 assert(fdisk_is_disklabel(cxt
, SGI
));
838 sys
= SGI_TYPE_ENTIRE_DISK
;
842 sgi
= self_label(cxt
);
844 if (sgi_get_num_sectors(cxt
, n
)) {
845 fdisk_warnx(cxt
, _("Partition %zd is already defined. Delete "
846 "it before re-adding it."), n
+ 1);
849 if (sgi_entire(cxt
) == -1 && sys
!= SGI_TYPE_ENTIRE_DISK
) {
850 fdisk_info(cxt
, _("Attempting to generate entire disk entry automatically."));
854 if (sgi_gaps(cxt
) == 0 && sys
!= SGI_TYPE_ENTIRE_DISK
) {
855 fdisk_warnx(cxt
, _("The entire disk is already covered with partitions."));
858 if (sgi_gaps(cxt
) < 0) {
859 fdisk_warnx(cxt
, _("You got a partition overlap on the disk. Fix it first!"));
863 snprintf(mesg
, sizeof(mesg
), _("First %s"),
864 fdisk_context_get_unit(cxt
, SINGULAR
));
866 ask
= fdisk_new_ask();
870 fdisk_ask_set_query(ask
, mesg
);
871 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_NUMBER
);
873 if (sys
== SGI_TYPE_ENTIRE_DISK
) {
874 last
= sgi_get_lastblock(cxt
);
875 fdisk_ask_number_set_low(ask
, 0); /* minimal */
876 fdisk_ask_number_set_default(ask
, 0); /* default */
877 fdisk_ask_number_set_high(ask
, last
- 1); /* maximal */
879 first
= sgi
->freelist
[0].first
;
880 last
= sgi
->freelist
[0].last
;
881 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
882 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, first
)); /* default */
883 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, last
) - 1); /* maximal */
885 rc
= fdisk_do_ask(cxt
, ask
);
886 first
= fdisk_ask_number_get_result(ask
);
892 if (first
&& sys
== SGI_TYPE_ENTIRE_DISK
)
893 fdisk_info(cxt
, _("It is highly recommended that "
894 "eleventh partition covers the entire "
895 "disk and is of type `SGI volume'"));
897 if (fdisk_context_use_cylinders(cxt
))
898 first
*= fdisk_context_get_units_per_sector(cxt
);
900 first = first; * align to cylinder if you know how ... */
902 last
= is_in_freelist(cxt
, first
);
904 fdisk_warnx(cxt
, _("You will get a partition overlap "
905 "on the disk. Fix it first!"));
910 snprintf(mesg
, sizeof(mesg
),
911 _("Last %s or +%s or +size{K,M,G,T,P}"),
912 fdisk_context_get_unit(cxt
, SINGULAR
),
913 fdisk_context_get_unit(cxt
, PLURAL
));
915 ask
= fdisk_new_ask();
919 fdisk_ask_set_query(ask
, mesg
);
920 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_OFFSET
);
922 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
923 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, last
) - 1);/* default */
924 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, last
) - 1);/* maximal */
925 fdisk_ask_number_set_base(ask
, fdisk_scround(cxt
, first
));
927 if (fdisk_context_use_cylinders(cxt
))
928 fdisk_ask_number_set_unit(ask
,
930 fdisk_context_get_units_per_sector(cxt
));
932 fdisk_ask_number_set_unit(ask
,cxt
->sector_size
);
934 rc
= fdisk_do_ask(cxt
, ask
);
935 last
= fdisk_ask_number_get_result(ask
) + 1;
941 if (fdisk_context_use_cylinders(cxt
))
942 last
*= fdisk_context_get_units_per_sector(cxt
);
944 if (sys
== SGI_TYPE_ENTIRE_DISK
945 && (first
!= 0 || last
!= sgi_get_lastblock(cxt
)))
946 fdisk_info(cxt
, _("It is highly recommended that eleventh "
947 "partition covers the entire disk and is of type "
950 sgi_set_partition(cxt
, n
, first
, last
- first
, sys
);
951 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
956 static int sgi_create_disklabel(struct fdisk_context
*cxt
)
958 struct fdisk_sgi_label
*sgi
;
959 struct sgi_disklabel
*sgilabel
;
963 assert(fdisk_is_disklabel(cxt
, SGI
));
966 if (cxt
->geom
.heads
&& cxt
->geom
.sectors
) {
969 if (blkdev_get_sectors(cxt
->dev_fd
, &llsectors
) == 0) {
970 /* the get device size ioctl was successful */
972 int sec_fac
= cxt
->sector_size
/ 512;
974 llcyls
= llsectors
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
* sec_fac
);
975 cxt
->geom
.cylinders
= llcyls
;
976 if (cxt
->geom
.cylinders
!= llcyls
) /* truncated? */
977 cxt
->geom
.cylinders
= ~0;
979 /* otherwise print error and use truncated version */
981 _("Warning: BLKGETSIZE ioctl failed on %s. "
982 "Using geometry cylinder value of %llu. "
983 "This value may be truncated for devices "
984 "> 33.8 GB."), cxt
->dev_path
, cxt
->geom
.cylinders
);
988 fdisk_zeroize_firstsector(cxt
);
989 sgi
= (struct fdisk_sgi_label
*) cxt
->label
;
990 sgi
->header
= (struct sgi_disklabel
*) cxt
->firstsector
;
992 sgilabel
= sgi
->header
;
994 sgilabel
->magic
= cpu_to_be32(SGI_LABEL_MAGIC
);
995 sgilabel
->root_part_num
= cpu_to_be16(0);
996 sgilabel
->swap_part_num
= cpu_to_be16(1);
998 /* sizeof(sgilabel->boot_file) = 16 > 6 */
999 memset(sgilabel
->boot_file
, 0, 16);
1000 strcpy((char *) sgilabel
->boot_file
, "/unix");
1002 sgilabel
->devparam
.skew
= (0);
1003 sgilabel
->devparam
.gap1
= (0);
1004 sgilabel
->devparam
.gap2
= (0);
1005 sgilabel
->devparam
.sparecyl
= (0);
1006 sgilabel
->devparam
.pcylcount
= cpu_to_be16(cxt
->geom
.cylinders
);
1007 sgilabel
->devparam
.head_vol0
= cpu_to_be16(0);
1008 sgilabel
->devparam
.ntrks
= cpu_to_be16(cxt
->geom
.heads
);
1009 /* tracks/cylinder (heads) */
1010 sgilabel
->devparam
.cmd_tag_queue_depth
= (0);
1011 sgilabel
->devparam
.unused0
= (0);
1012 sgilabel
->devparam
.unused1
= cpu_to_be16(0);
1013 sgilabel
->devparam
.nsect
= cpu_to_be16(cxt
->geom
.sectors
);
1015 sgilabel
->devparam
.bytes
= cpu_to_be16(cxt
->sector_size
);
1016 sgilabel
->devparam
.ilfact
= cpu_to_be16(1);
1017 sgilabel
->devparam
.flags
= cpu_to_be32(
1018 SGI_DEVPARAM_TRACK_FWD
1019 | SGI_DEVPARAM_IGNORE_ERRORS
1020 | SGI_DEVPARAM_RESEEK
);
1021 sgilabel
->devparam
.datarate
= cpu_to_be32(0);
1022 sgilabel
->devparam
.retries_on_error
= cpu_to_be32(1);
1023 sgilabel
->devparam
.ms_per_word
= cpu_to_be32(0);
1024 sgilabel
->devparam
.xylogics_gap1
= cpu_to_be16(0);
1025 sgilabel
->devparam
.xylogics_syncdelay
= cpu_to_be16(0);
1026 sgilabel
->devparam
.xylogics_readdelay
= cpu_to_be16(0);
1027 sgilabel
->devparam
.xylogics_gap2
= cpu_to_be16(0);
1028 sgilabel
->devparam
.xylogics_readgate
= cpu_to_be16(0);
1029 sgilabel
->devparam
.xylogics_writecont
= cpu_to_be16(0);
1031 memset(&(sgilabel
->volume
), 0,
1032 sizeof(struct sgi_volume
) * SGI_MAXVOLUMES
);
1033 memset(&(sgilabel
->partitions
), 0,
1034 sizeof(struct sgi_partition
) * SGI_MAXPARTITIONS
);
1035 cxt
->label
->nparts_max
= SGI_MAXPARTITIONS
;
1036 sgi_set_entire(cxt
);
1037 sgi_set_volhdr(cxt
);
1039 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
1041 fdisk_sinfo(cxt
, FDISK_INFO_SUCCESS
,
1042 _("Created a new SGI disklabel."));
1046 static struct fdisk_parttype
*sgi_get_parttype(struct fdisk_context
*cxt
, size_t n
)
1048 struct fdisk_parttype
*t
;
1050 if (n
>= cxt
->label
->nparts_max
)
1053 t
= fdisk_get_parttype_from_code(cxt
, sgi_get_sysid(cxt
, n
));
1055 t
= fdisk_new_unknown_parttype(sgi_get_sysid(cxt
, n
), NULL
);
1059 static int sgi_set_parttype(struct fdisk_context
*cxt
,
1061 struct fdisk_parttype
*t
)
1063 struct sgi_disklabel
*sgilabel
;
1065 if (i
>= cxt
->label
->nparts_max
|| !t
|| t
->type
> UINT32_MAX
)
1068 if (sgi_get_num_sectors(cxt
, i
) == 0) /* caught already before, ... */ {
1069 fdisk_warnx(cxt
, _("Sorry, only for non-empty partitions you can change the tag."));
1073 if ((i
== 10 && t
->type
!= SGI_TYPE_ENTIRE_DISK
)
1074 || (i
== 8 && t
->type
!= 0))
1075 fdisk_info(cxt
, _("Consider leaving partition 9 as volume header (0), "
1076 "and partition 11 as entire volume (6), as IRIX "
1079 if (((t
->type
!= SGI_TYPE_ENTIRE_DISK
) && (t
->type
!= SGI_TYPE_VOLHDR
))
1080 && (sgi_get_start_sector(cxt
, i
) < 1)) {
1082 fdisk_ask_yesno(cxt
,
1083 _("It is highly recommended that the partition at offset 0 "
1084 "is of type \"SGI volhdr\", the IRIX system will rely on it to "
1085 "retrieve from its directory standalone tools like sash and fx. "
1086 "Only the \"SGI volume\" entire disk section may violate this. "
1087 "Are you sure about tagging this partition differently?"), &yes
);
1092 sgilabel
= self_disklabel(cxt
);
1093 sgilabel
->partitions
[i
].type
= cpu_to_be32(t
->type
);
1098 static int sgi_get_partition_status(
1099 struct fdisk_context
*cxt
,
1104 assert(fdisk_is_disklabel(cxt
, SGI
));
1106 if (!status
|| i
>= cxt
->label
->nparts_max
)
1109 *status
= FDISK_PARTSTAT_NONE
;
1111 if (sgi_get_num_sectors(cxt
, i
))
1112 *status
= FDISK_PARTSTAT_USED
;
1117 static int sgi_toggle_partition_flag(struct fdisk_context
*cxt
, size_t i
, unsigned long flag
)
1119 struct sgi_disklabel
*sgilabel
;
1122 assert(fdisk_is_disklabel(cxt
, SGI
));
1124 if (i
>= cxt
->label
->nparts_max
)
1127 sgilabel
= self_disklabel(cxt
);
1131 sgilabel
->root_part_num
=
1132 be16_to_cpu(sgilabel
->root_part_num
) == i
?
1134 fdisk_label_set_changed(cxt
->label
, 1);
1137 sgilabel
->swap_part_num
=
1138 be16_to_cpu(sgilabel
->swap_part_num
) == i
?
1140 fdisk_label_set_changed(cxt
->label
, 1);
1149 static const struct fdisk_label_operations sgi_operations
=
1151 .probe
= sgi_probe_label
,
1152 .write
= sgi_write_disklabel
,
1153 .verify
= sgi_verify_disklabel
,
1154 .create
= sgi_create_disklabel
,
1155 .list
= sgi_list_table
,
1156 .part_add
= sgi_add_partition
,
1157 .part_delete
= sgi_delete_partition
,
1158 .part_get_type
= sgi_get_parttype
,
1159 .part_set_type
= sgi_set_parttype
,
1161 .part_get_status
= sgi_get_partition_status
,
1162 .part_toggle_flag
= sgi_toggle_partition_flag
1165 /* Allocates an SGI label driver. */
1166 struct fdisk_label
*fdisk_new_sgi_label(struct fdisk_context
*cxt
)
1168 struct fdisk_label
*lb
;
1169 struct fdisk_sgi_label
*sgi
;
1173 sgi
= calloc(1, sizeof(*sgi
));
1177 /* initialize generic part of the driver */
1178 lb
= (struct fdisk_label
*) sgi
;
1180 lb
->id
= FDISK_DISKLABEL_SGI
;
1181 lb
->op
= &sgi_operations
;
1182 lb
->parttypes
= sgi_parttypes
;
1183 lb
->nparttypes
= ARRAY_SIZE(sgi_parttypes
);
1185 lb
->flags
|= FDISK_LABEL_FL_REQUIRE_GEOMETRY
;