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