blob: 9cdf869e9373a1ef8ab3bd97b3b9dfb8eb501bc8 [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
Denis Vlasenko98ae2162006-10-12 19:30:44 +000030static int sun_other_endian;
31static int scsi_disk;
32static int floppy;
33
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
84set_sun_partition(int i, uint start, uint stop, int sysid)
85{
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
101 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
Denis Vlasenko4437d192008-04-17 00:12:10 +0000102 current_label_type = LABEL_DOS;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000103 sun_other_endian = 0;
104 return 0;
105 }
106 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
107 ush = ((unsigned short *) (sunlabel + 1)) - 1;
108 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
109 if (csum) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000110 printf("Detected sun disklabel with wrong checksum.\n"
111"Probably you'll have to set all the values,\n"
112"e.g. heads, sectors, cylinders and partitions\n"
113"or force a fresh label (s command in main menu)\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000114 } else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000115 g_heads = SUN_SSWAP16(sunlabel->ntrks);
116 g_cylinders = SUN_SSWAP16(sunlabel->ncyl);
117 g_sectors = SUN_SSWAP16(sunlabel->nsect);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000118 }
119 update_units();
Denis Vlasenko4437d192008-04-17 00:12:10 +0000120 current_label_type = LABEL_SUN;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000121 g_partitions = 8;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000122 return 1;
123}
124
125static const struct sun_predefined_drives {
126 const char *vendor;
127 const char *model;
128 unsigned short sparecyl;
129 unsigned short ncyl;
130 unsigned short nacyl;
131 unsigned short pcylcount;
132 unsigned short ntrks;
133 unsigned short nsect;
134 unsigned short rspeed;
135} sun_drives[] = {
136 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
137 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
138 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
139 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
140 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
141 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
142 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
143 { "","SUN0104",1,974,2,1019,6,35,3662},
144 { "","SUN0207",4,1254,2,1272,9,36,3600},
145 { "","SUN0327",3,1545,2,1549,9,46,3600},
146 { "","SUN0340",0,1538,2,1544,6,72,4200},
147 { "","SUN0424",2,1151,2,2500,9,80,4400},
148 { "","SUN0535",0,1866,2,2500,7,80,5400},
149 { "","SUN0669",5,1614,2,1632,15,54,3600},
150 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
151 { "","SUN1.05",0,2036,2,2038,14,72,5400},
152 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
153 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
154 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
155};
156
157static const struct sun_predefined_drives *
158sun_autoconfigure_scsi(void)
159{
160 const struct sun_predefined_drives *p = NULL;
161
162#ifdef SCSI_IOCTL_GET_IDLUN
163 unsigned int id[2];
164 char buffer[2048];
165 char buffer2[2048];
166 FILE *pfd;
167 char *vendor;
168 char *model;
169 char *q;
170 int i;
171
Denis Vlasenko4437d192008-04-17 00:12:10 +0000172 if (ioctl(dev_fd, SCSI_IOCTL_GET_IDLUN, &id))
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000173 return NULL;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000174
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000175 sprintf(buffer,
176 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
177 /* This is very wrong (works only if you have one HBA),
178 but I haven't found a way how to get hostno
179 from the current kernel */
180 0,
181 (id[0]>>16) & 0xff,
182 id[0] & 0xff,
183 (id[0]>>8) & 0xff
184 );
Denis Vlasenko5415c852008-07-21 23:05:26 +0000185 pfd = fopen_for_read("/proc/scsi/scsi");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000186 if (!pfd) {
187 return NULL;
188 }
189 while (fgets(buffer2, 2048, pfd)) {
190 if (strcmp(buffer, buffer2))
191 continue;
192 if (!fgets(buffer2, 2048, pfd))
193 break;
194 q = strstr(buffer2, "Vendor: ");
195 if (!q)
196 break;
197 q += 8;
198 vendor = q;
199 q = strstr(q, " ");
200 *q++ = '\0'; /* truncate vendor name */
201 q = strstr(q, "Model: ");
202 if (!q)
203 break;
204 *q = '\0';
205 q += 7;
206 model = q;
207 q = strstr(q, " Rev: ");
208 if (!q)
209 break;
210 *q = '\0';
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000211 for (i = 0; i < ARRAY_SIZE(sun_drives); i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000212 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
213 continue;
214 if (!strstr(model, sun_drives[i].model))
215 continue;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000216 printf("Autoconfigure found a %s%s%s\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000217 sun_drives[i].vendor,
218 (*sun_drives[i].vendor) ? " " : "",
219 sun_drives[i].model);
220 p = sun_drives + i;
221 break;
222 }
223 break;
224 }
225 fclose(pfd);
226#endif
227 return p;
228}
229
230static void
231create_sunlabel(void)
232{
233 struct hd_geometry geometry;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000234 unsigned ndiv;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000235 unsigned char c;
236 const struct sun_predefined_drives *p = NULL;
237
Denis Vlasenkobd852072007-03-19 14:43:38 +0000238 printf(msg_building_new_label, "sun disklabel");
239
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000240 sun_other_endian = BB_LITTLE_ENDIAN;
241 memset(MBRbuffer, 0, sizeof(MBRbuffer));
242 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
243 if (!floppy) {
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000244 unsigned i;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000245 puts("Drive type\n"
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000246 " ? auto configure\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000247 " 0 custom (with hardware detected defaults)");
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000248 for (i = 0; i < ARRAY_SIZE(sun_drives); i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000249 printf(" %c %s%s%s\n",
250 i + 'a', sun_drives[i].vendor,
251 (*sun_drives[i].vendor) ? " " : "",
252 sun_drives[i].model);
253 }
254 while (1) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000255 c = read_nonempty("Select type (? for auto, 0 for custom): ");
256 if (c == '0') {
257 break;
258 }
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000259 if (c >= 'a' && c < 'a' + ARRAY_SIZE(sun_drives)) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000260 p = sun_drives + c - 'a';
261 break;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000262 }
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000263 if (c >= 'A' && c < 'A' + ARRAY_SIZE(sun_drives)) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000264 p = sun_drives + c - 'A';
265 break;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000266 }
267 if (c == '?' && scsi_disk) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000268 p = sun_autoconfigure_scsi();
Denis Vlasenkobd852072007-03-19 14:43:38 +0000269 if (p)
270 break;
271 printf("Autoconfigure failed\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000272 }
273 }
274 }
275 if (!p || floppy) {
Denis Vlasenko4437d192008-04-17 00:12:10 +0000276 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000277 g_heads = geometry.heads;
278 g_sectors = geometry.sectors;
279 g_cylinders = geometry.cylinders;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000280 } else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000281 g_heads = 0;
282 g_sectors = 0;
283 g_cylinders = 0;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000284 }
285 if (floppy) {
286 sunlabel->nacyl = 0;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000287 sunlabel->pcylcount = SUN_SSWAP16(g_cylinders);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000288 sunlabel->rspeed = SUN_SSWAP16(300);
289 sunlabel->ilfact = SUN_SSWAP16(1);
290 sunlabel->sparecyl = 0;
291 } else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000292 g_heads = read_int(1, g_heads, 1024, 0, "Heads");
293 g_sectors = read_int(1, g_sectors, 1024, 0, "Sectors/track");
294 if (g_cylinders)
295 g_cylinders = read_int(1, g_cylinders - 2, 65535, 0, "Cylinders");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000296 else
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000297 g_cylinders = read_int(1, 0, 65535, 0, "Cylinders");
Denis Vlasenkobd852072007-03-19 14:43:38 +0000298 sunlabel->nacyl = SUN_SSWAP16(read_int(0, 2, 65535, 0, "Alternate cylinders"));
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000299 sunlabel->pcylcount = SUN_SSWAP16(read_int(0, g_cylinders + SUN_SSWAP16(sunlabel->nacyl), 65535, 0, "Physical cylinders"));
Denis Vlasenkobd852072007-03-19 14:43:38 +0000300 sunlabel->rspeed = SUN_SSWAP16(read_int(1, 5400, 100000, 0, "Rotation speed (rpm)"));
301 sunlabel->ilfact = SUN_SSWAP16(read_int(1, 1, 32, 0, "Interleave factor"));
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000302 sunlabel->sparecyl = SUN_SSWAP16(read_int(0, 0, g_sectors, 0, "Extra sectors per cylinder"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000303 }
304 } else {
305 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
306 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
307 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
308 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
309 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
310 sunlabel->nsect = SUN_SSWAP16(p->nsect);
311 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
312 sunlabel->ilfact = SUN_SSWAP16(1);
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000313 g_cylinders = p->ncyl;
314 g_heads = p->ntrks;
315 g_sectors = p->nsect;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000316 puts("You may change all the disk params from the x menu");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000317 }
318
319 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
320 "%s%s%s cyl %d alt %d hd %d sec %d",
321 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
Denis Vlasenkobd852072007-03-19 14:43:38 +0000322 p ? p->model : (floppy ? "3,5\" floppy" : "Linux custom"),
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000323 g_cylinders, SUN_SSWAP16(sunlabel->nacyl), g_heads, g_sectors);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000324
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000325 sunlabel->ntrks = SUN_SSWAP16(g_heads);
326 sunlabel->nsect = SUN_SSWAP16(g_sectors);
327 sunlabel->ncyl = SUN_SSWAP16(g_cylinders);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000328 if (floppy)
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000329 set_sun_partition(0, 0, g_cylinders * g_heads * g_sectors, LINUX_NATIVE);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000330 else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000331 if (g_cylinders * g_heads * g_sectors >= 150 * 2048) {
332 ndiv = g_cylinders - (50 * 2048 / (g_heads * g_sectors)); /* 50M swap */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000333 } else
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000334 ndiv = g_cylinders * 2 / 3;
335 set_sun_partition(0, 0, ndiv * g_heads * g_sectors, LINUX_NATIVE);
336 set_sun_partition(1, ndiv * g_heads * g_sectors, g_cylinders * g_heads * g_sectors, LINUX_SWAP);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000337 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
338 }
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000339 set_sun_partition(2, 0, g_cylinders * g_heads * g_sectors, SUN_WHOLE_DISK);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000340 {
341 unsigned short *ush = (unsigned short *)sunlabel;
342 unsigned short csum = 0;
343 while (ush < (unsigned short *)(&sunlabel->csum))
344 csum ^= *ush++;
345 sunlabel->csum = csum;
346 }
347
348 set_all_unchanged();
349 set_changed(0);
Denis Vlasenko4437d192008-04-17 00:12:10 +0000350 get_boot(CREATE_EMPTY_SUN);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000351}
352
353static void
354toggle_sunflags(int i, unsigned char mask)
355{
356 if (sunlabel->infos[i].flags & mask)
357 sunlabel->infos[i].flags &= ~mask;
358 else
359 sunlabel->infos[i].flags |= mask;
360 set_changed(i);
361}
362
363static void
364fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
365{
366 int i, continuous = 1;
367
368 *start = 0;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000369 *stop = g_cylinders * g_heads * g_sectors;
370 for (i = 0; i < g_partitions; i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000371 if (sunlabel->partitions[i].num_sectors
372 && sunlabel->infos[i].id
373 && sunlabel->infos[i].id != SUN_WHOLE_DISK) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000374 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000375 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
376 if (continuous) {
377 if (starts[i] == *start)
378 *start += lens[i];
379 else if (starts[i] + lens[i] >= *stop)
380 *stop = starts[i];
381 else
382 continuous = 0;
383 /* There will be probably more gaps
384 than one, so lets check afterwards */
385 }
386 } else {
387 starts[i] = 0;
388 lens[i] = 0;
389 }
390 }
391}
392
393static uint *verify_sun_starts;
394
395static int
396verify_sun_cmp(int *a, int *b)
397{
398 if (*a == -1) return 1;
399 if (*b == -1) return -1;
400 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
401 return -1;
402}
403
404static void
405verify_sun(void)
406{
407 uint starts[8], lens[8], start, stop;
408 int i,j,k,starto,endo;
409 int array[8];
410
411 verify_sun_starts = starts;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000412 fetch_sun(starts, lens, &start, &stop);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000413 for (k = 0; k < 7; k++) {
414 for (i = 0; i < 8; i++) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000415 if (k && (lens[i] % (g_heads * g_sectors))) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000416 printf("Partition %d doesn't end on cylinder boundary\n", i+1);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000417 }
418 if (lens[i]) {
419 for (j = 0; j < i; j++)
420 if (lens[j]) {
421 if (starts[j] == starts[i]+lens[i]) {
422 starts[j] = starts[i]; lens[j] += lens[i];
423 lens[i] = 0;
424 } else if (starts[i] == starts[j]+lens[j]){
425 lens[j] += lens[i];
426 lens[i] = 0;
427 } else if (!k) {
428 if (starts[i] < starts[j]+lens[j]
429 && starts[j] < starts[i]+lens[i]) {
430 starto = starts[i];
431 if (starts[j] > starto)
432 starto = starts[j];
433 endo = starts[i]+lens[i];
434 if (starts[j]+lens[j] < endo)
435 endo = starts[j]+lens[j];
Denis Vlasenkobd852072007-03-19 14:43:38 +0000436 printf("Partition %d overlaps with others in "
437 "sectors %d-%d\n", i+1, starto, endo);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000438 }
439 }
440 }
441 }
442 }
443 }
444 for (i = 0; i < 8; i++) {
445 if (lens[i])
446 array[i] = i;
447 else
448 array[i] = -1;
449 }
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000450 qsort(array, ARRAY_SIZE(array), sizeof(array[0]),
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000451 (int (*)(const void *,const void *)) verify_sun_cmp);
452 if (array[0] == -1) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000453 printf("No partitions defined\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000454 return;
455 }
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000456 stop = g_cylinders * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000457 if (starts[array[0]])
Denis Vlasenkobd852072007-03-19 14:43:38 +0000458 printf("Unused gap - sectors 0-%d\n", starts[array[0]]);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000459 for (i = 0; i < 7 && array[i+1] != -1; i++) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000460 printf("Unused gap - sectors %d-%d\n", starts[array[i]]+lens[array[i]], starts[array[i+1]]);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000461 }
462 start = starts[array[i]] + lens[array[i]];
463 if (start < stop)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000464 printf("Unused gap - sectors %d-%d\n", start, stop);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000465}
466
467static void
468add_sun_partition(int n, int sys)
469{
470 uint start, stop, stop2;
471 uint starts[8], lens[8];
472 int whole_disk = 0;
473
474 char mesg[256];
475 int i, first, last;
476
477 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000478 printf(msg_part_already_defined, n + 1);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000479 return;
480 }
481
482 fetch_sun(starts,lens,&start,&stop);
483 if (stop <= start) {
484 if (n == 2)
485 whole_disk = 1;
486 else {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000487 printf("Other partitions already cover the whole disk.\n"
488 "Delete/shrink them before retry.\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000489 return;
490 }
491 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000492 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000493 while (1) {
494 if (whole_disk)
495 first = read_int(0, 0, 0, 0, mesg);
496 else
497 first = read_int(scround(start), scround(stop)+1,
498 scround(stop), 0, mesg);
499 if (display_in_cyl_units)
500 first *= units_per_sector;
501 else
502 /* Starting sector has to be properly aligned */
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000503 first = (first + g_heads * g_sectors - 1) / (g_heads * g_sectors);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000504 if (n == 2 && first != 0)
505 printf("\
506It is highly recommended that the third partition covers the whole disk\n\
Denis Vlasenkobd852072007-03-19 14:43:38 +0000507and is of type 'Whole disk'\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000508 /* ewt asks to add: "don't start a partition at cyl 0"
509 However, edmundo@rano.demon.co.uk writes:
510 "In addition to having a Sun partition table, to be able to
511 boot from the disc, the first partition, /dev/sdX1, must
512 start at cylinder 0. This means that /dev/sdX1 contains
513 the partition table and the boot block, as these are the
514 first two sectors of the disc. Therefore you must be
515 careful what you use /dev/sdX1 for. In particular, you must
516 not use a partition starting at cylinder 0 for Linux swap,
517 as that would overwrite the partition table and the boot
518 block. You may, however, use such a partition for a UFS
519 or EXT2 file system, as these file systems leave the first
520 1024 bytes undisturbed. */
521 /* On the other hand, one should not use partitions
522 starting at block 0 in an md, or the label will
523 be trashed. */
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000524 for (i = 0; i < g_partitions; i++)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000525 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
526 break;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000527 if (i < g_partitions && !whole_disk) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000528 if (n == 2 && !first) {
529 whole_disk = 1;
530 break;
531 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000532 printf("Sector %d is already allocated\n", first);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000533 } else
534 break;
535 }
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000536 stop = g_cylinders * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000537 stop2 = stop;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000538 for (i = 0; i < g_partitions; i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000539 if (starts[i] > first && starts[i] < stop)
540 stop = starts[i];
541 }
542 snprintf(mesg, sizeof(mesg),
Denis Vlasenkobd852072007-03-19 14:43:38 +0000543 "Last %s or +size or +sizeM or +sizeK",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000544 str_units(SINGULAR));
545 if (whole_disk)
546 last = read_int(scround(stop2), scround(stop2), scround(stop2),
547 0, mesg);
548 else if (n == 2 && !first)
549 last = read_int(scround(first), scround(stop2), scround(stop2),
550 scround(first), mesg);
551 else
552 last = read_int(scround(first), scround(stop), scround(stop),
553 scround(first), mesg);
554 if (display_in_cyl_units)
555 last *= units_per_sector;
556 if (n == 2 && !first) {
557 if (last >= stop2) {
558 whole_disk = 1;
559 last = stop2;
560 } else if (last > stop) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000561 printf(
562"You haven't covered the whole disk with the 3rd partition,\n"
563"but your value %d %s covers some other partition.\n"
564"Your entry has been changed to %d %s\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000565 scround(last), str_units(SINGULAR),
566 scround(stop), str_units(SINGULAR));
567 last = stop;
568 }
569 } else if (!whole_disk && last > stop)
570 last = stop;
571
572 if (whole_disk)
573 sys = SUN_WHOLE_DISK;
574 set_sun_partition(n, first, last, sys);
575}
576
577static void
578sun_delete_partition(int i)
579{
580 unsigned int nsec;
581
582 if (i == 2
583 && sunlabel->infos[i].id == SUN_WHOLE_DISK
584 && !sunlabel->partitions[i].start_cylinder
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000585 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == g_heads * g_sectors * g_cylinders)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000586 printf("If you want to maintain SunOS/Solaris compatibility, "
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000587 "consider leaving this\n"
588 "partition as Whole disk (5), starting at 0, with %u "
Denis Vlasenkobd852072007-03-19 14:43:38 +0000589 "sectors\n", nsec);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000590 sunlabel->infos[i].id = 0;
591 sunlabel->partitions[i].num_sectors = 0;
592}
593
594static void
595sun_change_sysid(int i, int sys)
596{
597 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
598 read_maybe_empty(
Denis Vlasenkobd852072007-03-19 14:43:38 +0000599 "It is highly recommended that the partition at offset 0\n"
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000600 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
601 "there may destroy your partition table and bootblock.\n"
602 "Type YES if you're very sure you would like that partition\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000603 "tagged with 82 (Linux swap): ");
604 if (strcmp (line_ptr, "YES\n"))
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000605 return;
606 }
607 switch (sys) {
608 case SUNOS_SWAP:
609 case LINUX_SWAP:
610 /* swaps are not mountable by default */
611 sunlabel->infos[i].flags |= 0x01;
612 break;
613 default:
614 /* assume other types are mountable;
615 user can change it anyway */
616 sunlabel->infos[i].flags &= ~0x01;
617 break;
618 }
619 sunlabel->infos[i].id = sys;
620}
621
622static void
623sun_list_table(int xtra)
624{
625 int i, w;
626
627 w = strlen(disk_device);
628 if (xtra)
629 printf(
Denis Vlasenkobd852072007-03-19 14:43:38 +0000630 "\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000631 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
632 "%d extra sects/cyl, interleave %d:1\n"
633 "%s\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000634 "Units = %s of %d * 512 bytes\n\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000635 disk_device, g_heads, g_sectors, SUN_SSWAP16(sunlabel->rspeed),
636 g_cylinders, SUN_SSWAP16(sunlabel->nacyl),
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000637 SUN_SSWAP16(sunlabel->pcylcount),
638 SUN_SSWAP16(sunlabel->sparecyl),
639 SUN_SSWAP16(sunlabel->ilfact),
640 (char *)sunlabel,
641 str_units(PLURAL), units_per_sector);
642 else
643 printf(
Denis Vlasenkobd852072007-03-19 14:43:38 +0000644 "\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
645 "Units = %s of %d * 512 bytes\n\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000646 disk_device, g_heads, g_sectors, g_cylinders,
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000647 str_units(PLURAL), units_per_sector);
648
Denis Vlasenkobd852072007-03-19 14:43:38 +0000649 printf("%*s Flag Start End Blocks Id System\n",
650 w + 1, "Device");
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000651 for (i = 0; i < g_partitions; i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000652 if (sunlabel->partitions[i].num_sectors) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000653 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000654 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
655 printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000656 partname(disk_device, i+1, w), /* device */
657 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
658 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
659 (long) scround(start), /* start */
660 (long) scround(start+len), /* end */
661 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
662 sunlabel->infos[i].id, /* type id */
663 partition_type(sunlabel->infos[i].id)); /* type name */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000664 }
665 }
666}
667
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000668#if ENABLE_FEATURE_FDISK_ADVANCED
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000669
670static void
671sun_set_alt_cyl(void)
672{
673 sunlabel->nacyl =
Denis Vlasenkobd852072007-03-19 14:43:38 +0000674 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
675 "Number of alternate cylinders"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000676}
677
678static void
679sun_set_ncyl(int cyl)
680{
681 sunlabel->ncyl = SUN_SSWAP16(cyl);
682}
683
684static void
685sun_set_xcyl(void)
686{
687 sunlabel->sparecyl =
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000688 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), g_sectors, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000689 "Extra sectors per cylinder"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000690}
691
692static void
693sun_set_ilfact(void)
694{
695 sunlabel->ilfact =
696 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000697 "Interleave factor"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000698}
699
700static void
701sun_set_rspeed(void)
702{
703 sunlabel->rspeed =
704 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000705 "Rotation speed (rpm)"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000706}
707
708static void
709sun_set_pcylcount(void)
710{
711 sunlabel->pcylcount =
712 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000713 "Number of physical cylinders"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000714}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000715#endif /* FEATURE_FDISK_ADVANCED */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000716
717static void
718sun_write_table(void)
719{
720 unsigned short *ush = (unsigned short *)sunlabel;
721 unsigned short csum = 0;
722
723 while (ush < (unsigned short *)(&sunlabel->csum))
724 csum ^= *ush++;
725 sunlabel->csum = csum;
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +0000726 write_sector(0, sunlabel);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000727}
728#endif /* SUN_LABEL */