blob: d1a436b4ae0de93b676af1bffa6f13abc5c42556 [file] [log] [blame]
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +00001#if ENABLE_FEATURE_SUN_LABEL
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002
Denis Vlasenkobd852072007-03-19 14:43:38 +00003#define SUNOS_SWAP 3
4#define SUN_WHOLE_DISK 5
5
Denis Vlasenko98ae2162006-10-12 19:30:44 +00006#define SUN_LABEL_MAGIC 0xDABE
7#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
Denis Vlasenko28703012006-12-19 20:32:02 +00008#define SUN_SSWAP16(x) (sun_other_endian ? fdisk_swap16(x) : (uint16_t)(x))
9#define SUN_SSWAP32(x) (sun_other_endian ? fdisk_swap32(x) : (uint32_t)(x))
Denis Vlasenko98ae2162006-10-12 19:30:44 +000010
11/* Copied from linux/major.h */
12#define FLOPPY_MAJOR 2
13
14#define SCSI_IOCTL_GET_IDLUN 0x5382
15
16/*
17 * fdisksunlabel.c
18 *
19 * I think this is mostly, or entirely, due to
20 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
21 *
22 * Merged with fdisk for other architectures, aeb, June 1998.
23 *
24 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
25 * Internationalization
26 */
27
28
29static int sun_other_endian;
30static int scsi_disk;
31static int floppy;
32
33#ifndef IDE0_MAJOR
34#define IDE0_MAJOR 3
35#endif
36#ifndef IDE1_MAJOR
37#define IDE1_MAJOR 22
38#endif
39
40static void
41guess_device_type(void)
42{
43 struct stat bootstat;
44
Denis Vlasenko4437d192008-04-17 00:12:10 +000045 if (fstat(dev_fd, &bootstat) < 0) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +000046 scsi_disk = 0;
47 floppy = 0;
48 } else if (S_ISBLK(bootstat.st_mode)
49 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
50 major(bootstat.st_rdev) == IDE1_MAJOR)) {
51 scsi_disk = 0;
52 floppy = 0;
53 } else if (S_ISBLK(bootstat.st_mode)
54 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
55 scsi_disk = 0;
56 floppy = 1;
57 } else {
58 scsi_disk = 1;
59 floppy = 0;
60 }
61}
62
Denis Vlasenkobd852072007-03-19 14:43:38 +000063static const char *const sun_sys_types[] = {
64 "\x00" "Empty" , /* 0 */
65 "\x01" "Boot" , /* 1 */
66 "\x02" "SunOS root" , /* 2 */
67 "\x03" "SunOS swap" , /* SUNOS_SWAP */
68 "\x04" "SunOS usr" , /* 4 */
69 "\x05" "Whole disk" , /* SUN_WHOLE_DISK */
70 "\x06" "SunOS stand" , /* 6 */
71 "\x07" "SunOS var" , /* 7 */
72 "\x08" "SunOS home" , /* 8 */
73 "\x82" "Linux swap" , /* LINUX_SWAP */
74 "\x83" "Linux native", /* LINUX_NATIVE */
75 "\x8e" "Linux LVM" , /* 0x8e */
Denis Vlasenko98ae2162006-10-12 19:30:44 +000076/* New (2.2.x) raid partition with autodetect using persistent superblock */
Denis Vlasenkobd852072007-03-19 14:43:38 +000077 "\xfd" "Linux raid autodetect", /* 0xfd */
78 NULL
Denis Vlasenko98ae2162006-10-12 19:30:44 +000079};
80
81
82static void
83set_sun_partition(int i, uint start, uint stop, int sysid)
84{
85 sunlabel->infos[i].id = sysid;
86 sunlabel->partitions[i].start_cylinder =
Denis Vlasenkof77f3692007-12-16 17:22:33 +000087 SUN_SSWAP32(start / (g_heads * g_sectors));
Denis Vlasenko98ae2162006-10-12 19:30:44 +000088 sunlabel->partitions[i].num_sectors =
89 SUN_SSWAP32(stop - start);
90 set_changed(i);
91}
92
93static int
94check_sun_label(void)
95{
96 unsigned short *ush;
97 int csum;
98
99 if (sunlabel->magic != SUN_LABEL_MAGIC
100 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
Denis Vlasenko4437d192008-04-17 00:12:10 +0000101 current_label_type = LABEL_DOS;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000102 sun_other_endian = 0;
103 return 0;
104 }
105 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
106 ush = ((unsigned short *) (sunlabel + 1)) - 1;
107 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
108 if (csum) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000109 printf("Detected sun disklabel with wrong checksum.\n"
110"Probably you'll have to set all the values,\n"
111"e.g. heads, sectors, cylinders and partitions\n"
112"or force a fresh label (s command in main menu)\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000113 } else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000114 g_heads = SUN_SSWAP16(sunlabel->ntrks);
115 g_cylinders = SUN_SSWAP16(sunlabel->ncyl);
116 g_sectors = SUN_SSWAP16(sunlabel->nsect);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000117 }
118 update_units();
Denis Vlasenko4437d192008-04-17 00:12:10 +0000119 current_label_type = LABEL_SUN;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000120 g_partitions = 8;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000121 return 1;
122}
123
124static const struct sun_predefined_drives {
125 const char *vendor;
126 const char *model;
127 unsigned short sparecyl;
128 unsigned short ncyl;
129 unsigned short nacyl;
130 unsigned short pcylcount;
131 unsigned short ntrks;
132 unsigned short nsect;
133 unsigned short rspeed;
134} sun_drives[] = {
135 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
136 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
137 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
138 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
139 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
140 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
141 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
142 { "","SUN0104",1,974,2,1019,6,35,3662},
143 { "","SUN0207",4,1254,2,1272,9,36,3600},
144 { "","SUN0327",3,1545,2,1549,9,46,3600},
145 { "","SUN0340",0,1538,2,1544,6,72,4200},
146 { "","SUN0424",2,1151,2,2500,9,80,4400},
147 { "","SUN0535",0,1866,2,2500,7,80,5400},
148 { "","SUN0669",5,1614,2,1632,15,54,3600},
149 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
150 { "","SUN1.05",0,2036,2,2038,14,72,5400},
151 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
152 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
153 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
154};
155
156static const struct sun_predefined_drives *
157sun_autoconfigure_scsi(void)
158{
159 const struct sun_predefined_drives *p = NULL;
160
161#ifdef SCSI_IOCTL_GET_IDLUN
162 unsigned int id[2];
163 char buffer[2048];
164 char buffer2[2048];
165 FILE *pfd;
166 char *vendor;
167 char *model;
168 char *q;
169 int i;
170
Denis Vlasenko4437d192008-04-17 00:12:10 +0000171 if (ioctl(dev_fd, SCSI_IOCTL_GET_IDLUN, &id))
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000172 return NULL;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000173
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000174 sprintf(buffer,
175 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
176 /* This is very wrong (works only if you have one HBA),
177 but I haven't found a way how to get hostno
178 from the current kernel */
179 0,
180 (id[0]>>16) & 0xff,
181 id[0] & 0xff,
182 (id[0]>>8) & 0xff
183 );
Denis Vlasenko5415c852008-07-21 23:05:26 +0000184 pfd = fopen_for_read("/proc/scsi/scsi");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000185 if (!pfd) {
186 return NULL;
187 }
188 while (fgets(buffer2, 2048, pfd)) {
189 if (strcmp(buffer, buffer2))
190 continue;
191 if (!fgets(buffer2, 2048, pfd))
192 break;
193 q = strstr(buffer2, "Vendor: ");
194 if (!q)
195 break;
196 q += 8;
197 vendor = q;
198 q = strstr(q, " ");
199 *q++ = '\0'; /* truncate vendor name */
200 q = strstr(q, "Model: ");
201 if (!q)
202 break;
203 *q = '\0';
204 q += 7;
205 model = q;
206 q = strstr(q, " Rev: ");
207 if (!q)
208 break;
209 *q = '\0';
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000210 for (i = 0; i < ARRAY_SIZE(sun_drives); i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000211 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
212 continue;
213 if (!strstr(model, sun_drives[i].model))
214 continue;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000215 printf("Autoconfigure found a %s%s%s\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000216 sun_drives[i].vendor,
217 (*sun_drives[i].vendor) ? " " : "",
218 sun_drives[i].model);
219 p = sun_drives + i;
220 break;
221 }
222 break;
223 }
224 fclose(pfd);
225#endif
226 return p;
227}
228
229static void
230create_sunlabel(void)
231{
232 struct hd_geometry geometry;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000233 unsigned ndiv;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000234 unsigned char c;
235 const struct sun_predefined_drives *p = NULL;
236
Denis Vlasenkobd852072007-03-19 14:43:38 +0000237 printf(msg_building_new_label, "sun disklabel");
238
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000239 sun_other_endian = BB_LITTLE_ENDIAN;
240 memset(MBRbuffer, 0, sizeof(MBRbuffer));
241 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
242 if (!floppy) {
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000243 unsigned i;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000244 puts("Drive type\n"
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000245 " ? auto configure\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000246 " 0 custom (with hardware detected defaults)");
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000247 for (i = 0; i < ARRAY_SIZE(sun_drives); i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000248 printf(" %c %s%s%s\n",
249 i + 'a', sun_drives[i].vendor,
250 (*sun_drives[i].vendor) ? " " : "",
251 sun_drives[i].model);
252 }
253 while (1) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000254 c = read_nonempty("Select type (? for auto, 0 for custom): ");
255 if (c == '0') {
256 break;
257 }
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000258 if (c >= 'a' && c < 'a' + ARRAY_SIZE(sun_drives)) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000259 p = sun_drives + c - 'a';
260 break;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000261 }
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000262 if (c >= 'A' && c < 'A' + ARRAY_SIZE(sun_drives)) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000263 p = sun_drives + c - 'A';
264 break;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000265 }
266 if (c == '?' && scsi_disk) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000267 p = sun_autoconfigure_scsi();
Denis Vlasenkobd852072007-03-19 14:43:38 +0000268 if (p)
269 break;
270 printf("Autoconfigure failed\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000271 }
272 }
273 }
274 if (!p || floppy) {
Denis Vlasenko4437d192008-04-17 00:12:10 +0000275 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000276 g_heads = geometry.heads;
277 g_sectors = geometry.sectors;
278 g_cylinders = geometry.cylinders;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000279 } else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000280 g_heads = 0;
281 g_sectors = 0;
282 g_cylinders = 0;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000283 }
284 if (floppy) {
285 sunlabel->nacyl = 0;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000286 sunlabel->pcylcount = SUN_SSWAP16(g_cylinders);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000287 sunlabel->rspeed = SUN_SSWAP16(300);
288 sunlabel->ilfact = SUN_SSWAP16(1);
289 sunlabel->sparecyl = 0;
290 } else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000291 g_heads = read_int(1, g_heads, 1024, 0, "Heads");
292 g_sectors = read_int(1, g_sectors, 1024, 0, "Sectors/track");
293 if (g_cylinders)
294 g_cylinders = read_int(1, g_cylinders - 2, 65535, 0, "Cylinders");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000295 else
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000296 g_cylinders = read_int(1, 0, 65535, 0, "Cylinders");
Denis Vlasenkobd852072007-03-19 14:43:38 +0000297 sunlabel->nacyl = SUN_SSWAP16(read_int(0, 2, 65535, 0, "Alternate cylinders"));
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000298 sunlabel->pcylcount = SUN_SSWAP16(read_int(0, g_cylinders + SUN_SSWAP16(sunlabel->nacyl), 65535, 0, "Physical cylinders"));
Denis Vlasenkobd852072007-03-19 14:43:38 +0000299 sunlabel->rspeed = SUN_SSWAP16(read_int(1, 5400, 100000, 0, "Rotation speed (rpm)"));
300 sunlabel->ilfact = SUN_SSWAP16(read_int(1, 1, 32, 0, "Interleave factor"));
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000301 sunlabel->sparecyl = SUN_SSWAP16(read_int(0, 0, g_sectors, 0, "Extra sectors per cylinder"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000302 }
303 } else {
304 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
305 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
306 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
307 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
308 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
309 sunlabel->nsect = SUN_SSWAP16(p->nsect);
310 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
311 sunlabel->ilfact = SUN_SSWAP16(1);
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000312 g_cylinders = p->ncyl;
313 g_heads = p->ntrks;
314 g_sectors = p->nsect;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000315 puts("You may change all the disk params from the x menu");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000316 }
317
318 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
319 "%s%s%s cyl %d alt %d hd %d sec %d",
320 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
Denis Vlasenkobd852072007-03-19 14:43:38 +0000321 p ? p->model : (floppy ? "3,5\" floppy" : "Linux custom"),
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000322 g_cylinders, SUN_SSWAP16(sunlabel->nacyl), g_heads, g_sectors);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000323
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000324 sunlabel->ntrks = SUN_SSWAP16(g_heads);
325 sunlabel->nsect = SUN_SSWAP16(g_sectors);
326 sunlabel->ncyl = SUN_SSWAP16(g_cylinders);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000327 if (floppy)
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000328 set_sun_partition(0, 0, g_cylinders * g_heads * g_sectors, LINUX_NATIVE);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000329 else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000330 if (g_cylinders * g_heads * g_sectors >= 150 * 2048) {
331 ndiv = g_cylinders - (50 * 2048 / (g_heads * g_sectors)); /* 50M swap */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000332 } else
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000333 ndiv = g_cylinders * 2 / 3;
334 set_sun_partition(0, 0, ndiv * g_heads * g_sectors, LINUX_NATIVE);
335 set_sun_partition(1, ndiv * g_heads * g_sectors, g_cylinders * g_heads * g_sectors, LINUX_SWAP);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000336 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
337 }
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000338 set_sun_partition(2, 0, g_cylinders * g_heads * g_sectors, SUN_WHOLE_DISK);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000339 {
340 unsigned short *ush = (unsigned short *)sunlabel;
341 unsigned short csum = 0;
342 while (ush < (unsigned short *)(&sunlabel->csum))
343 csum ^= *ush++;
344 sunlabel->csum = csum;
345 }
346
347 set_all_unchanged();
348 set_changed(0);
Denis Vlasenko4437d192008-04-17 00:12:10 +0000349 get_boot(CREATE_EMPTY_SUN);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000350}
351
352static void
353toggle_sunflags(int i, unsigned char mask)
354{
355 if (sunlabel->infos[i].flags & mask)
356 sunlabel->infos[i].flags &= ~mask;
357 else
358 sunlabel->infos[i].flags |= mask;
359 set_changed(i);
360}
361
362static void
363fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
364{
365 int i, continuous = 1;
366
367 *start = 0;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000368 *stop = g_cylinders * g_heads * g_sectors;
369 for (i = 0; i < g_partitions; i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000370 if (sunlabel->partitions[i].num_sectors
371 && sunlabel->infos[i].id
372 && sunlabel->infos[i].id != SUN_WHOLE_DISK) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000373 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000374 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
375 if (continuous) {
376 if (starts[i] == *start)
377 *start += lens[i];
378 else if (starts[i] + lens[i] >= *stop)
379 *stop = starts[i];
380 else
381 continuous = 0;
382 /* There will be probably more gaps
383 than one, so lets check afterwards */
384 }
385 } else {
386 starts[i] = 0;
387 lens[i] = 0;
388 }
389 }
390}
391
392static uint *verify_sun_starts;
393
394static int
395verify_sun_cmp(int *a, int *b)
396{
397 if (*a == -1) return 1;
398 if (*b == -1) return -1;
399 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
400 return -1;
401}
402
403static void
404verify_sun(void)
405{
406 uint starts[8], lens[8], start, stop;
407 int i,j,k,starto,endo;
408 int array[8];
409
410 verify_sun_starts = starts;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000411 fetch_sun(starts, lens, &start, &stop);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000412 for (k = 0; k < 7; k++) {
413 for (i = 0; i < 8; i++) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000414 if (k && (lens[i] % (g_heads * g_sectors))) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000415 printf("Partition %d doesn't end on cylinder boundary\n", i+1);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000416 }
417 if (lens[i]) {
418 for (j = 0; j < i; j++)
419 if (lens[j]) {
420 if (starts[j] == starts[i]+lens[i]) {
421 starts[j] = starts[i]; lens[j] += lens[i];
422 lens[i] = 0;
423 } else if (starts[i] == starts[j]+lens[j]){
424 lens[j] += lens[i];
425 lens[i] = 0;
426 } else if (!k) {
427 if (starts[i] < starts[j]+lens[j]
428 && starts[j] < starts[i]+lens[i]) {
429 starto = starts[i];
430 if (starts[j] > starto)
431 starto = starts[j];
432 endo = starts[i]+lens[i];
433 if (starts[j]+lens[j] < endo)
434 endo = starts[j]+lens[j];
Denis Vlasenkobd852072007-03-19 14:43:38 +0000435 printf("Partition %d overlaps with others in "
436 "sectors %d-%d\n", i+1, starto, endo);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000437 }
438 }
439 }
440 }
441 }
442 }
443 for (i = 0; i < 8; i++) {
444 if (lens[i])
445 array[i] = i;
446 else
447 array[i] = -1;
448 }
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000449 qsort(array, ARRAY_SIZE(array), sizeof(array[0]),
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000450 (int (*)(const void *,const void *)) verify_sun_cmp);
451 if (array[0] == -1) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000452 printf("No partitions defined\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000453 return;
454 }
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000455 stop = g_cylinders * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000456 if (starts[array[0]])
Denis Vlasenkobd852072007-03-19 14:43:38 +0000457 printf("Unused gap - sectors 0-%d\n", starts[array[0]]);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000458 for (i = 0; i < 7 && array[i+1] != -1; i++) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000459 printf("Unused gap - sectors %d-%d\n", starts[array[i]]+lens[array[i]], starts[array[i+1]]);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000460 }
461 start = starts[array[i]] + lens[array[i]];
462 if (start < stop)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000463 printf("Unused gap - sectors %d-%d\n", start, stop);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000464}
465
466static void
467add_sun_partition(int n, int sys)
468{
469 uint start, stop, stop2;
470 uint starts[8], lens[8];
471 int whole_disk = 0;
472
473 char mesg[256];
474 int i, first, last;
475
476 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000477 printf(msg_part_already_defined, n + 1);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000478 return;
479 }
480
481 fetch_sun(starts,lens,&start,&stop);
482 if (stop <= start) {
483 if (n == 2)
484 whole_disk = 1;
485 else {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000486 printf("Other partitions already cover the whole disk.\n"
487 "Delete/shrink them before retry.\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000488 return;
489 }
490 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000491 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000492 while (1) {
493 if (whole_disk)
494 first = read_int(0, 0, 0, 0, mesg);
495 else
496 first = read_int(scround(start), scround(stop)+1,
497 scround(stop), 0, mesg);
498 if (display_in_cyl_units)
499 first *= units_per_sector;
500 else
501 /* Starting sector has to be properly aligned */
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000502 first = (first + g_heads * g_sectors - 1) / (g_heads * g_sectors);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000503 if (n == 2 && first != 0)
504 printf("\
505It is highly recommended that the third partition covers the whole disk\n\
Denis Vlasenkobd852072007-03-19 14:43:38 +0000506and is of type 'Whole disk'\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000507 /* ewt asks to add: "don't start a partition at cyl 0"
508 However, edmundo@rano.demon.co.uk writes:
509 "In addition to having a Sun partition table, to be able to
510 boot from the disc, the first partition, /dev/sdX1, must
511 start at cylinder 0. This means that /dev/sdX1 contains
512 the partition table and the boot block, as these are the
513 first two sectors of the disc. Therefore you must be
514 careful what you use /dev/sdX1 for. In particular, you must
515 not use a partition starting at cylinder 0 for Linux swap,
516 as that would overwrite the partition table and the boot
517 block. You may, however, use such a partition for a UFS
518 or EXT2 file system, as these file systems leave the first
519 1024 bytes undisturbed. */
520 /* On the other hand, one should not use partitions
521 starting at block 0 in an md, or the label will
522 be trashed. */
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000523 for (i = 0; i < g_partitions; i++)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000524 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
525 break;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000526 if (i < g_partitions && !whole_disk) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000527 if (n == 2 && !first) {
528 whole_disk = 1;
529 break;
530 }
Denis Vlasenkobd852072007-03-19 14:43:38 +0000531 printf("Sector %d is already allocated\n", first);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000532 } else
533 break;
534 }
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000535 stop = g_cylinders * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000536 stop2 = stop;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000537 for (i = 0; i < g_partitions; i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000538 if (starts[i] > first && starts[i] < stop)
539 stop = starts[i];
540 }
541 snprintf(mesg, sizeof(mesg),
Denis Vlasenkobd852072007-03-19 14:43:38 +0000542 "Last %s or +size or +sizeM or +sizeK",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000543 str_units(SINGULAR));
544 if (whole_disk)
545 last = read_int(scround(stop2), scround(stop2), scround(stop2),
546 0, mesg);
547 else if (n == 2 && !first)
548 last = read_int(scround(first), scround(stop2), scround(stop2),
549 scround(first), mesg);
550 else
551 last = read_int(scround(first), scround(stop), scround(stop),
552 scround(first), mesg);
553 if (display_in_cyl_units)
554 last *= units_per_sector;
555 if (n == 2 && !first) {
556 if (last >= stop2) {
557 whole_disk = 1;
558 last = stop2;
559 } else if (last > stop) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000560 printf(
561"You haven't covered the whole disk with the 3rd partition,\n"
562"but your value %d %s covers some other partition.\n"
563"Your entry has been changed to %d %s\n",
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000564 scround(last), str_units(SINGULAR),
565 scround(stop), str_units(SINGULAR));
566 last = stop;
567 }
568 } else if (!whole_disk && last > stop)
569 last = stop;
570
571 if (whole_disk)
572 sys = SUN_WHOLE_DISK;
573 set_sun_partition(n, first, last, sys);
574}
575
576static void
577sun_delete_partition(int i)
578{
579 unsigned int nsec;
580
581 if (i == 2
582 && sunlabel->infos[i].id == SUN_WHOLE_DISK
583 && !sunlabel->partitions[i].start_cylinder
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000584 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == g_heads * g_sectors * g_cylinders)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000585 printf("If you want to maintain SunOS/Solaris compatibility, "
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000586 "consider leaving this\n"
587 "partition as Whole disk (5), starting at 0, with %u "
Denis Vlasenkobd852072007-03-19 14:43:38 +0000588 "sectors\n", nsec);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000589 sunlabel->infos[i].id = 0;
590 sunlabel->partitions[i].num_sectors = 0;
591}
592
593static void
594sun_change_sysid(int i, int sys)
595{
596 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
597 read_maybe_empty(
Denis Vlasenkobd852072007-03-19 14:43:38 +0000598 "It is highly recommended that the partition at offset 0\n"
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000599 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
600 "there may destroy your partition table and bootblock.\n"
601 "Type YES if you're very sure you would like that partition\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000602 "tagged with 82 (Linux swap): ");
603 if (strcmp (line_ptr, "YES\n"))
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000604 return;
605 }
606 switch (sys) {
607 case SUNOS_SWAP:
608 case LINUX_SWAP:
609 /* swaps are not mountable by default */
610 sunlabel->infos[i].flags |= 0x01;
611 break;
612 default:
613 /* assume other types are mountable;
614 user can change it anyway */
615 sunlabel->infos[i].flags &= ~0x01;
616 break;
617 }
618 sunlabel->infos[i].id = sys;
619}
620
621static void
622sun_list_table(int xtra)
623{
624 int i, w;
625
626 w = strlen(disk_device);
627 if (xtra)
628 printf(
Denis Vlasenkobd852072007-03-19 14:43:38 +0000629 "\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000630 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
631 "%d extra sects/cyl, interleave %d:1\n"
632 "%s\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000633 "Units = %s of %d * 512 bytes\n\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000634 disk_device, g_heads, g_sectors, SUN_SSWAP16(sunlabel->rspeed),
635 g_cylinders, SUN_SSWAP16(sunlabel->nacyl),
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000636 SUN_SSWAP16(sunlabel->pcylcount),
637 SUN_SSWAP16(sunlabel->sparecyl),
638 SUN_SSWAP16(sunlabel->ilfact),
639 (char *)sunlabel,
640 str_units(PLURAL), units_per_sector);
641 else
642 printf(
Denis Vlasenkobd852072007-03-19 14:43:38 +0000643 "\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
644 "Units = %s of %d * 512 bytes\n\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000645 disk_device, g_heads, g_sectors, g_cylinders,
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000646 str_units(PLURAL), units_per_sector);
647
Denis Vlasenkobd852072007-03-19 14:43:38 +0000648 printf("%*s Flag Start End Blocks Id System\n",
649 w + 1, "Device");
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000650 for (i = 0; i < g_partitions; i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000651 if (sunlabel->partitions[i].num_sectors) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000652 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000653 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
654 printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000655 partname(disk_device, i+1, w), /* device */
656 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
657 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
658 (long) scround(start), /* start */
659 (long) scround(start+len), /* end */
660 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
661 sunlabel->infos[i].id, /* type id */
662 partition_type(sunlabel->infos[i].id)); /* type name */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000663 }
664 }
665}
666
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000667#if ENABLE_FEATURE_FDISK_ADVANCED
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000668
669static void
670sun_set_alt_cyl(void)
671{
672 sunlabel->nacyl =
Denis Vlasenkobd852072007-03-19 14:43:38 +0000673 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
674 "Number of alternate cylinders"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000675}
676
677static void
678sun_set_ncyl(int cyl)
679{
680 sunlabel->ncyl = SUN_SSWAP16(cyl);
681}
682
683static void
684sun_set_xcyl(void)
685{
686 sunlabel->sparecyl =
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000687 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), g_sectors, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000688 "Extra sectors per cylinder"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000689}
690
691static void
692sun_set_ilfact(void)
693{
694 sunlabel->ilfact =
695 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000696 "Interleave factor"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000697}
698
699static void
700sun_set_rspeed(void)
701{
702 sunlabel->rspeed =
703 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000704 "Rotation speed (rpm)"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000705}
706
707static void
708sun_set_pcylcount(void)
709{
710 sunlabel->pcylcount =
711 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000712 "Number of physical cylinders"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000713}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000714#endif /* FEATURE_FDISK_ADVANCED */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000715
716static void
717sun_write_table(void)
718{
719 unsigned short *ush = (unsigned short *)sunlabel;
720 unsigned short csum = 0;
721
722 while (ush < (unsigned short *)(&sunlabel->csum))
723 csum ^= *ush++;
724 sunlabel->csum = csum;
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +0000725 write_sector(0, sunlabel);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000726}
727#endif /* SUN_LABEL */