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