1 /*
2 *
3 * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org>
4 * 2013 Karel Zak <kzak@redhat.com>
5 *
6 * This is a re-written version for libfdisk, the original was fdisksgilabel.c
7 * from util-linux fdisk, by:
8 *
9 * Andreas Neuper, Sep 1998,
10 * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, Mar 1999,
11 * Phillip Kesling <pkesling@sgi.com>, Mar 2003.
12 */
13
14 #include "c.h"
15 #include "all-io.h"
16
17 #include "blkdev.h"
18
19 #include "bitops.h"
20 #include "pt-sgi.h"
21 #include "pt-mbr.h"
22 #include "fdiskP.h"
23
24 /**
25 * SECTION: sgi
26 * @title: SGI
27 * @short_description: disk label specific functions
28 *
29 */
30
31 /*
32 * in-memory fdisk SGI stuff
33 */
34 struct fdisk_sgi_label {
35 struct fdisk_label head; /* generic fdisk part */
36 struct sgi_disklabel *header; /* on-disk data (pointer to cxt->firstsector) */
37
38 struct sgi_freeblocks {
39 unsigned int first;
40 unsigned int last;
41 } freelist[SGI_MAXPARTITIONS + 1];
42 };
43
44 static struct fdisk_parttype sgi_parttypes[] =
45 {
46 {SGI_TYPE_VOLHDR, N_("SGI volhdr")},
47 {SGI_TYPE_TRKREPL, N_("SGI trkrepl")},
48 {SGI_TYPE_SECREPL, N_("SGI secrepl")},
49 {SGI_TYPE_SWAP, N_("SGI raw")},
50 {SGI_TYPE_BSD, N_("SGI bsd")},
51 {SGI_TYPE_SYSV, N_("SGI sysv")},
52 {SGI_TYPE_ENTIRE_DISK, N_("SGI volume")},
53 {SGI_TYPE_EFS, N_("SGI efs")},
54 {SGI_TYPE_LVOL, N_("SGI lvol")},
55 {SGI_TYPE_RLVOL, N_("SGI rlvol")},
56 {SGI_TYPE_XFS, N_("SGI xfs")},
57 {SGI_TYPE_XFSLOG, N_("SGI xfslog")},
58 {SGI_TYPE_XLV, N_("SGI xlv")},
59 {SGI_TYPE_XVM, N_("SGI xvm")},
60 {MBR_LINUX_SWAP_PARTITION, N_("Linux swap")},
61 {MBR_LINUX_DATA_PARTITION, N_("Linux native")},
62 {MBR_LINUX_LVM_PARTITION, N_("Linux LVM")},
63 {MBR_LINUX_RAID_PARTITION, N_("Linux RAID")},
64 {0, NULL }
65 };
66
67 static unsigned int sgi_get_start_sector(struct fdisk_context *cxt, int i );
68 static unsigned int sgi_get_num_sectors(struct fdisk_context *cxt, int i );
69 static int sgi_get_bootpartition(struct fdisk_context *cxt);
70 static int sgi_get_swappartition(struct fdisk_context *cxt);
71
72 /* Returns a pointer buffer with on-disk data. */
self_disklabel(struct fdisk_context * cxt)73 static inline struct sgi_disklabel *self_disklabel(struct fdisk_context *cxt)
74 {
75 assert(cxt);
76 assert(cxt->label);
77 assert(fdisk_is_label(cxt, SGI));
78
79 return ((struct fdisk_sgi_label *) cxt->label)->header;
80 }
81
82 /* Returns in-memory fdisk data. */
self_label(struct fdisk_context * cxt)83 static inline struct fdisk_sgi_label *self_label(struct fdisk_context *cxt)
84 {
85 assert(cxt);
86 assert(cxt->label);
87 assert(fdisk_is_label(cxt, SGI));
88
89 return (struct fdisk_sgi_label *) cxt->label;
90 }
91
92 /*
93 * Information within second on-disk block
94 */
95 #define SGI_INFO_MAGIC 0x00072959
96
97 struct sgi_info {
98 unsigned int magic; /* looks like a magic number */
99 unsigned int a2;
100 unsigned int a3;
101 unsigned int a4;
102 unsigned int b1;
103 unsigned short b2;
104 unsigned short b3;
105 unsigned int c[16];
106 unsigned short d[3];
107 unsigned char scsi_string[50];
108 unsigned char serial[137];
109 unsigned short check1816;
110 unsigned char installer[225];
111 };
112
sgi_new_info(void)113 static struct sgi_info *sgi_new_info(void)
114 {
115 struct sgi_info *info = calloc(1, sizeof(struct sgi_info));
116
117 if (!info)
118 return NULL;
119
120 info->magic = cpu_to_be32(SGI_INFO_MAGIC);
121 info->b1 = cpu_to_be32(-1);
122 info->b2 = cpu_to_be16(-1);
123 info->b3 = cpu_to_be16(1);
124
125 /* You may want to replace this string !!!!!!! */
126 strcpy((char *) info->scsi_string, "IBM OEM 0662S12 3 30");
127 strcpy((char *) info->serial, "0000");
128 info->check1816 = cpu_to_be16(18 * 256 + 16);
129 strcpy((char *) info->installer, "Sfx version 5.3, Oct 18, 1994");
130
131 return info;
132 }
133
sgi_free_info(struct sgi_info * info)134 static void sgi_free_info(struct sgi_info *info)
135 {
136 free(info);
137 }
138
139 /**
140 * fdisk_sgi_create_info:
141 * @cxt: context
142 *
143 * This function add hint about SGI label (e.g. set "sgilabel" as volume name)
144 * to the first SGI volume. This is probably old SGI convention without any
145 * effect to the device partitioning.
146 *
147 * Returns: 0 on success, <0 on error
148 */
fdisk_sgi_create_info(struct fdisk_context * cxt)149 int fdisk_sgi_create_info(struct fdisk_context *cxt)
150 {
151 struct sgi_disklabel *sgilabel = self_disklabel(cxt);
152
153 /* I keep SGI's habit to write the sgilabel to the second block */
154 sgilabel->volume[0].block_num = cpu_to_be32(2);
155 sgilabel->volume[0].num_bytes = cpu_to_be32(sizeof(struct sgi_info));
156 memcpy((char *) sgilabel->volume[0].name, "sgilabel", 8);
157
158 fdisk_info(cxt, _("SGI info created on second sector."));
159 return 0;
160 }
161
162
163 /*
164 * only dealing with free blocks here
165 */
set_freelist(struct fdisk_context * cxt,size_t i,unsigned int f,unsigned int l)166 static void set_freelist(struct fdisk_context *cxt,
167 size_t i, unsigned int f, unsigned int l)
168 {
169 struct fdisk_sgi_label *sgi = self_label(cxt);
170
171 if (i < ARRAY_SIZE(sgi->freelist)) {
172 sgi->freelist[i].first = f;
173 sgi->freelist[i].last = l;
174 }
175 }
176
add_to_freelist(struct fdisk_context * cxt,unsigned int f,unsigned int l)177 static void add_to_freelist(struct fdisk_context *cxt,
178 unsigned int f, unsigned int l)
179 {
180 struct fdisk_sgi_label *sgi = self_label(cxt);
181 size_t i;
182
183 for (i = 0; i < ARRAY_SIZE(sgi->freelist); i++) {
184 if (sgi->freelist[i].last == 0)
185 break;
186 }
187 set_freelist(cxt, i, f, l);
188 }
189
clear_freelist(struct fdisk_context * cxt)190 static void clear_freelist(struct fdisk_context *cxt)
191 {
192 struct fdisk_sgi_label *sgi = self_label(cxt);
193
194 memset(sgi->freelist, 0, sizeof(sgi->freelist));
195 }
196
is_in_freelist(struct fdisk_context * cxt,unsigned int b)197 static unsigned int is_in_freelist(struct fdisk_context *cxt, unsigned int b)
198 {
199 struct fdisk_sgi_label *sgi = self_label(cxt);
200 size_t i;
201
202 for (i = 0; i < ARRAY_SIZE(sgi->freelist); i++) {
203 if (sgi->freelist[i].first <= b
204 && sgi->freelist[i].last >= b)
205 return sgi->freelist[i].last;
206 }
207
208 return 0;
209 }
210
211
sgi_get_nsect(struct fdisk_context * cxt)212 static int sgi_get_nsect(struct fdisk_context *cxt)
213 {
214 struct sgi_disklabel *sgilabel = self_disklabel(cxt);
215 return be16_to_cpu(sgilabel->devparam.nsect);
216 }
217
sgi_get_ntrks(struct fdisk_context * cxt)218 static int sgi_get_ntrks(struct fdisk_context *cxt)
219 {
220 struct sgi_disklabel *sgilabel = self_disklabel(cxt);
221 return be16_to_cpu(sgilabel->devparam.ntrks);
222 }
223
count_used_partitions(struct fdisk_context * cxt)224 static size_t count_used_partitions(struct fdisk_context *cxt)
225 {
226 size_t i, ct = 0;
227
228 for (i = 0; i < cxt->label->nparts_max; i++)
229 ct += sgi_get_num_sectors(cxt, i) > 0;
230
231 return ct;
232 }
233
sgi_probe_label(struct fdisk_context * cxt)234 static int sgi_probe_label(struct fdisk_context *cxt)
235 {
236 struct fdisk_sgi_label *sgi;
237 struct sgi_disklabel *sgilabel;
238
239 assert(cxt);
240 assert(cxt->label);
241 assert(fdisk_is_label(cxt, SGI));
242 assert(sizeof(struct sgi_disklabel) <= 512);
243
244 /* map first sector to header */
245 sgi = (struct fdisk_sgi_label *) cxt->label;
246 sgi->header = (struct sgi_disklabel *) cxt->firstsector;
247 sgilabel = sgi->header;
248
249 if (be32_to_cpu(sgilabel->magic) != SGI_LABEL_MAGIC) {
250 sgi->header = NULL;
251 return 0;
252 }
253
254 /*
255 * test for correct checksum
256 */
257 if (sgi_pt_checksum(sgilabel) != 0)
258 fdisk_warnx(cxt, _("Detected an SGI disklabel with wrong checksum."));
259
260 clear_freelist(cxt);
261 cxt->label->nparts_max = SGI_MAXPARTITIONS;
262 cxt->label->nparts_cur = count_used_partitions(cxt);
263 return 1;
264 }
265
sgi_get_disklabel_item(struct fdisk_context * cxt,struct fdisk_labelitem * item)266 static int sgi_get_disklabel_item(struct fdisk_context *cxt, struct fdisk_labelitem *item)
267 {
268 struct sgi_disklabel *sgilabel;
269 struct sgi_device_parameter *sgiparam;
270 int rc = 0;
271
272 assert(cxt);
273 assert(cxt->label);
274 assert(fdisk_is_label(cxt, SGI));
275
276 sgilabel = self_disklabel(cxt);
277 sgiparam = &sgilabel->devparam;
278
279 switch (item->id) {
280 case SGI_LABELITEM_PCYLCOUNT:
281 item->name = _("Physical cylinders");
282 item->type = 'j';
283 item->data.num64 = (uint64_t) be16_to_cpu(sgiparam->pcylcount);
284 break;
285 case SGI_LABELITEM_SPARECYL:
286 item->name = _("Extra sects/cyl");
287 item->type = 'j';
288 item->data.num64 = (uint64_t) sgiparam->sparecyl;
289 break;
290 case SGI_LABELITEM_ILFACT:
291 item->name = _("Interleave");
292 item->type = 'j';
293 item->data.num64 = (uint64_t) be16_to_cpu(sgiparam->ilfact);
294 break;
295 case SGI_LABELITEM_BOOTFILE:
296 item->name = _("Bootfile");
297 item->type = 's';
298 item->data.str = *sgilabel->boot_file ? strdup((char *) sgilabel->boot_file) : NULL;
299 break;
300 default:
301 if (item->id < __FDISK_NLABELITEMS)
302 rc = 1; /* unsupported generic item */
303 else
304 rc = 2; /* out of range */
305 break;
306 }
307
308 return rc;
309 }
310
sgi_get_start_sector(struct fdisk_context * cxt,int i)311 static unsigned int sgi_get_start_sector(struct fdisk_context *cxt, int i)
312 {
313 struct sgi_disklabel *sgilabel = self_disklabel(cxt);
314 return be32_to_cpu(sgilabel->partitions[i].first_block);
315 }
316
sgi_get_num_sectors(struct fdisk_context * cxt,int i)317 static unsigned int sgi_get_num_sectors(struct fdisk_context *cxt, int i)
318 {
319 struct sgi_disklabel *sgilabel = self_disklabel(cxt);
320 return be32_to_cpu(sgilabel->partitions[i].num_blocks);
321 }
322
sgi_get_sysid(struct fdisk_context * cxt,int i)323 static int sgi_get_sysid(struct fdisk_context *cxt, int i)
324 {
325 struct sgi_disklabel *sgilabel = self_disklabel(cxt);
326 return be32_to_cpu(sgilabel->partitions[i].type);
327 }
328
sgi_get_bootpartition(struct fdisk_context * cxt)329 static int sgi_get_bootpartition(struct fdisk_context *cxt)
330 {
331 struct sgi_disklabel *sgilabel = self_disklabel(cxt);
332 return be16_to_cpu(sgilabel->root_part_num);
333 }
334
sgi_get_swappartition(struct fdisk_context * cxt)335 static int sgi_get_swappartition(struct fdisk_context *cxt)
336 {
337 struct sgi_disklabel *sgilabel = self_disklabel(cxt);
338 return be16_to_cpu(sgilabel->swap_part_num);
339 }
340
sgi_get_lastblock(struct fdisk_context * cxt)341 static unsigned int sgi_get_lastblock(struct fdisk_context *cxt)
342 {
343 return cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders;
344 }
345
sgi_get_parttype(struct fdisk_context * cxt,size_t n)346 static struct fdisk_parttype *sgi_get_parttype(struct fdisk_context *cxt, size_t n)
347 {
348 struct fdisk_parttype *t;
349
350 if (n >= cxt->label->nparts_max)
351 return NULL;
352
353 t = fdisk_label_get_parttype_from_code(cxt->label, sgi_get_sysid(cxt, n));
354 return t ? : fdisk_new_unknown_parttype(sgi_get_sysid(cxt, n), NULL);
355 }
356
357 /* fdisk_get_partition() backend */
sgi_get_partition(struct fdisk_context * cxt,size_t n,struct fdisk_partition * pa)358 static int sgi_get_partition(struct fdisk_context *cxt, size_t n, struct fdisk_partition *pa)
359 {
360 fdisk_sector_t start, len;
361
362 pa->used = sgi_get_num_sectors(cxt, n) > 0;
363 if (!pa->used)
364 return 0;
365
366 start = sgi_get_start_sector(cxt, n);
367 len = sgi_get_num_sectors(cxt, n);
368
369 pa->type = sgi_get_parttype(cxt, n);
370 pa->size = len;
371 pa->start = start;
372
373 if (pa->type && pa->type->code == SGI_TYPE_ENTIRE_DISK)
374 pa->wholedisk = 1;
375
376 pa->attrs = sgi_get_swappartition(cxt) == (int) n ? "swap" :
377 sgi_get_bootpartition(cxt) == (int) n ? "boot" : NULL;
378 if (pa->attrs)
379 pa->attrs = strdup(pa->attrs);
380
381 return 0;
382 }
383
384
sgi_check_bootfile(struct fdisk_context * cxt,const char * name)385 static int sgi_check_bootfile(struct fdisk_context *cxt, const char *name)
386 {
387 size_t sz;
388 struct sgi_disklabel *sgilabel = self_disklabel(cxt);
389
390 sz = strlen(name);
391
392 if (sz < 3) {
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\"."));
397 return -EINVAL;
398
399 }
400
401 if (sz > sizeof(sgilabel->boot_file)) {
402 fdisk_warnx(cxt, P_("Name of bootfile is too long: %zu byte maximum.",
403 "Name of bootfile is too long: %zu bytes maximum.",
404 sizeof(sgilabel->boot_file)),
405 sizeof(sgilabel->boot_file));
406 return -EINVAL;
407
408 }
409
410 if (*name != '/') {
411 fdisk_warnx(cxt, _("Bootfile must have a fully qualified pathname."));
412 return -EINVAL;
413 }
414
415 if (strncmp(name, (char *) sgilabel->boot_file,
416 sizeof(sgilabel->boot_file)) != 0) {
417 fdisk_warnx(cxt, _("Be aware that the bootfile is not checked "
418 "for existence. SGI's default is \"/unix\", "
419 "and for backup \"/unix.save\"."));
420 return 0; /* filename is correct and did change */
421 }
422
423 return 1; /* filename did not change */
424 }
425
426 /**
427 * fdisk_sgi_set_bootfile:
428 * @cxt: context
429 *
430 * Allows to set SGI boot file. The function uses Ask API for dialog with
431 * user.
432 *
433 * Returns: 0 on success, <0 on error
434 */
fdisk_sgi_set_bootfile(struct fdisk_context * cxt)435 int fdisk_sgi_set_bootfile(struct fdisk_context *cxt)
436 {
437 int rc = 0;
438 size_t sz;
439 char *name = NULL;
440 struct sgi_disklabel *sgilabel = self_disklabel(cxt);
441
442 fdisk_info(cxt, _("The current boot file is: %s"), sgilabel->boot_file);
443
444 rc = fdisk_ask_string(cxt, _("Enter of the new boot file"), &name);
445 if (rc == 0)
446 rc = sgi_check_bootfile(cxt, name);
447 if (rc) {
448 if (rc == 1)
449 fdisk_info(cxt, _("Boot file is unchanged."));
450 goto done;
451 }
452
453 memset(sgilabel->boot_file, 0, sizeof(sgilabel->boot_file));
454 sz = strlen(name);
455
456 assert(sz <= sizeof(sgilabel->boot_file)); /* see sgi_check_bootfile() */
457
458 memcpy(sgilabel->boot_file, name, sz);
459
460 fdisk_info(cxt, _("Bootfile has been changed to \"%s\"."), name);
461 done:
462 free(name);
463 return rc;
464 }
465
sgi_write_disklabel(struct fdisk_context * cxt)466 static int sgi_write_disklabel(struct fdisk_context *cxt)
467 {
468 struct sgi_disklabel *sgilabel;
469 struct sgi_info *info = NULL;
470
471 assert(cxt);
472 assert(cxt->label);
473 assert(fdisk_is_label(cxt, SGI));
474
475 sgilabel = self_disklabel(cxt);
476 sgilabel->csum = 0;
477 sgilabel->csum = cpu_to_be32(sgi_pt_checksum(sgilabel));
478
479 assert(sgi_pt_checksum(sgilabel) == 0);
480
481 if (lseek(cxt->dev_fd, 0, SEEK_SET) < 0)
482 goto err;
483 if (write_all(cxt->dev_fd, sgilabel, DEFAULT_SECTOR_SIZE))
484 goto err;
485 if (!strncmp((char *) sgilabel->volume[0].name, "sgilabel", 8)) {
486 /*
487 * Keep this habit of first writing the "sgilabel".
488 * I never tested whether it works without. (AN 1998-10-02)
489 */
490 int infostartblock
491 = be32_to_cpu(sgilabel->volume[0].block_num);
492
493 if (lseek(cxt->dev_fd, (off_t) infostartblock *
494 DEFAULT_SECTOR_SIZE, SEEK_SET) < 0)
495 goto err;
496 info = sgi_new_info();
497 if (!info)
498 goto err;
499 if (write_all(cxt->dev_fd, info, sizeof(*info)))
500 goto err;
501 }
502
503 sgi_free_info(info);
504 return 0;
505 err:
506 sgi_free_info(info);
507 return -errno;
508 }
509
compare_start(struct fdisk_context * cxt,const void * x,const void * y)510 static int compare_start(struct fdisk_context *cxt,
511 const void *x, const void *y)
512 {
513 /*
514 * Sort according to start sectors and prefer the largest partition:
515 * entry zero is the entire-disk entry.
516 */
517 const unsigned int i = *(const int *) x;
518 const unsigned int j = *(const int *) y;
519 unsigned int a = sgi_get_start_sector(cxt, i);
520 unsigned int b = sgi_get_start_sector(cxt, j);
521 unsigned int c = sgi_get_num_sectors(cxt, i);
522 unsigned int d = sgi_get_num_sectors(cxt, j);
523
524 if (a == b)
525 return (d > c) ? 1 : (d == c) ? 0 : -1;
526 return (a > b) ? 1 : -1;
527 }
528
generic_swap(void * a0,void * b0,int size)529 static void generic_swap(void *a0, void *b0, int size)
530 {
531 char *a = a0, *b = b0;
532
533 for (; size > 0; --size, a++, b++) {
534 char t = *a;
535 *a = *b;
536 *b = t;
537 }
538 }
539
540
541 /* heap sort, based on Matt Mackall's linux kernel version */
sort(void * base0,size_t num,size_t size,struct fdisk_context * cxt,int (* cmp_func)(struct fdisk_context *,const void *,const void *))542 static void sort(void *base0, size_t num, size_t size, struct fdisk_context *cxt,
543 int (*cmp_func)(struct fdisk_context *, const void *, const void *))
544 {
545 /* pre-scale counters for performance */
546 int i = (num/2 - 1) * size;
547 size_t n = num * size, c, r;
548 char *base = base0;
549
550 /* heapify */
551 for ( ; i >= 0; i -= size) {
552 for (r = i; r * 2 + size < n; r = c) {
553 c = r * 2 + size;
554 if (c < n - size &&
555 cmp_func(cxt, base + c, base + c + size) < 0)
556 c += size;
557 if (cmp_func(cxt, base + r, base + c) >= 0)
558 break;
559 generic_swap(base + r, base + c, size);
560 }
561 }
562
563 /* sort */
564 for (i = n - size; i > 0; i -= size) {
565 generic_swap(base, base + i, size);
566 for (r = 0; r * 2 + size < (size_t) i; r = c) {
567 c = r * 2 + size;
568 if (c < i - size &&
569 cmp_func(cxt, base + c, base + c + size) < 0)
570 c += size;
571 if (cmp_func(cxt, base + r, base + c) >= 0)
572 break;
573 generic_swap(base + r, base + c, size);
574 }
575 }
576 }
577
verify_disklabel(struct fdisk_context * cxt,int verbose)578 static int verify_disklabel(struct fdisk_context *cxt, int verbose)
579 {
580 int Index[SGI_MAXPARTITIONS]; /* list of valid partitions */
581 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
582 int entire = 0, i = 0;
583 unsigned int start = 0;
584 long long gap = 0; /* count unused blocks */
585 unsigned int lastblock = sgi_get_lastblock(cxt);
586
587 assert(cxt);
588 assert(cxt->label);
589 assert(fdisk_is_label(cxt, SGI));
590
591 clear_freelist(cxt);
592 memset(Index, 0, sizeof(Index));
593
594 for (i=0; i < SGI_MAXPARTITIONS; i++) {
595 if (sgi_get_num_sectors(cxt, i) != 0) {
596 Index[sortcount++] = i;
597 if (sgi_get_sysid(cxt, i) == SGI_TYPE_ENTIRE_DISK
598 && entire++ == 1 && verbose) {
599 fdisk_info(cxt, _("More than one entire "
600 "disk entry present."));
601 }
602 }
603 }
604 if (sortcount == 0) {
605 if (verbose)
606 fdisk_info(cxt, _("No partitions defined."));
607 if (lastblock)
608 add_to_freelist(cxt, 0, lastblock);
609 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
610 }
611
612 sort(Index, sortcount, sizeof(Index[0]), cxt, compare_start);
613
614 if (sgi_get_sysid(cxt, Index[0]) == SGI_TYPE_ENTIRE_DISK) {
615 if (verbose && Index[0] != 10)
616 fdisk_info(cxt, _("IRIX likes it when partition 11 "
617 "covers the entire disk."));
618
619 if (verbose && sgi_get_start_sector(cxt, Index[0]) != 0)
620 fdisk_info(cxt, _("The entire disk partition should "
621 "start at block 0, not at block %d."),
622 sgi_get_start_sector(cxt, Index[0]));
623
624 if (verbose && sgi_get_num_sectors(cxt, Index[0]) != lastblock)
625 DBG(LABEL, ul_debug(
626 "entire disk partition=%ds, but disk=%ds",
627 sgi_get_num_sectors(cxt, Index[0]),
628 lastblock));
629 lastblock = sgi_get_num_sectors(cxt, Index[0]);
630 } else if (verbose) {
631 fdisk_info(cxt, _("Partition 11 should cover the entire disk."));
632 DBG(LABEL, ul_debug("sysid=%d\tpartition=%d",
633 sgi_get_sysid(cxt, Index[0]), Index[0]+1));
634 }
635 for (i=1, start=0; i<sortcount; i++) {
636 int cylsize = sgi_get_nsect(cxt) * sgi_get_ntrks(cxt);
637
638 if (verbose && cylsize
639 && (sgi_get_start_sector(cxt, Index[i]) % cylsize) != 0)
640 DBG(LABEL, ul_debug("partition %d does not start on "
641 "cylinder boundary.", Index[i]+1));
642
643 if (verbose && cylsize
644 && sgi_get_num_sectors(cxt, Index[i]) % cylsize != 0)
645 DBG(LABEL, ul_debug("partition %d does not end on "
646 "cylinder boundary.", Index[i]+1));
647
648 /* We cannot handle several "entire disk" entries. */
649 if (sgi_get_sysid(cxt, Index[i]) == SGI_TYPE_ENTIRE_DISK)
650 continue;
651
652 if (start > sgi_get_start_sector(cxt, Index[i])) {
653 if (verbose)
654 fdisk_info(cxt,
655 P_("Partitions %d and %d overlap by %d sector.",
656 "Partitions %d and %d overlap by %d sectors.",
657 start - sgi_get_start_sector(cxt, Index[i])),
658 Index[i-1]+1, Index[i]+1,
659 start - sgi_get_start_sector(cxt, Index[i]));
660 if (gap > 0) gap = -gap;
661 if (gap == 0) gap = -1;
662 }
663 if (start < sgi_get_start_sector(cxt, Index[i])) {
664 if (verbose)
665 fdisk_info(cxt,
666 P_("Unused gap of %8u sector: sector %8u",
667 "Unused gap of %8u sectors: sectors %8u-%u",
668 sgi_get_start_sector(cxt, Index[i]) - start),
669 sgi_get_start_sector(cxt, Index[i]) - start,
670 start, sgi_get_start_sector(cxt, Index[i])-1);
671 gap += sgi_get_start_sector(cxt, Index[i]) - start;
672 add_to_freelist(cxt, start,
673 sgi_get_start_sector(cxt, Index[i]));
674 }
675 start = sgi_get_start_sector(cxt, Index[i])
676 + sgi_get_num_sectors(cxt, Index[i]);
677 /* Align free space on cylinder boundary. */
678 if (cylsize && start % cylsize)
679 start += cylsize - (start % cylsize);
680
681 DBG(LABEL, ul_debug("%2d:%12d\t%12d\t%12d", Index[i],
682 sgi_get_start_sector(cxt, Index[i]),
683 sgi_get_num_sectors(cxt, Index[i]),
684 sgi_get_sysid(cxt, Index[i])));
685 }
686 if (start < lastblock) {
687 if (verbose)
688 fdisk_info(cxt, P_("Unused gap of %8u sector: sector %8u",
689 "Unused gap of %8u sectors: sectors %8u-%u",
690 lastblock - start),
691 lastblock - start, start, lastblock-1);
692 gap += lastblock - start;
693 add_to_freelist(cxt, start, lastblock);
694 }
695 /*
696 * Done with arithmetic. Go for details now.
697 */
698 if (verbose) {
699 if (sgi_get_bootpartition(cxt) < 0
700 || !sgi_get_num_sectors(cxt, sgi_get_bootpartition(cxt)))
701 fdisk_info(cxt, _("The boot partition does not exist."));
702
703 if (sgi_get_swappartition(cxt) < 0
704 || !sgi_get_num_sectors(cxt, sgi_get_swappartition(cxt)))
705 fdisk_info(cxt, _("The swap partition does not exist."));
706
707 else if (sgi_get_sysid(cxt, sgi_get_swappartition(cxt)) != SGI_TYPE_SWAP
708 && sgi_get_sysid(cxt, sgi_get_swappartition(cxt)) != MBR_LINUX_SWAP_PARTITION)
709 fdisk_info(cxt, _("The swap partition has no swap type."));
710
711 if (sgi_check_bootfile(cxt, "/unix"))
712 fdisk_info(cxt, _("You have chosen an unusual bootfile name."));
713 }
714
715 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
716 }
717
sgi_verify_disklabel(struct fdisk_context * cxt)718 static int sgi_verify_disklabel(struct fdisk_context *cxt)
719 {
720 return verify_disklabel(cxt, 1);
721 }
722
sgi_gaps(struct fdisk_context * cxt)723 static int sgi_gaps(struct fdisk_context *cxt)
724 {
725 /*
726 * returned value is:
727 * = 0 : disk is properly filled to the rim
728 * < 0 : there is an overlap
729 * > 0 : there is still some vacant space
730 */
731 return verify_disklabel(cxt, 0);
732 }
733
734 /* Returns partition index of first entry marked as entire disk. */
sgi_entire(struct fdisk_context * cxt)735 static int sgi_entire(struct fdisk_context *cxt)
736 {
737 size_t i;
738
739 for (i = 0; i < SGI_MAXPARTITIONS; i++)
740 if (sgi_get_sysid(cxt, i) == SGI_TYPE_ENTIRE_DISK)
741 return i;
742 return -1;
743 }
744
set_partition(struct fdisk_context * cxt,size_t i,unsigned int start,unsigned int length,int sys)745 static int set_partition(struct fdisk_context *cxt, size_t i,
746 unsigned int start, unsigned int length, int sys)
747 {
748 struct sgi_disklabel *sgilabel;
749
750 assert(cxt);
751 assert(cxt->label);
752 assert(fdisk_is_label(cxt, SGI));
753
754 sgilabel = self_disklabel(cxt);
755 sgilabel->partitions[i].type = cpu_to_be32(sys);
756 sgilabel->partitions[i].num_blocks = cpu_to_be32(length);
757 sgilabel->partitions[i].first_block = cpu_to_be32(start);
758
759 fdisk_label_set_changed(cxt->label, 1);
760
761 if (sgi_gaps(cxt) < 0) /* rebuild freelist */
762 fdisk_warnx(cxt, _("Partition overlap on the disk."));
763 if (length) {
764 struct fdisk_parttype *t =
765 fdisk_label_get_parttype_from_code(cxt->label, sys);
766 fdisk_info_new_partition(cxt, i + 1, start, start + length, t);
767 }
768
769 return 0;
770 }
771
sgi_set_entire(struct fdisk_context * cxt)772 static void sgi_set_entire(struct fdisk_context *cxt)
773 {
774 size_t n;
775
776 for (n = 10; n < cxt->label->nparts_max; n++) {
777 if (!sgi_get_num_sectors(cxt, n)) {
778 set_partition(cxt, n, 0, sgi_get_lastblock(cxt), SGI_TYPE_ENTIRE_DISK);
779 break;
780 }
781 }
782 }
783
sgi_set_volhdr(struct fdisk_context * cxt)784 static void sgi_set_volhdr(struct fdisk_context *cxt)
785 {
786 size_t n;
787
788 for (n = 8; n < cxt->label->nparts_max; n++) {
789 if (!sgi_get_num_sectors(cxt, n)) {
790 /* Choose same default volume header size as IRIX fx uses. */
791 if (4096 < sgi_get_lastblock(cxt))
792 set_partition(cxt, n, 0, 4096, SGI_TYPE_VOLHDR);
793 break;
794 }
795 }
796 }
797
sgi_delete_partition(struct fdisk_context * cxt,size_t partnum)798 static int sgi_delete_partition(struct fdisk_context *cxt, size_t partnum)
799 {
800 int rc;
801
802 assert(cxt);
803 assert(cxt->label);
804
805 if (partnum > cxt->label->nparts_max)
806 return -EINVAL;
807
808 rc = set_partition(cxt, partnum, 0, 0, 0);
809
810 cxt->label->nparts_cur = count_used_partitions(cxt);
811
812 return rc;
813 }
814
sgi_add_partition(struct fdisk_context * cxt,struct fdisk_partition * pa,size_t * partno)815 static int sgi_add_partition(struct fdisk_context *cxt,
816 struct fdisk_partition *pa,
817 size_t *partno)
818 {
819 struct fdisk_sgi_label *sgi;
820 char mesg[256];
821 unsigned int first = 0, last = 0;
822 struct fdisk_ask *ask;
823 int sys = pa && pa->type ? pa->type->code : SGI_TYPE_XFS;
824 int rc;
825 size_t n;
826
827 assert(cxt);
828 assert(cxt->label);
829 assert(fdisk_is_label(cxt, SGI));
830
831 rc = fdisk_partition_next_partno(pa, cxt, &n);
832 if (rc)
833 return rc;
834 if (n == 10)
835 sys = SGI_TYPE_ENTIRE_DISK;
836 else if (n == 8)
837 sys = 0;
838
839 sgi = self_label(cxt);
840
841 if (sgi_get_num_sectors(cxt, n)) {
842 fdisk_warnx(cxt, _("Partition %zu is already defined. "
843 "Delete it before re-adding it."), n + 1);
844 return -EINVAL;
845 }
846 if (!cxt->script && sgi_entire(cxt) == -1 && sys != SGI_TYPE_ENTIRE_DISK) {
847 fdisk_info(cxt, _("Attempting to generate entire disk entry automatically."));
848 sgi_set_entire(cxt);
849 sgi_set_volhdr(cxt);
850 }
851 if (sgi_gaps(cxt) == 0 && sys != SGI_TYPE_ENTIRE_DISK) {
852 fdisk_warnx(cxt, _("The entire disk is already covered with partitions."));
853 return -EINVAL;
854 }
855 if (sgi_gaps(cxt) < 0) {
856 fdisk_warnx(cxt, _("You got a partition overlap on the disk. Fix it first!"));
857 return -EINVAL;
858 }
859
860 if (sys == SGI_TYPE_ENTIRE_DISK) {
861 first = 0;
862 last = sgi_get_lastblock(cxt);
863 } else {
864 first = sgi->freelist[0].first;
865 last = sgi->freelist[0].last;
866 }
867
868 /* first sector */
869 if (pa && pa->start_follow_default)
870 ;
871 else if (pa && fdisk_partition_has_start(pa)) {
872 first = pa->start;
873 last = is_in_freelist(cxt, first);
874
875 if (sys != SGI_TYPE_ENTIRE_DISK && !last)
876 return -ERANGE;
877 } else {
878 snprintf(mesg, sizeof(mesg), _("First %s"),
879 fdisk_get_unit(cxt, FDISK_SINGULAR));
880 ask = fdisk_new_ask();
881 if (!ask)
882 return -ENOMEM;
883
884 fdisk_ask_set_query(ask, mesg);
885 fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
886
887 fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */
888 fdisk_ask_number_set_default(ask, fdisk_scround(cxt, first)); /* default */
889 fdisk_ask_number_set_high(ask, fdisk_scround(cxt, last) - 1); /* maximal */
890
891 rc = fdisk_do_ask(cxt, ask);
892 first = fdisk_ask_number_get_result(ask);
893 fdisk_unref_ask(ask);
894
895 if (rc)
896 return rc;
897 if (fdisk_use_cylinders(cxt))
898 first *= fdisk_get_units_per_sector(cxt);
899 }
900
901 if (first && sys == SGI_TYPE_ENTIRE_DISK)
902 fdisk_info(cxt, _("It is highly recommended that the "
903 "eleventh partition covers the entire "
904 "disk and is of type 'SGI volume'."));
905 if (!last)
906 last = is_in_freelist(cxt, first);
907
908 /* last sector */
909 if (pa && pa->end_follow_default)
910 last -= 1ULL;
911 else if (pa && fdisk_partition_has_size(pa)) {
912 if (first + pa->size - 1ULL > last)
913 return -ERANGE;
914 last = first + pa->size - 1ULL;
915 } else {
916 snprintf(mesg, sizeof(mesg),
917 _("Last %s or +%s or +size{K,M,G,T,P}"),
918 fdisk_get_unit(cxt, FDISK_SINGULAR),
919 fdisk_get_unit(cxt, FDISK_PLURAL));
920
921 ask = fdisk_new_ask();
922 if (!ask)
923 return -ENOMEM;
924
925 fdisk_ask_set_query(ask, mesg);
926 fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET);
927
928 fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */
929 fdisk_ask_number_set_default(ask, fdisk_scround(cxt, last) - 1);/* default */
930 fdisk_ask_number_set_high(ask, fdisk_scround(cxt, last) - 1);/* maximal */
931 fdisk_ask_number_set_base(ask, fdisk_scround(cxt, first));
932 fdisk_ask_number_set_wrap_negative(ask, 1); /* wrap negative around high */
933
934 if (fdisk_use_cylinders(cxt))
935 fdisk_ask_number_set_unit(ask,
936 cxt->sector_size *
937 fdisk_get_units_per_sector(cxt));
938 else
939 fdisk_ask_number_set_unit(ask,cxt->sector_size);
940
941 rc = fdisk_do_ask(cxt, ask);
942 last = fdisk_ask_number_get_result(ask) + 1;
943
944 fdisk_unref_ask(ask);
945 if (rc)
946 return rc;
947 if (fdisk_use_cylinders(cxt))
948 last *= fdisk_get_units_per_sector(cxt);
949 }
950
951 if (sys == SGI_TYPE_ENTIRE_DISK
952 && (first != 0 || last != sgi_get_lastblock(cxt)))
953 fdisk_info(cxt, _("It is highly recommended that the "
954 "eleventh partition covers the entire "
955 "disk and is of type 'SGI volume'."));
956
957 set_partition(cxt, n, first, last - first, sys);
958 cxt->label->nparts_cur = count_used_partitions(cxt);
959 if (partno)
960 *partno = n;
961 return 0;
962 }
963
sgi_create_disklabel(struct fdisk_context * cxt)964 static int sgi_create_disklabel(struct fdisk_context *cxt)
965 {
966 struct fdisk_sgi_label *sgi;
967 struct sgi_disklabel *sgilabel;
968 int rc;
969
970 assert(cxt);
971 assert(cxt->label);
972 assert(fdisk_is_label(cxt, SGI));
973
974 if (cxt->geom.heads && cxt->geom.sectors) {
975 fdisk_sector_t llsectors;
976
977 if (blkdev_get_sectors(cxt->dev_fd, (unsigned long long *) &llsectors) == 0) {
978 /* the get device size ioctl was successful */
979 fdisk_sector_t llcyls;
980 int sec_fac = cxt->sector_size / 512;
981
982 llcyls = llsectors / (cxt->geom.heads * cxt->geom.sectors * sec_fac);
983 cxt->geom.cylinders = llcyls;
984 if (cxt->geom.cylinders != llcyls) /* truncated? */
985 cxt->geom.cylinders = ~0;
986 } else {
987 /* otherwise print error and use truncated version */
988 fdisk_warnx(cxt,
989 _("BLKGETSIZE ioctl failed on %s. "
990 "Using geometry cylinder value of %llu. "
991 "This value may be truncated for devices "
992 "> 33.8 GB."), cxt->dev_path, cxt->geom.cylinders);
993 }
994 }
995
996 rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
997 if (rc)
998 return rc;
999
1000 sgi = (struct fdisk_sgi_label *) cxt->label;
1001 sgi->header = (struct sgi_disklabel *) cxt->firstsector;
1002
1003 sgilabel = sgi->header;
1004
1005 sgilabel->magic = cpu_to_be32(SGI_LABEL_MAGIC);
1006 sgilabel->root_part_num = cpu_to_be16(0);
1007 sgilabel->swap_part_num = cpu_to_be16(1);
1008
1009 /* sizeof(sgilabel->boot_file) = 16 > 6 */
1010 memset(sgilabel->boot_file, 0, 16);
1011 strcpy((char *) sgilabel->boot_file, "/unix");
1012
1013 sgilabel->devparam.skew = (0);
1014 sgilabel->devparam.gap1 = (0);
1015 sgilabel->devparam.gap2 = (0);
1016 sgilabel->devparam.sparecyl = (0);
1017 sgilabel->devparam.pcylcount = cpu_to_be16(cxt->geom.cylinders);
1018 sgilabel->devparam.head_vol0 = cpu_to_be16(0);
1019 sgilabel->devparam.ntrks = cpu_to_be16(cxt->geom.heads);
1020 /* tracks/cylinder (heads) */
1021 sgilabel->devparam.cmd_tag_queue_depth = (0);
1022 sgilabel->devparam.unused0 = (0);
1023 sgilabel->devparam.unused1 = cpu_to_be16(0);
1024 sgilabel->devparam.nsect = cpu_to_be16(cxt->geom.sectors);
1025 /* sectors/track */
1026 sgilabel->devparam.bytes = cpu_to_be16(cxt->sector_size);
1027 sgilabel->devparam.ilfact = cpu_to_be16(1);
1028 sgilabel->devparam.flags = cpu_to_be32(
1029 SGI_DEVPARAM_TRACK_FWD
1030 | SGI_DEVPARAM_IGNORE_ERRORS
1031 | SGI_DEVPARAM_RESEEK);
1032 sgilabel->devparam.datarate = cpu_to_be32(0);
1033 sgilabel->devparam.retries_on_error = cpu_to_be32(1);
1034 sgilabel->devparam.ms_per_word = cpu_to_be32(0);
1035 sgilabel->devparam.xylogics_gap1 = cpu_to_be16(0);
1036 sgilabel->devparam.xylogics_syncdelay = cpu_to_be16(0);
1037 sgilabel->devparam.xylogics_readdelay = cpu_to_be16(0);
1038 sgilabel->devparam.xylogics_gap2 = cpu_to_be16(0);
1039 sgilabel->devparam.xylogics_readgate = cpu_to_be16(0);
1040 sgilabel->devparam.xylogics_writecont = cpu_to_be16(0);
1041
1042 memset(&(sgilabel->volume), 0,
1043 sizeof(struct sgi_volume) * SGI_MAXVOLUMES);
1044 memset(&(sgilabel->partitions), 0,
1045 sizeof(struct sgi_partition) * SGI_MAXPARTITIONS);
1046 cxt->label->nparts_max = SGI_MAXPARTITIONS;
1047
1048 /* don't create default layout when a script defined */
1049 if (!cxt->script) {
1050 sgi_set_entire(cxt);
1051 sgi_set_volhdr(cxt);
1052 }
1053 cxt->label->nparts_cur = count_used_partitions(cxt);
1054
1055 fdisk_info(cxt, _("Created a new SGI disklabel."));
1056 return 0;
1057 }
1058
sgi_set_partition(struct fdisk_context * cxt,size_t i,struct fdisk_partition * pa)1059 static int sgi_set_partition(struct fdisk_context *cxt,
1060 size_t i,
1061 struct fdisk_partition *pa)
1062 {
1063 struct sgi_disklabel *sgilabel;
1064
1065 if (i >= cxt->label->nparts_max)
1066 return -EINVAL;
1067
1068 sgilabel = self_disklabel(cxt);
1069
1070 if (pa->type) {
1071 struct fdisk_parttype *t = pa->type;
1072
1073 if (sgi_get_num_sectors(cxt, i) == 0) /* caught already before, ... */ {
1074 fdisk_warnx(cxt, _("Sorry, only for non-empty partitions you can change the tag."));
1075 return -EINVAL;
1076 }
1077
1078 if ((i == 10 && t->code != SGI_TYPE_ENTIRE_DISK)
1079 || (i == 8 && t->code != 0))
1080 fdisk_info(cxt, _("Consider leaving partition 9 as volume header (0), "
1081 "and partition 11 as entire volume (6), "
1082 "as IRIX expects it."));
1083
1084 if (cxt->script == NULL
1085 && ((t->code != SGI_TYPE_ENTIRE_DISK) && (t->code != SGI_TYPE_VOLHDR))
1086 && (sgi_get_start_sector(cxt, i) < 1)) {
1087 int yes = 0;
1088 fdisk_ask_yesno(cxt,
1089 _("It is highly recommended that the partition at offset 0 "
1090 "is of type \"SGI volhdr\", the IRIX system will rely on it to "
1091 "retrieve from its directory standalone tools like sash and fx. "
1092 "Only the \"SGI volume\" entire disk section may violate this. "
1093 "Are you sure about tagging this partition differently?"), &yes);
1094 if (!yes)
1095 return 1;
1096 }
1097
1098 sgilabel->partitions[i].type = cpu_to_be32(t->code);
1099 }
1100
1101 if (fdisk_partition_has_start(pa))
1102 sgilabel->partitions[i].first_block = cpu_to_be32(pa->start);
1103 if (fdisk_partition_has_size(pa))
1104 sgilabel->partitions[i].num_blocks = cpu_to_be32(pa->size);
1105
1106 fdisk_label_set_changed(cxt->label, 1);
1107 return 0;
1108 }
1109
1110
sgi_partition_is_used(struct fdisk_context * cxt,size_t i)1111 static int sgi_partition_is_used(
1112 struct fdisk_context *cxt,
1113 size_t i)
1114 {
1115 assert(cxt);
1116 assert(fdisk_is_label(cxt, SGI));
1117
1118 if (i >= cxt->label->nparts_max)
1119 return 0;
1120 return sgi_get_num_sectors(cxt, i) ? 1 : 0;
1121 }
1122
sgi_toggle_partition_flag(struct fdisk_context * cxt,size_t i,unsigned long flag)1123 static int sgi_toggle_partition_flag(struct fdisk_context *cxt, size_t i, unsigned long flag)
1124 {
1125 struct sgi_disklabel *sgilabel;
1126 assert(cxt);
1127 assert(cxt->label);
1128 assert(fdisk_is_label(cxt, SGI));
1129
1130 if (i >= cxt->label->nparts_max)
1131 return -EINVAL;
1132
1133 sgilabel = self_disklabel(cxt);
1134
1135 switch (flag) {
1136 case SGI_FLAG_BOOT:
1137 sgilabel->root_part_num =
1138 be16_to_cpu(sgilabel->root_part_num) == i ?
1139 0 : cpu_to_be16(i);
1140 fdisk_label_set_changed(cxt->label, 1);
1141 break;
1142 case SGI_FLAG_SWAP:
1143 sgilabel->swap_part_num =
1144 be16_to_cpu(sgilabel->swap_part_num) == i ?
1145 0 : cpu_to_be16(i);
1146 fdisk_label_set_changed(cxt->label, 1);
1147 break;
1148 default:
1149 return 1;
1150 }
1151
1152 return 0;
1153 }
1154
1155 static const struct fdisk_field sgi_fields[] =
1156 {
1157 { FDISK_FIELD_DEVICE, N_("Device"), 10, 0 },
1158 { FDISK_FIELD_START, N_("Start"), 5, FDISK_FIELDFL_NUMBER },
1159 { FDISK_FIELD_END, N_("End"), 5, FDISK_FIELDFL_NUMBER },
1160 { FDISK_FIELD_SECTORS, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER },
1161 { FDISK_FIELD_CYLINDERS,N_("Cylinders"), 5, FDISK_FIELDFL_NUMBER },
1162 { FDISK_FIELD_SIZE, N_("Size"), 5, FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_EYECANDY },
1163 { FDISK_FIELD_TYPEID, N_("Id"), 2, FDISK_FIELDFL_NUMBER },
1164 { FDISK_FIELD_TYPE, N_("Type"), 0.1, FDISK_FIELDFL_EYECANDY },
1165 { FDISK_FIELD_ATTR, N_("Attrs"), 0, FDISK_FIELDFL_NUMBER }
1166 };
1167
1168 static const struct fdisk_label_operations sgi_operations =
1169 {
1170 .probe = sgi_probe_label,
1171 .write = sgi_write_disklabel,
1172 .verify = sgi_verify_disklabel,
1173 .get_item = sgi_get_disklabel_item,
1174 .create = sgi_create_disklabel,
1175
1176 .get_part = sgi_get_partition,
1177 .set_part = sgi_set_partition,
1178 .add_part = sgi_add_partition,
1179 .del_part = sgi_delete_partition,
1180
1181 .part_is_used = sgi_partition_is_used,
1182 .part_toggle_flag = sgi_toggle_partition_flag
1183 };
1184
1185 /* Allocates an SGI label driver. */
fdisk_new_sgi_label(struct fdisk_context * cxt)1186 struct fdisk_label *fdisk_new_sgi_label(struct fdisk_context *cxt __attribute__ ((__unused__)))
1187 {
1188 struct fdisk_label *lb;
1189 struct fdisk_sgi_label *sgi;
1190
1191 sgi = calloc(1, sizeof(*sgi));
1192 if (!sgi)
1193 return NULL;
1194
1195 /* initialize generic part of the driver */
1196 lb = (struct fdisk_label *) sgi;
1197 lb->name = "sgi";
1198 lb->id = FDISK_DISKLABEL_SGI;
1199 lb->op = &sgi_operations;
1200 lb->parttypes = sgi_parttypes;
1201 lb->nparttypes = ARRAY_SIZE(sgi_parttypes) - 1;
1202 lb->fields = sgi_fields;
1203 lb->nfields = ARRAY_SIZE(sgi_fields);
1204
1205 lb->flags |= FDISK_LABEL_FL_REQUIRE_GEOMETRY;
1206
1207 return lb;
1208 }
1209