blob: 5b7760e8c9d720d07c9bd4b180128f5980df7a03 [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 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +020012 * Licensed under GPLv2, see file LICENSE in this source tree.
Denis Vlasenkodb12d1d2008-12-07 00:52:58 +000013 */
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
Denys Vlasenko965b7952020-11-30 13:03:03 +010064static const char *const sun_sys_types[] ALIGN_PTR = {
Denis Vlasenkobd852072007-03-19 14:43:38 +000065 "\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;
Denys Vlasenko965b7952020-11-30 13:03:03 +0100136} sun_drives[] ALIGN_PTR = {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000137 { "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");
Denys Vlasenko9ba50242021-08-16 11:13:30 +0200295 if (g_cylinders)
296 g_cylinders = read_int(1, g_cylinders - 2, 65535, 0, "Cylinders");
297 else
298 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);
Aaro Koskinen1bd5ca22013-02-09 21:12:25 +0200351 check_sun_label();
Denis Vlasenko4437d192008-04-17 00:12:10 +0000352 get_boot(CREATE_EMPTY_SUN);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000353}
354
355static void
356toggle_sunflags(int i, unsigned char mask)
357{
358 if (sunlabel->infos[i].flags & mask)
359 sunlabel->infos[i].flags &= ~mask;
360 else
361 sunlabel->infos[i].flags |= mask;
362 set_changed(i);
363}
364
365static void
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200366fetch_sun(unsigned *starts, unsigned *lens, unsigned *start, unsigned *stop)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000367{
368 int i, continuous = 1;
369
370 *start = 0;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000371 *stop = g_cylinders * g_heads * g_sectors;
372 for (i = 0; i < g_partitions; i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000373 if (sunlabel->partitions[i].num_sectors
374 && sunlabel->infos[i].id
375 && sunlabel->infos[i].id != SUN_WHOLE_DISK) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000376 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000377 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
378 if (continuous) {
379 if (starts[i] == *start)
380 *start += lens[i];
381 else if (starts[i] + lens[i] >= *stop)
382 *stop = starts[i];
383 else
384 continuous = 0;
385 /* There will be probably more gaps
386 than one, so lets check afterwards */
387 }
388 } else {
389 starts[i] = 0;
390 lens[i] = 0;
391 }
392 }
393}
394
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200395static unsigned *verify_sun_starts;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000396
397static int
398verify_sun_cmp(int *a, int *b)
399{
400 if (*a == -1) return 1;
401 if (*b == -1) return -1;
402 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
403 return -1;
404}
405
Denys Vlasenkod3dbf4a2021-10-10 14:32:05 +0200406static NOINLINE void
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000407verify_sun(void)
408{
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200409 unsigned starts[8], lens[8], start, stop;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000410 int i,j,k,starto,endo;
411 int array[8];
412
413 verify_sun_starts = starts;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000414 fetch_sun(starts, lens, &start, &stop);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000415 for (k = 0; k < 7; k++) {
416 for (i = 0; i < 8; i++) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000417 if (k && (lens[i] % (g_heads * g_sectors))) {
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200418 printf("Partition %u doesn't end on cylinder boundary\n", i+1);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000419 }
420 if (lens[i]) {
421 for (j = 0; j < i; j++)
422 if (lens[j]) {
423 if (starts[j] == starts[i]+lens[i]) {
424 starts[j] = starts[i]; lens[j] += lens[i];
425 lens[i] = 0;
426 } else if (starts[i] == starts[j]+lens[j]){
427 lens[j] += lens[i];
428 lens[i] = 0;
429 } else if (!k) {
430 if (starts[i] < starts[j]+lens[j]
431 && starts[j] < starts[i]+lens[i]) {
432 starto = starts[i];
433 if (starts[j] > starto)
434 starto = starts[j];
435 endo = starts[i]+lens[i];
436 if (starts[j]+lens[j] < endo)
437 endo = starts[j]+lens[j];
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200438 printf("Partition %u overlaps with others in "
439 "sectors %u-%u\n", i+1, starto, endo);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000440 }
441 }
442 }
443 }
444 }
445 }
446 for (i = 0; i < 8; i++) {
447 if (lens[i])
448 array[i] = i;
449 else
450 array[i] = -1;
451 }
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000452 qsort(array, ARRAY_SIZE(array), sizeof(array[0]),
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000453 (int (*)(const void *,const void *)) verify_sun_cmp);
454 if (array[0] == -1) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000455 printf("No partitions defined\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000456 return;
457 }
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000458 stop = g_cylinders * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000459 if (starts[array[0]])
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200460 printf("Unused gap - sectors %u-%u\n", 0, starts[array[0]]);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000461 for (i = 0; i < 7 && array[i+1] != -1; i++) {
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200462 printf("Unused gap - sectors %u-%u\n", starts[array[i]]+lens[array[i]], starts[array[i+1]]);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000463 }
464 start = starts[array[i]] + lens[array[i]];
465 if (start < stop)
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200466 printf("Unused gap - sectors %u-%u\n", start, stop);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000467}
468
469static void
470add_sun_partition(int n, int sys)
471{
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200472 unsigned start, stop, stop2;
473 unsigned starts[8], lens[8];
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000474 int whole_disk = 0;
475
476 char mesg[256];
477 int i, first, last;
478
479 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000480 printf(msg_part_already_defined, n + 1);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000481 return;
482 }
483
Denys Vlasenko083e1722010-01-28 12:30:24 +0100484 fetch_sun(starts, lens, &start, &stop);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000485 if (stop <= start) {
486 if (n == 2)
487 whole_disk = 1;
488 else {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000489 printf("Other partitions already cover the whole disk.\n"
490 "Delete/shrink them before retry.\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000491 return;
492 }
493 }
Denys Vlasenkod8e4ce02019-10-04 16:45:04 +0200494 snprintf(mesg, sizeof(mesg), "First %s", str_units());
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000495 while (1) {
496 if (whole_disk)
497 first = read_int(0, 0, 0, 0, mesg);
498 else
499 first = read_int(scround(start), scround(stop)+1,
500 scround(stop), 0, mesg);
Aaro Koskinencf5731b2013-02-09 21:12:26 +0200501 if (display_in_cyl_units) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000502 first *= units_per_sector;
Aaro Koskinencf5731b2013-02-09 21:12:26 +0200503 } else {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000504 /* Starting sector has to be properly aligned */
Aaro Koskinencf5731b2013-02-09 21:12:26 +0200505 first = (first + g_heads * g_sectors - 1) /
506 (g_heads * g_sectors);
507 first *= g_heads * g_sectors;
508 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000509 if (n == 2 && first != 0)
510 printf("\
511It is highly recommended that the third partition covers the whole disk\n\
Denis Vlasenkobd852072007-03-19 14:43:38 +0000512and is of type 'Whole disk'\n");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000513 /* ewt asks to add: "don't start a partition at cyl 0"
514 However, edmundo@rano.demon.co.uk writes:
515 "In addition to having a Sun partition table, to be able to
516 boot from the disc, the first partition, /dev/sdX1, must
517 start at cylinder 0. This means that /dev/sdX1 contains
518 the partition table and the boot block, as these are the
519 first two sectors of the disc. Therefore you must be
520 careful what you use /dev/sdX1 for. In particular, you must
521 not use a partition starting at cylinder 0 for Linux swap,
522 as that would overwrite the partition table and the boot
523 block. You may, however, use such a partition for a UFS
524 or EXT2 file system, as these file systems leave the first
525 1024 bytes undisturbed. */
526 /* On the other hand, one should not use partitions
527 starting at block 0 in an md, or the label will
528 be trashed. */
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000529 for (i = 0; i < g_partitions; i++)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000530 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
531 break;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000532 if (i < g_partitions && !whole_disk) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000533 if (n == 2 && !first) {
534 whole_disk = 1;
535 break;
536 }
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200537 printf("Sector %u is already allocated\n", first);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000538 } else
539 break;
540 }
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000541 stop = g_cylinders * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000542 stop2 = stop;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000543 for (i = 0; i < g_partitions; i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000544 if (starts[i] > first && starts[i] < stop)
545 stop = starts[i];
546 }
547 snprintf(mesg, sizeof(mesg),
Denis Vlasenkobd852072007-03-19 14:43:38 +0000548 "Last %s or +size or +sizeM or +sizeK",
Denys Vlasenkod8e4ce02019-10-04 16:45:04 +0200549 str_units());
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000550 if (whole_disk)
551 last = read_int(scround(stop2), scround(stop2), scround(stop2),
552 0, mesg);
553 else if (n == 2 && !first)
554 last = read_int(scround(first), scround(stop2), scround(stop2),
555 scround(first), mesg);
556 else
557 last = read_int(scround(first), scround(stop), scround(stop),
558 scround(first), mesg);
559 if (display_in_cyl_units)
560 last *= units_per_sector;
561 if (n == 2 && !first) {
562 if (last >= stop2) {
563 whole_disk = 1;
564 last = stop2;
565 } else if (last > stop) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000566 printf(
567"You haven't covered the whole disk with the 3rd partition,\n"
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200568"but your value %u %s covers some other partition.\n"
569"Your entry has been changed to %u %s\n",
Denys Vlasenkod8e4ce02019-10-04 16:45:04 +0200570 scround(last), str_units(),
571 scround(stop), str_units());
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000572 last = stop;
573 }
574 } else if (!whole_disk && last > stop)
575 last = stop;
576
577 if (whole_disk)
578 sys = SUN_WHOLE_DISK;
579 set_sun_partition(n, first, last, sys);
580}
581
582static void
583sun_delete_partition(int i)
584{
585 unsigned int nsec;
586
587 if (i == 2
588 && sunlabel->infos[i].id == SUN_WHOLE_DISK
589 && !sunlabel->partitions[i].start_cylinder
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000590 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == g_heads * g_sectors * g_cylinders)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000591 printf("If you want to maintain SunOS/Solaris compatibility, "
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000592 "consider leaving this\n"
593 "partition as Whole disk (5), starting at 0, with %u "
Denis Vlasenkobd852072007-03-19 14:43:38 +0000594 "sectors\n", nsec);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000595 sunlabel->infos[i].id = 0;
596 sunlabel->partitions[i].num_sectors = 0;
597}
598
599static void
600sun_change_sysid(int i, int sys)
601{
602 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
603 read_maybe_empty(
Denis Vlasenkobd852072007-03-19 14:43:38 +0000604 "It is highly recommended that the partition at offset 0\n"
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000605 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
606 "there may destroy your partition table and bootblock.\n"
607 "Type YES if you're very sure you would like that partition\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +0000608 "tagged with 82 (Linux swap): ");
Denys Vlasenkoc1045492018-07-25 13:45:36 +0200609 if (strcmp(line_ptr, "YES") != 0)
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000610 return;
611 }
612 switch (sys) {
613 case SUNOS_SWAP:
614 case LINUX_SWAP:
615 /* swaps are not mountable by default */
616 sunlabel->infos[i].flags |= 0x01;
617 break;
618 default:
619 /* assume other types are mountable;
620 user can change it anyway */
621 sunlabel->infos[i].flags &= ~0x01;
622 break;
623 }
624 sunlabel->infos[i].id = sys;
625}
626
627static void
628sun_list_table(int xtra)
629{
630 int i, w;
631
632 w = strlen(disk_device);
633 if (xtra)
634 printf(
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200635 "\nDisk %s (Sun disk label): %u heads, %u sectors, %u rpm\n"
636 "%u cylinders, %u alternate cylinders, %u physical cylinders\n"
637 "%u extra sects/cyl, interleave %u:1\n"
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000638 "%s\n"
Denys Vlasenkod8e4ce02019-10-04 16:45:04 +0200639 "Units = %ss of %u * 512 bytes\n\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000640 disk_device, g_heads, g_sectors, SUN_SSWAP16(sunlabel->rspeed),
641 g_cylinders, SUN_SSWAP16(sunlabel->nacyl),
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000642 SUN_SSWAP16(sunlabel->pcylcount),
643 SUN_SSWAP16(sunlabel->sparecyl),
644 SUN_SSWAP16(sunlabel->ilfact),
645 (char *)sunlabel,
Denys Vlasenkod8e4ce02019-10-04 16:45:04 +0200646 str_units(), units_per_sector);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000647 else
648 printf(
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200649 "\nDisk %s (Sun disk label): %u heads, %u sectors, %u cylinders\n"
Denys Vlasenkod8e4ce02019-10-04 16:45:04 +0200650 "Units = %ss of %u * 512 bytes\n\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000651 disk_device, g_heads, g_sectors, g_cylinders,
Denys Vlasenkod8e4ce02019-10-04 16:45:04 +0200652 str_units(), units_per_sector);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000653
Denis Vlasenkobd852072007-03-19 14:43:38 +0000654 printf("%*s Flag Start End Blocks Id System\n",
655 w + 1, "Device");
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000656 for (i = 0; i < g_partitions; i++) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000657 if (sunlabel->partitions[i].num_sectors) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000658 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000659 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Denys Vlasenkoddf78502009-09-16 03:03:13 +0200660 printf("%s %c%c %9lu %9lu %9lu%c %2x %s\n",
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +0200661 partname(disk_device, i+1, w), /* device */
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000662 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
663 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
664 (long) scround(start), /* start */
665 (long) scround(start+len), /* end */
666 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
667 sunlabel->infos[i].id, /* type id */
668 partition_type(sunlabel->infos[i].id)); /* type name */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000669 }
670 }
671}
672
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000673#if ENABLE_FEATURE_FDISK_ADVANCED
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000674
675static void
676sun_set_alt_cyl(void)
677{
678 sunlabel->nacyl =
Denis Vlasenkobd852072007-03-19 14:43:38 +0000679 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
680 "Number of alternate cylinders"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000681}
682
683static void
684sun_set_ncyl(int cyl)
685{
686 sunlabel->ncyl = SUN_SSWAP16(cyl);
687}
688
689static void
690sun_set_xcyl(void)
691{
692 sunlabel->sparecyl =
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000693 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), g_sectors, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000694 "Extra sectors per cylinder"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000695}
696
697static void
698sun_set_ilfact(void)
699{
700 sunlabel->ilfact =
701 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000702 "Interleave factor"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000703}
704
705static void
706sun_set_rspeed(void)
707{
708 sunlabel->rspeed =
709 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000710 "Rotation speed (rpm)"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000711}
712
713static void
714sun_set_pcylcount(void)
715{
716 sunlabel->pcylcount =
717 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +0000718 "Number of physical cylinders"));
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000719}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000720#endif /* FEATURE_FDISK_ADVANCED */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000721
722static void
723sun_write_table(void)
724{
725 unsigned short *ush = (unsigned short *)sunlabel;
726 unsigned short csum = 0;
727
728 while (ush < (unsigned short *)(&sunlabel->csum))
729 csum ^= *ush++;
730 sunlabel->csum = csum;
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +0000731 write_sector(0, sunlabel);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000732}
733#endif /* SUN_LABEL */