blob: 463082f6a17b32504320cf22b59ee8018eff331e [file] [log] [blame]
Denis Vlasenkodb12d1d2008-12-07 00:52:58 +00001/*
2 * fdisk_sun.c
3 *
4 * I think this is mostly, or entirely, due to
5 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
6 *
7 * Merged with fdisk for other architectures, aeb, June 1998.
8 *
9 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
10 * Internationalization
11 *
12 * Licensed under GPLv2, see file LICENSE in this tarball for details.
13 */
14
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +000015#if ENABLE_FEATURE_SUN_LABEL
Denis Vlasenko98ae2162006-10-12 19:30:44 +000016
Denis Vlasenkobd852072007-03-19 14:43:38 +000017#define SUNOS_SWAP 3
18#define SUN_WHOLE_DISK 5
19
Denis Vlasenko98ae2162006-10-12 19:30:44 +000020#define SUN_LABEL_MAGIC 0xDABE
21#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
Denis Vlasenko28703012006-12-19 20:32:02 +000022#define SUN_SSWAP16(x) (sun_other_endian ? fdisk_swap16(x) : (uint16_t)(x))
23#define SUN_SSWAP32(x) (sun_other_endian ? fdisk_swap32(x) : (uint32_t)(x))
Denis Vlasenko98ae2162006-10-12 19:30:44 +000024
25/* Copied from linux/major.h */
26#define FLOPPY_MAJOR 2
27
28#define SCSI_IOCTL_GET_IDLUN 0x5382
29
Denys Vlasenkoddf78502009-09-16 03:03:13 +020030static smallint sun_other_endian;
31static smallint scsi_disk;
32static smallint floppy;
Denis Vlasenko98ae2162006-10-12 19:30:44 +000033
34#ifndef IDE0_MAJOR
35#define IDE0_MAJOR 3
36#endif
37#ifndef IDE1_MAJOR
38#define IDE1_MAJOR 22
39#endif
40
41static void
42guess_device_type(void)
43{
44 struct stat bootstat;
45
Denis Vlasenko4437d192008-04-17 00:12:10 +000046 if (fstat(dev_fd, &bootstat) < 0) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +000047 scsi_disk = 0;
48 floppy = 0;
49 } else if (S_ISBLK(bootstat.st_mode)
50 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
51 major(bootstat.st_rdev) == IDE1_MAJOR)) {
52 scsi_disk = 0;
53 floppy = 0;
54 } else if (S_ISBLK(bootstat.st_mode)
55 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
56 scsi_disk = 0;
57 floppy = 1;
58 } else {
59 scsi_disk = 1;
60 floppy = 0;
61 }
62}
63
Denis Vlasenkobd852072007-03-19 14:43:38 +000064static const char *const sun_sys_types[] = {
65 "\x00" "Empty" , /* 0 */
66 "\x01" "Boot" , /* 1 */
67 "\x02" "SunOS root" , /* 2 */
68 "\x03" "SunOS swap" , /* SUNOS_SWAP */
69 "\x04" "SunOS usr" , /* 4 */
70 "\x05" "Whole disk" , /* SUN_WHOLE_DISK */
71 "\x06" "SunOS stand" , /* 6 */
72 "\x07" "SunOS var" , /* 7 */
73 "\x08" "SunOS home" , /* 8 */
74 "\x82" "Linux swap" , /* LINUX_SWAP */
75 "\x83" "Linux native", /* LINUX_NATIVE */
76 "\x8e" "Linux LVM" , /* 0x8e */
Denis Vlasenko98ae2162006-10-12 19:30:44 +000077/* New (2.2.x) raid partition with autodetect using persistent superblock */
Denis Vlasenkobd852072007-03-19 14:43:38 +000078 "\xfd" "Linux raid autodetect", /* 0xfd */
79 NULL
Denis Vlasenko98ae2162006-10-12 19:30:44 +000080};
81
82
83static void
Denys Vlasenkoddf78502009-09-16 03:03:13 +020084set_sun_partition(int i, unsigned start, unsigned stop, int sysid)
Denis Vlasenko98ae2162006-10-12 19:30:44 +000085{
86 sunlabel->infos[i].id = sysid;
87 sunlabel->partitions[i].start_cylinder =
Denis Vlasenkof77f3692007-12-16 17:22:33 +000088 SUN_SSWAP32(start / (g_heads * g_sectors));
Denis Vlasenko98ae2162006-10-12 19:30:44 +000089 sunlabel->partitions[i].num_sectors =
90 SUN_SSWAP32(stop - start);
91 set_changed(i);
92}
93
94static int
95check_sun_label(void)
96{
97 unsigned short *ush;
98 int csum;
99
100 if (sunlabel->magic != SUN_LABEL_MAGIC
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200101 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED
102 ) {
Denis Vlasenko4437d192008-04-17 00:12:10 +0000103 current_label_type = LABEL_DOS;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000104 sun_other_endian = 0;
105 return 0;
106 }
107 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
108 ush = ((unsigned short *) (sunlabel + 1)) - 1;
109 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
110 if (csum) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000111 printf("Detected sun disklabel with wrong checksum.\n"
112"Probably you'll have to set all the values,\n"
113"e.g. heads, sectors, cylinders and partitions\n"
114"or force a fresh label (s command in main menu)\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000115 } else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000116 g_heads = SUN_SSWAP16(sunlabel->ntrks);
117 g_cylinders = SUN_SSWAP16(sunlabel->ncyl);
118 g_sectors = SUN_SSWAP16(sunlabel->nsect);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000119 }
120 update_units();
Denis Vlasenko4437d192008-04-17 00:12:10 +0000121 current_label_type = LABEL_SUN;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000122 g_partitions = 8;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000123 return 1;
124}
125
126static const struct sun_predefined_drives {
127 const char *vendor;
128 const char *model;
129 unsigned short sparecyl;
130 unsigned short ncyl;
131 unsigned short nacyl;
132 unsigned short pcylcount;
133 unsigned short ntrks;
134 unsigned short nsect;
135 unsigned short rspeed;
136} sun_drives[] = {
137 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
138 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
139 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
140 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
141 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
142 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
143 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
144 { "","SUN0104",1,974,2,1019,6,35,3662},
145 { "","SUN0207",4,1254,2,1272,9,36,3600},
146 { "","SUN0327",3,1545,2,1549,9,46,3600},
147 { "","SUN0340",0,1538,2,1544,6,72,4200},
148 { "","SUN0424",2,1151,2,2500,9,80,4400},
149 { "","SUN0535",0,1866,2,2500,7,80,5400},
150 { "","SUN0669",5,1614,2,1632,15,54,3600},
151 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
152 { "","SUN1.05",0,2036,2,2038,14,72,5400},
153 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
154 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
155 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
156};
157
158static const struct sun_predefined_drives *
159sun_autoconfigure_scsi(void)
160{
161 const struct sun_predefined_drives *p = NULL;
162
163#ifdef SCSI_IOCTL_GET_IDLUN
164 unsigned int id[2];
165 char buffer[2048];
166 char buffer2[2048];
167 FILE *pfd;
168 char *vendor;
169 char *model;
170 char *q;
171 int i;
172
Denis Vlasenko4437d192008-04-17 00:12:10 +0000173 if (ioctl(dev_fd, SCSI_IOCTL_GET_IDLUN, &id))
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000174 return NULL;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000175
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000176 sprintf(buffer,
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200177 "Host: scsi%u Channel: %02u Id: %02u Lun: %02u\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000178 /* This is very wrong (works only if you have one HBA),
179 but I haven't found a way how to get hostno
180 from the current kernel */
181 0,
182 (id[0]>>16) & 0xff,
183 id[0] & 0xff,
184 (id[0]>>8) & 0xff
185 );
Denis Vlasenko5415c852008-07-21 23:05:26 +0000186 pfd = fopen_for_read("/proc/scsi/scsi");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000187 if (!pfd) {
188 return NULL;
189 }
190 while (fgets(buffer2, 2048, pfd)) {
191 if (strcmp(buffer, buffer2))
192 continue;
193 if (!fgets(buffer2, 2048, pfd))
194 break;
195 q = strstr(buffer2, "Vendor: ");
196 if (!q)
197 break;
198 q += 8;
199 vendor = q;
200 q = strstr(q, " ");
201 *q++ = '\0'; /* truncate vendor name */
202 q = strstr(q, "Model: ");
203 if (!q)
204 break;
205 *q = '\0';
206 q += 7;
207 model = q;
208 q = strstr(q, " Rev: ");
209 if (!q)
210 break;
211 *q = '\0';
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000212 for (i = 0; i < ARRAY_SIZE(sun_drives); i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000213 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
214 continue;
215 if (!strstr(model, sun_drives[i].model))
216 continue;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000217 printf("Autoconfigure found a %s%s%s\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000218 sun_drives[i].vendor,
219 (*sun_drives[i].vendor) ? " " : "",
220 sun_drives[i].model);
221 p = sun_drives + i;
222 break;
223 }
224 break;
225 }
226 fclose(pfd);
227#endif
228 return p;
229}
230
231static void
232create_sunlabel(void)
233{
234 struct hd_geometry geometry;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000235 unsigned ndiv;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000236 unsigned char c;
237 const struct sun_predefined_drives *p = NULL;
238
Denis Vlasenkobd852072007-03-19 14:43:38 +0000239 printf(msg_building_new_label, "sun disklabel");
240
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000241 sun_other_endian = BB_LITTLE_ENDIAN;
242 memset(MBRbuffer, 0, sizeof(MBRbuffer));
243 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
244 if (!floppy) {
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000245 unsigned i;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000246 puts("Drive type\n"
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000247 " ? auto configure\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000248 " 0 custom (with hardware detected defaults)");
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000249 for (i = 0; i < ARRAY_SIZE(sun_drives); i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000250 printf(" %c %s%s%s\n",
251 i + 'a', sun_drives[i].vendor,
252 (*sun_drives[i].vendor) ? " " : "",
253 sun_drives[i].model);
254 }
255 while (1) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000256 c = read_nonempty("Select type (? for auto, 0 for custom): ");
257 if (c == '0') {
258 break;
259 }
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000260 if (c >= 'a' && c < 'a' + ARRAY_SIZE(sun_drives)) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000261 p = sun_drives + c - 'a';
262 break;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000263 }
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000264 if (c >= 'A' && c < 'A' + ARRAY_SIZE(sun_drives)) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000265 p = sun_drives + c - 'A';
266 break;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000267 }
268 if (c == '?' && scsi_disk) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000269 p = sun_autoconfigure_scsi();
Denis Vlasenkobd852072007-03-19 14:43:38 +0000270 if (p)
271 break;
272 printf("Autoconfigure failed\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000273 }
274 }
275 }
276 if (!p || floppy) {
Denis Vlasenko4437d192008-04-17 00:12:10 +0000277 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000278 g_heads = geometry.heads;
279 g_sectors = geometry.sectors;
280 g_cylinders = geometry.cylinders;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000281 } else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000282 g_heads = 0;
283 g_sectors = 0;
284 g_cylinders = 0;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000285 }
286 if (floppy) {
287 sunlabel->nacyl = 0;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000288 sunlabel->pcylcount = SUN_SSWAP16(g_cylinders);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000289 sunlabel->rspeed = SUN_SSWAP16(300);
290 sunlabel->ilfact = SUN_SSWAP16(1);
291 sunlabel->sparecyl = 0;
292 } else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000293 g_heads = read_int(1, g_heads, 1024, 0, "Heads");
294 g_sectors = read_int(1, g_sectors, 1024, 0, "Sectors/track");
295 if (g_cylinders)
296 g_cylinders = read_int(1, g_cylinders - 2, 65535, 0, "Cylinders");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000297 else
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000298 g_cylinders = read_int(1, 0, 65535, 0, "Cylinders");
Denis Vlasenkobd852072007-03-19 14:43:38 +0000299 sunlabel->nacyl = SUN_SSWAP16(read_int(0, 2, 65535, 0, "Alternate cylinders"));
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000300 sunlabel->pcylcount = SUN_SSWAP16(read_int(0, g_cylinders + SUN_SSWAP16(sunlabel->nacyl), 65535, 0, "Physical cylinders"));
Denis Vlasenkobd852072007-03-19 14:43:38 +0000301 sunlabel->rspeed = SUN_SSWAP16(read_int(1, 5400, 100000, 0, "Rotation speed (rpm)"));
302 sunlabel->ilfact = SUN_SSWAP16(read_int(1, 1, 32, 0, "Interleave factor"));
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000303 sunlabel->sparecyl = SUN_SSWAP16(read_int(0, 0, g_sectors, 0, "Extra sectors per cylinder"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000304 }
305 } else {
306 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
307 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
308 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
309 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
310 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
311 sunlabel->nsect = SUN_SSWAP16(p->nsect);
312 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
313 sunlabel->ilfact = SUN_SSWAP16(1);
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000314 g_cylinders = p->ncyl;
315 g_heads = p->ntrks;
316 g_sectors = p->nsect;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000317 puts("You may change all the disk params from the x menu");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000318 }
319
320 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200321 "%s%s%s cyl %u alt %u hd %u sec %u",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000322 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
Denis Vlasenkobd852072007-03-19 14:43:38 +0000323 p ? p->model : (floppy ? "3,5\" floppy" : "Linux custom"),
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000324 g_cylinders, SUN_SSWAP16(sunlabel->nacyl), g_heads, g_sectors);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000325
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000326 sunlabel->ntrks = SUN_SSWAP16(g_heads);
327 sunlabel->nsect = SUN_SSWAP16(g_sectors);
328 sunlabel->ncyl = SUN_SSWAP16(g_cylinders);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000329 if (floppy)
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000330 set_sun_partition(0, 0, g_cylinders * g_heads * g_sectors, LINUX_NATIVE);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000331 else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000332 if (g_cylinders * g_heads * g_sectors >= 150 * 2048) {
333 ndiv = g_cylinders - (50 * 2048 / (g_heads * g_sectors)); /* 50M swap */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000334 } else
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000335 ndiv = g_cylinders * 2 / 3;
336 set_sun_partition(0, 0, ndiv * g_heads * g_sectors, LINUX_NATIVE);
337 set_sun_partition(1, ndiv * g_heads * g_sectors, g_cylinders * g_heads * g_sectors, LINUX_SWAP);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000338 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
339 }
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000340 set_sun_partition(2, 0, g_cylinders * g_heads * g_sectors, SUN_WHOLE_DISK);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000341 {
342 unsigned short *ush = (unsigned short *)sunlabel;
343 unsigned short csum = 0;
344 while (ush < (unsigned short *)(&sunlabel->csum))
345 csum ^= *ush++;
346 sunlabel->csum = csum;
347 }
348
349 set_all_unchanged();
350 set_changed(0);
Denis Vlasenko4437d192008-04-17 00:12:10 +0000351 get_boot(CREATE_EMPTY_SUN);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000352}
353
354static void
355toggle_sunflags(int i, unsigned char mask)
356{
357 if (sunlabel->infos[i].flags & mask)
358 sunlabel->infos[i].flags &= ~mask;
359 else
360 sunlabel->infos[i].flags |= mask;
361 set_changed(i);
362}
363
364static void
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200365fetch_sun(unsigned *starts, unsigned *lens, unsigned *start, unsigned *stop)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000366{
367 int i, continuous = 1;
368
369 *start = 0;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000370 *stop = g_cylinders * g_heads * g_sectors;
371 for (i = 0; i < g_partitions; i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000372 if (sunlabel->partitions[i].num_sectors
373 && sunlabel->infos[i].id
374 && sunlabel->infos[i].id != SUN_WHOLE_DISK) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000375 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000376 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
377 if (continuous) {
378 if (starts[i] == *start)
379 *start += lens[i];
380 else if (starts[i] + lens[i] >= *stop)
381 *stop = starts[i];
382 else
383 continuous = 0;
384 /* There will be probably more gaps
385 than one, so lets check afterwards */
386 }
387 } else {
388 starts[i] = 0;
389 lens[i] = 0;
390 }
391 }
392}
393
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200394static unsigned *verify_sun_starts;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000395
396static int
397verify_sun_cmp(int *a, int *b)
398{
399 if (*a == -1) return 1;
400 if (*b == -1) return -1;
401 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
402 return -1;
403}
404
405static void
406verify_sun(void)
407{
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200408 unsigned starts[8], lens[8], start, stop;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000409 int i,j,k,starto,endo;
410 int array[8];
411
412 verify_sun_starts = starts;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000413 fetch_sun(starts, lens, &start, &stop);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000414 for (k = 0; k < 7; k++) {
415 for (i = 0; i < 8; i++) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000416 if (k && (lens[i] % (g_heads * g_sectors))) {
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200417 printf("Partition %u doesn't end on cylinder boundary\n", i+1);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000418 }
419 if (lens[i]) {
420 for (j = 0; j < i; j++)
421 if (lens[j]) {
422 if (starts[j] == starts[i]+lens[i]) {
423 starts[j] = starts[i]; lens[j] += lens[i];
424 lens[i] = 0;
425 } else if (starts[i] == starts[j]+lens[j]){
426 lens[j] += lens[i];
427 lens[i] = 0;
428 } else if (!k) {
429 if (starts[i] < starts[j]+lens[j]
430 && starts[j] < starts[i]+lens[i]) {
431 starto = starts[i];
432 if (starts[j] > starto)
433 starto = starts[j];
434 endo = starts[i]+lens[i];
435 if (starts[j]+lens[j] < endo)
436 endo = starts[j]+lens[j];
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200437 printf("Partition %u overlaps with others in "
438 "sectors %u-%u\n", i+1, starto, endo);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000439 }
440 }
441 }
442 }
443 }
444 }
445 for (i = 0; i < 8; i++) {
446 if (lens[i])
447 array[i] = i;
448 else
449 array[i] = -1;
450 }
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000451 qsort(array, ARRAY_SIZE(array), sizeof(array[0]),
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000452 (int (*)(const void *,const void *)) verify_sun_cmp);
453 if (array[0] == -1) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000454 printf("No partitions defined\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000455 return;
456 }
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000457 stop = g_cylinders * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000458 if (starts[array[0]])
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200459 printf("Unused gap - sectors %u-%u\n", 0, starts[array[0]]);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000460 for (i = 0; i < 7 && array[i+1] != -1; i++) {
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200461 printf("Unused gap - sectors %u-%u\n", starts[array[i]]+lens[array[i]], starts[array[i+1]]);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000462 }
463 start = starts[array[i]] + lens[array[i]];
464 if (start < stop)
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200465 printf("Unused gap - sectors %u-%u\n", start, stop);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000466}
467
468static void
469add_sun_partition(int n, int sys)
470{
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200471 unsigned start, stop, stop2;
472 unsigned starts[8], lens[8];
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000473 int whole_disk = 0;
474
475 char mesg[256];
476 int i, first, last;
477
478 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000479 printf(msg_part_already_defined, n + 1);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000480 return;
481 }
482
Denys Vlasenko083e1722010-01-28 12:30:24 +0100483 fetch_sun(starts, lens, &start, &stop);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000484 if (stop <= start) {
485 if (n == 2)
486 whole_disk = 1;
487 else {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000488 printf("Other partitions already cover the whole disk.\n"
489 "Delete/shrink them before retry.\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000490 return;
491 }
492 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000493 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000494 while (1) {
495 if (whole_disk)
496 first = read_int(0, 0, 0, 0, mesg);
497 else
498 first = read_int(scround(start), scround(stop)+1,
499 scround(stop), 0, mesg);
500 if (display_in_cyl_units)
501 first *= units_per_sector;
502 else
503 /* Starting sector has to be properly aligned */
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000504 first = (first + g_heads * g_sectors - 1) / (g_heads * g_sectors);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000505 if (n == 2 && first != 0)
506 printf("\
507It is highly recommended that the third partition covers the whole disk\n\
Denis Vlasenkobd852072007-03-19 14:43:38 +0000508and is of type 'Whole disk'\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000509 /* ewt asks to add: "don't start a partition at cyl 0"
510 However, edmundo@rano.demon.co.uk writes:
511 "In addition to having a Sun partition table, to be able to
512 boot from the disc, the first partition, /dev/sdX1, must
513 start at cylinder 0. This means that /dev/sdX1 contains
514 the partition table and the boot block, as these are the
515 first two sectors of the disc. Therefore you must be
516 careful what you use /dev/sdX1 for. In particular, you must
517 not use a partition starting at cylinder 0 for Linux swap,
518 as that would overwrite the partition table and the boot
519 block. You may, however, use such a partition for a UFS
520 or EXT2 file system, as these file systems leave the first
521 1024 bytes undisturbed. */
522 /* On the other hand, one should not use partitions
523 starting at block 0 in an md, or the label will
524 be trashed. */
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000525 for (i = 0; i < g_partitions; i++)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000526 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
527 break;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000528 if (i < g_partitions && !whole_disk) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000529 if (n == 2 && !first) {
530 whole_disk = 1;
531 break;
532 }
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200533 printf("Sector %u is already allocated\n", first);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000534 } else
535 break;
536 }
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000537 stop = g_cylinders * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000538 stop2 = stop;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000539 for (i = 0; i < g_partitions; i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000540 if (starts[i] > first && starts[i] < stop)
541 stop = starts[i];
542 }
543 snprintf(mesg, sizeof(mesg),
Denis Vlasenkobd852072007-03-19 14:43:38 +0000544 "Last %s or +size or +sizeM or +sizeK",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000545 str_units(SINGULAR));
546 if (whole_disk)
547 last = read_int(scround(stop2), scround(stop2), scround(stop2),
548 0, mesg);
549 else if (n == 2 && !first)
550 last = read_int(scround(first), scround(stop2), scround(stop2),
551 scround(first), mesg);
552 else
553 last = read_int(scround(first), scround(stop), scround(stop),
554 scround(first), mesg);
555 if (display_in_cyl_units)
556 last *= units_per_sector;
557 if (n == 2 && !first) {
558 if (last >= stop2) {
559 whole_disk = 1;
560 last = stop2;
561 } else if (last > stop) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000562 printf(
563"You haven't covered the whole disk with the 3rd partition,\n"
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200564"but your value %u %s covers some other partition.\n"
565"Your entry has been changed to %u %s\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000566 scround(last), str_units(SINGULAR),
567 scround(stop), str_units(SINGULAR));
568 last = stop;
569 }
570 } else if (!whole_disk && last > stop)
571 last = stop;
572
573 if (whole_disk)
574 sys = SUN_WHOLE_DISK;
575 set_sun_partition(n, first, last, sys);
576}
577
578static void
579sun_delete_partition(int i)
580{
581 unsigned int nsec;
582
583 if (i == 2
584 && sunlabel->infos[i].id == SUN_WHOLE_DISK
585 && !sunlabel->partitions[i].start_cylinder
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000586 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == g_heads * g_sectors * g_cylinders)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000587 printf("If you want to maintain SunOS/Solaris compatibility, "
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000588 "consider leaving this\n"
589 "partition as Whole disk (5), starting at 0, with %u "
Denis Vlasenkobd852072007-03-19 14:43:38 +0000590 "sectors\n", nsec);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000591 sunlabel->infos[i].id = 0;
592 sunlabel->partitions[i].num_sectors = 0;
593}
594
595static void
596sun_change_sysid(int i, int sys)
597{
598 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
599 read_maybe_empty(
Denis Vlasenkobd852072007-03-19 14:43:38 +0000600 "It is highly recommended that the partition at offset 0\n"
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000601 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
602 "there may destroy your partition table and bootblock.\n"
603 "Type YES if you're very sure you would like that partition\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000604 "tagged with 82 (Linux swap): ");
605 if (strcmp (line_ptr, "YES\n"))
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000606 return;
607 }
608 switch (sys) {
609 case SUNOS_SWAP:
610 case LINUX_SWAP:
611 /* swaps are not mountable by default */
612 sunlabel->infos[i].flags |= 0x01;
613 break;
614 default:
615 /* assume other types are mountable;
616 user can change it anyway */
617 sunlabel->infos[i].flags &= ~0x01;
618 break;
619 }
620 sunlabel->infos[i].id = sys;
621}
622
623static void
624sun_list_table(int xtra)
625{
626 int i, w;
627
628 w = strlen(disk_device);
629 if (xtra)
630 printf(
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200631 "\nDisk %s (Sun disk label): %u heads, %u sectors, %u rpm\n"
632 "%u cylinders, %u alternate cylinders, %u physical cylinders\n"
633 "%u extra sects/cyl, interleave %u:1\n"
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000634 "%s\n"
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200635 "Units = %s of %u * 512 bytes\n\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000636 disk_device, g_heads, g_sectors, SUN_SSWAP16(sunlabel->rspeed),
637 g_cylinders, SUN_SSWAP16(sunlabel->nacyl),
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000638 SUN_SSWAP16(sunlabel->pcylcount),
639 SUN_SSWAP16(sunlabel->sparecyl),
640 SUN_SSWAP16(sunlabel->ilfact),
641 (char *)sunlabel,
642 str_units(PLURAL), units_per_sector);
643 else
644 printf(
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200645 "\nDisk %s (Sun disk label): %u heads, %u sectors, %u cylinders\n"
646 "Units = %s of %u * 512 bytes\n\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000647 disk_device, g_heads, g_sectors, g_cylinders,
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000648 str_units(PLURAL), units_per_sector);
649
Denis Vlasenkobd852072007-03-19 14:43:38 +0000650 printf("%*s Flag Start End Blocks Id System\n",
651 w + 1, "Device");
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000652 for (i = 0; i < g_partitions; i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000653 if (sunlabel->partitions[i].num_sectors) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000654 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000655 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200656 printf("%s %c%c %9lu %9lu %9lu%c %2x %s\n",
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000657 partname(disk_device, i+1, w), /* device */
658 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
659 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
660 (long) scround(start), /* start */
661 (long) scround(start+len), /* end */
662 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
663 sunlabel->infos[i].id, /* type id */
664 partition_type(sunlabel->infos[i].id)); /* type name */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000665 }
666 }
667}
668
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000669#if ENABLE_FEATURE_FDISK_ADVANCED
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000670
671static void
672sun_set_alt_cyl(void)
673{
674 sunlabel->nacyl =
Denis Vlasenkobd852072007-03-19 14:43:38 +0000675 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
676 "Number of alternate cylinders"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000677}
678
679static void
680sun_set_ncyl(int cyl)
681{
682 sunlabel->ncyl = SUN_SSWAP16(cyl);
683}
684
685static void
686sun_set_xcyl(void)
687{
688 sunlabel->sparecyl =
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000689 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), g_sectors, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000690 "Extra sectors per cylinder"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000691}
692
693static void
694sun_set_ilfact(void)
695{
696 sunlabel->ilfact =
697 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000698 "Interleave factor"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000699}
700
701static void
702sun_set_rspeed(void)
703{
704 sunlabel->rspeed =
705 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000706 "Rotation speed (rpm)"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000707}
708
709static void
710sun_set_pcylcount(void)
711{
712 sunlabel->pcylcount =
713 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000714 "Number of physical cylinders"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000715}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000716#endif /* FEATURE_FDISK_ADVANCED */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000717
718static void
719sun_write_table(void)
720{
721 unsigned short *ush = (unsigned short *)sunlabel;
722 unsigned short csum = 0;
723
724 while (ush < (unsigned short *)(&sunlabel->csum))
725 csum ^= *ush++;
726 sunlabel->csum = csum;
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +0000727 write_sector(0, sunlabel);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000728}
729#endif /* SUN_LABEL */