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