]>
Commit | Line | Data |
---|---|---|
2b6fc908 KZ |
1 | /* |
2 | * fdisksunlabel.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. | |
7eda085c KZ |
8 | * |
9 | * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br> | |
10 | * Internationalization | |
2b6fc908 | 11 | */ |
2b6fc908 KZ |
12 | |
13 | #include <stdio.h> /* stderr */ | |
14 | #include <stdlib.h> /* uint */ | |
15 | #include <string.h> /* strstr */ | |
16 | #include <unistd.h> /* write */ | |
17 | #include <sys/ioctl.h> /* ioctl */ | |
18 | #include <sys/stat.h> /* stat */ | |
95f1bdee KZ |
19 | #include <sys/sysmacros.h> /* major */ |
20 | ||
7eda085c | 21 | #include "nls.h" |
2b6fc908 KZ |
22 | |
23 | #include <endian.h> | |
7eda085c KZ |
24 | #include "../defines.h" /* for HAVE_scsi_h */ |
25 | #ifdef HAVE_scsi_h | |
26 | #define u_char unsigned char | |
5c36a0eb | 27 | #include <scsi/scsi.h> /* SCSI_IOCTL_GET_IDLUN */ |
7eda085c | 28 | #undef u_char |
5c36a0eb | 29 | #endif |
2b6fc908 | 30 | #include <linux/major.h> /* FLOPPY_MAJOR */ |
2b6fc908 | 31 | |
7eda085c | 32 | #include "common.h" |
2b6fc908 KZ |
33 | #include "fdisk.h" |
34 | #include "fdisksunlabel.h" | |
35 | ||
5c36a0eb KZ |
36 | static int other_endian = 0; |
37 | static int scsi_disk = 0; | |
38 | static int floppy = 0; | |
2b6fc908 KZ |
39 | |
40 | #define LINUX_SWAP 0x82 | |
41 | #define LINUX_NATIVE 0x83 | |
42 | ||
43 | struct systypes sun_sys_types[] = { | |
7eda085c KZ |
44 | {0, N_("Empty")}, |
45 | {1, N_("Boot")}, | |
46 | {2, N_("SunOS root")}, | |
47 | {SUNOS_SWAP, N_("SunOS swap")}, | |
48 | {4, N_("SunOS usr")}, | |
49 | {WHOLE_DISK, N_("Whole disk")}, | |
50 | {6, N_("SunOS stand")}, | |
51 | {7, N_("SunOS var")}, | |
52 | {8, N_("SunOS home")}, | |
53 | {LINUX_SWAP, N_("Linux swap")}, | |
54 | {LINUX_NATIVE, N_("Linux native")}, | |
22853e4a | 55 | {0x8e, N_("Linux LVM")}, |
364cda48 KZ |
56 | {0xfd, N_("Linux raid autodetect")},/* New (2.2.x) raid partition |
57 | with autodetect using | |
58 | persistent superblock */ | |
2b6fc908 KZ |
59 | { 0, NULL } |
60 | }; | |
61 | ||
5c36a0eb | 62 | static inline unsigned short __swap16(unsigned short x) { |
2b6fc908 KZ |
63 | return (((__u16)(x) & 0xFF) << 8) | (((__u16)(x) & 0xFF00) >> 8); |
64 | } | |
5c36a0eb | 65 | static inline __u32 __swap32(__u32 x) { |
2b6fc908 KZ |
66 | return (((__u32)(x) & 0xFF) << 24) | (((__u32)(x) & 0xFF00) << 8) | (((__u32)(x) & 0xFF0000) >> 8) | (((__u32)(x) & 0xFF000000) >> 24); |
67 | } | |
68 | ||
69 | int | |
70 | get_num_sectors(struct sun_partition p) { | |
71 | return SSWAP32(p.num_sectors); | |
72 | } | |
73 | ||
66ee8158 KZ |
74 | #ifndef IDE0_MAJOR |
75 | #define IDE0_MAJOR 3 | |
76 | #endif | |
77 | #ifndef IDE1_MAJOR | |
78 | #define IDE1_MAJOR 22 | |
79 | #endif | |
2b6fc908 KZ |
80 | void guess_device_type(int fd) { |
81 | struct stat bootstat; | |
82 | ||
83 | if (fstat (fd, &bootstat) < 0) { | |
84 | scsi_disk = 0; | |
85 | floppy = 0; | |
86 | } else if (S_ISBLK(bootstat.st_mode) | |
95f1bdee KZ |
87 | && (major(bootstat.st_rdev) == IDE0_MAJOR || |
88 | major(bootstat.st_rdev) == IDE1_MAJOR)) { | |
2b6fc908 KZ |
89 | scsi_disk = 0; |
90 | floppy = 0; | |
91 | } else if (S_ISBLK(bootstat.st_mode) | |
95f1bdee | 92 | && major(bootstat.st_rdev) == FLOPPY_MAJOR) { |
2b6fc908 KZ |
93 | scsi_disk = 0; |
94 | floppy = 1; | |
95 | } else { | |
96 | scsi_disk = 1; | |
97 | floppy = 0; | |
98 | } | |
99 | } | |
100 | ||
22853e4a KZ |
101 | static void |
102 | set_sun_partition(int i, uint start, uint stop, int sysid) { | |
2b6fc908 KZ |
103 | sunlabel->infos[i].id = sysid; |
104 | sunlabel->partitions[i].start_cylinder = | |
105 | SSWAP32(start / (heads * sectors)); | |
106 | sunlabel->partitions[i].num_sectors = | |
107 | SSWAP32(stop - start); | |
22853e4a | 108 | set_changed(i); |
2b6fc908 KZ |
109 | } |
110 | ||
22853e4a KZ |
111 | void |
112 | sun_nolabel(void) { | |
5c36a0eb KZ |
113 | sun_label = 0; |
114 | sunlabel->magic = 0; | |
115 | partitions = 4; | |
116 | } | |
117 | ||
22853e4a KZ |
118 | int |
119 | check_sun_label(void) { | |
2b6fc908 KZ |
120 | unsigned short *ush; |
121 | int csum; | |
24f4bbff | 122 | |
5c36a0eb KZ |
123 | if (sunlabel->magic != SUN_LABEL_MAGIC && |
124 | sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) { | |
2b6fc908 KZ |
125 | sun_label = 0; |
126 | other_endian = 0; | |
127 | return 0; | |
128 | } | |
129 | other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED); | |
130 | ush = ((unsigned short *) (sunlabel + 1)) - 1; | |
131 | for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--; | |
132 | if (csum) { | |
7eda085c | 133 | fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n" |
2b6fc908 KZ |
134 | "Probably you'll have to set all the values,\n" |
135 | "e.g. heads, sectors, cylinders and partitions\n" | |
7eda085c | 136 | "or force a fresh label (s command in main menu)\n")); |
2b6fc908 KZ |
137 | } else { |
138 | heads = SSWAP16(sunlabel->ntrks); | |
139 | cylinders = SSWAP16(sunlabel->ncyl); | |
140 | sectors = SSWAP16(sunlabel->nsect); | |
141 | } | |
142 | update_units(); | |
143 | sun_label = 1; | |
144 | partitions = 8; | |
145 | return 1; | |
146 | } | |
147 | ||
148 | struct sun_predefined_drives { | |
149 | char *vendor; | |
150 | char *model; | |
151 | unsigned short sparecyl; | |
152 | unsigned short ncyl; | |
153 | unsigned short nacyl; | |
154 | unsigned short pcylcount; | |
155 | unsigned short ntrks; | |
156 | unsigned short nsect; | |
157 | unsigned short rspeed; | |
158 | } sun_drives[] = { | |
159 | {"Quantum","ProDrive 80S",1,832,2,834,6,34,3662}, | |
160 | {"Quantum","ProDrive 105S",1,974,2,1019,6,35,3662}, | |
161 | {"CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600}, | |
22853e4a KZ |
162 | {"IBM","DPES-31080",0,4901,2,4903,4,108,5400}, |
163 | {"IBM","DORS-32160",0,1015,2,1017,67,62,5400}, | |
164 | {"IBM","DNES-318350",0,11199,2,11474,10,320,7200}, | |
165 | {"SEAGATE","ST34371",0,3880,2,3882,16,135,7228}, | |
2b6fc908 KZ |
166 | {"","SUN0104",1,974,2,1019,6,35,3662}, |
167 | {"","SUN0207",4,1254,2,1272,9,36,3600}, | |
168 | {"","SUN0327",3,1545,2,1549,9,46,3600}, | |
169 | {"","SUN0340",0,1538,2,1544,6,72,4200}, | |
170 | {"","SUN0424",2,1151,2,2500,9,80,4400}, | |
171 | {"","SUN0535",0,1866,2,2500,7,80,5400}, | |
172 | {"","SUN0669",5,1614,2,1632,15,54,3600}, | |
173 | {"","SUN1.0G",5,1703,2,1931,15,80,3597}, | |
174 | {"","SUN1.05",0,2036,2,2038,14,72,5400}, | |
175 | {"","SUN1.3G",6,1965,2,3500,17,80,5400}, | |
176 | {"","SUN2.1G",0,2733,2,3500,19,80,5400}, | |
177 | {"IOMEGA","Jaz",0,1019,2,1021,64,32,5394}, | |
178 | }; | |
179 | ||
22853e4a KZ |
180 | static struct sun_predefined_drives * |
181 | sun_autoconfigure_scsi(void) { | |
5c36a0eb KZ |
182 | struct sun_predefined_drives *p = NULL; |
183 | ||
184 | #ifdef SCSI_IOCTL_GET_IDLUN | |
185 | unsigned int id[2]; | |
186 | char buffer[2048]; | |
187 | char buffer2[2048]; | |
188 | FILE *pfd; | |
189 | char *vendor; | |
190 | char *model; | |
191 | char *q; | |
192 | int i; | |
193 | ||
194 | if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) { | |
195 | sprintf(buffer, | |
196 | "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n", | |
197 | #if 0 | |
198 | ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33, | |
199 | #else | |
200 | /* This is very wrong (works only if you have one HBA), | |
201 | but I haven't found a way how to get hostno | |
202 | from the current kernel */ | |
203 | 0, | |
204 | #endif | |
205 | (id[0]>>16)&0xff, | |
206 | id[0]&0xff, | |
207 | (id[0]>>8)&0xff); | |
208 | pfd = fopen("/proc/scsi/scsi","r"); | |
209 | if (pfd) { | |
210 | while (fgets(buffer2,2048,pfd)) { | |
22853e4a | 211 | if (!strcmp(buffer, buffer2)) { |
5c36a0eb KZ |
212 | if (fgets(buffer2,2048,pfd)) { |
213 | q = strstr(buffer2,"Vendor: "); | |
214 | if (q) { | |
215 | q += 8; | |
216 | vendor = q; | |
22853e4a KZ |
217 | q = strstr(q," "); |
218 | *q++ = 0; /* truncate vendor name */ | |
219 | q = strstr(q,"Model: "); | |
5c36a0eb KZ |
220 | if (q) { |
221 | *q = 0; | |
22853e4a | 222 | q += 7; |
5c36a0eb KZ |
223 | model = q; |
224 | q = strstr(q," Rev: "); | |
225 | if (q) { | |
226 | *q = 0; | |
227 | for (i = 0; i < SIZE(sun_drives); i++) { | |
228 | if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor)) | |
229 | continue; | |
230 | if (!strstr(model, sun_drives[i].model)) | |
231 | continue; | |
7eda085c | 232 | printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model); |
5c36a0eb KZ |
233 | p = sun_drives + i; |
234 | break; | |
235 | } | |
236 | } | |
237 | } | |
238 | } | |
239 | } | |
240 | break; | |
241 | } | |
242 | } | |
243 | fclose(pfd); | |
244 | } | |
245 | } | |
246 | #endif | |
247 | return p; | |
248 | } | |
249 | ||
2b6fc908 KZ |
250 | void create_sunlabel(void) |
251 | { | |
252 | struct hd_geometry geometry; | |
253 | unsigned int ndiv; | |
254 | int i; | |
255 | unsigned char c; | |
256 | struct sun_predefined_drives *p = NULL; | |
257 | ||
7eda085c KZ |
258 | fprintf(stderr, |
259 | _("Building a new sun disklabel. Changes will remain in memory only,\n" | |
260 | "until you decide to write them. After that, of course, the previous\n" | |
261 | "content won't be recoverable.\n\n")); | |
2b6fc908 KZ |
262 | #if BYTE_ORDER == LITTLE_ENDIAN |
263 | other_endian = 1; | |
264 | #else | |
265 | other_endian = 0; | |
266 | #endif | |
22853e4a | 267 | memset(MBRbuffer, 0, sizeof(MBRbuffer)); |
2b6fc908 KZ |
268 | sunlabel->magic = SSWAP16(SUN_LABEL_MAGIC); |
269 | if (!floppy) { | |
7eda085c | 270 | puts(_("Drive type\n" |
2b6fc908 | 271 | " ? auto configure\n" |
7eda085c | 272 | " 0 custom (with hardware detected defaults)")); |
2b6fc908 KZ |
273 | for (i = 0; i < SIZE(sun_drives); i++) { |
274 | printf(" %c %s%s%s\n", | |
275 | i + 'a', sun_drives[i].vendor, | |
276 | (*sun_drives[i].vendor) ? " " : "", | |
277 | sun_drives[i].model); | |
278 | } | |
279 | for (;;) { | |
7eda085c | 280 | c = read_char(_("Select type (? for auto, 0 for custom): ")); |
2b6fc908 KZ |
281 | if (c >= 'a' && c < 'a' + SIZE(sun_drives)) { |
282 | p = sun_drives + c - 'a'; | |
283 | break; | |
284 | } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) { | |
285 | p = sun_drives + c - 'A'; | |
286 | break; | |
5c36a0eb | 287 | } else if (c == '0') { |
2b6fc908 | 288 | break; |
5c36a0eb KZ |
289 | } else if (c == '?' && scsi_disk) { |
290 | p = sun_autoconfigure_scsi(); | |
2b6fc908 | 291 | if (!p) |
7eda085c | 292 | printf(_("Autoconfigure failed.\n")); |
2b6fc908 KZ |
293 | else |
294 | break; | |
295 | } | |
296 | } | |
297 | } | |
298 | if (!p || floppy) { | |
299 | #ifdef HDIO_REQ | |
300 | if (!ioctl(fd, HDIO_REQ, &geometry)) { | |
301 | #else | |
302 | if (!ioctl(fd, HDIO_GETGEO, &geometry)) { | |
303 | #endif | |
304 | heads = geometry.heads; | |
305 | sectors = geometry.sectors; | |
306 | cylinders = geometry.cylinders; | |
307 | } else { | |
308 | heads = 0; | |
309 | sectors = 0; | |
310 | cylinders = 0; | |
311 | } | |
312 | if (floppy) { | |
313 | sunlabel->nacyl = 0; | |
314 | sunlabel->pcylcount = SSWAP16(cylinders); | |
315 | sunlabel->rspeed = SSWAP16(300); | |
316 | sunlabel->ilfact = SSWAP16(1); | |
317 | sunlabel->sparecyl = 0; | |
318 | } else { | |
7eda085c KZ |
319 | heads = read_int(1,heads,1024,0,_("Heads")); |
320 | sectors = read_int(1,sectors,1024,0,_("Sectors/track")); | |
2b6fc908 | 321 | if (cylinders) |
7eda085c | 322 | cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders")); |
2b6fc908 | 323 | else |
7eda085c | 324 | cylinders = read_int(1,0,65535,0,_("Cylinders")); |
5c36a0eb KZ |
325 | sunlabel->nacyl = |
326 | SSWAP16(read_int(0,2,65535,0, | |
7eda085c | 327 | _("Alternate cylinders"))); |
5c36a0eb KZ |
328 | sunlabel->pcylcount = |
329 | SSWAP16(read_int(0,cylinders+SSWAP16(sunlabel->nacyl), | |
7eda085c | 330 | 65535,0,_("Physical cylinders"))); |
5c36a0eb KZ |
331 | sunlabel->rspeed = |
332 | SSWAP16(read_int(1,5400,100000,0, | |
7eda085c | 333 | _("Rotation speed (rpm)"))); |
5c36a0eb | 334 | sunlabel->ilfact = |
7eda085c | 335 | SSWAP16(read_int(1,1,32,0,_("Interleave factor"))); |
5c36a0eb KZ |
336 | sunlabel->sparecyl = |
337 | SSWAP16(read_int(0,0,sectors,0, | |
7eda085c | 338 | _("Extra sectors per cylinder"))); |
2b6fc908 KZ |
339 | } |
340 | } else { | |
341 | sunlabel->sparecyl = SSWAP16(p->sparecyl); | |
342 | sunlabel->ncyl = SSWAP16(p->ncyl); | |
343 | sunlabel->nacyl = SSWAP16(p->nacyl); | |
344 | sunlabel->pcylcount = SSWAP16(p->pcylcount); | |
345 | sunlabel->ntrks = SSWAP16(p->ntrks); | |
346 | sunlabel->nsect = SSWAP16(p->nsect); | |
347 | sunlabel->rspeed = SSWAP16(p->rspeed); | |
22853e4a | 348 | sunlabel->ilfact = SSWAP16(1); |
2b6fc908 KZ |
349 | cylinders = p->ncyl; |
350 | heads = p->ntrks; | |
351 | sectors = p->nsect; | |
7eda085c | 352 | puts(_("You may change all the disk params from the x menu")); |
2b6fc908 | 353 | } |
22853e4a | 354 | |
c07ebfa1 KZ |
355 | snprintf(sunlabel->info, sizeof(sunlabel->info), |
356 | "%s%s%s cyl %d alt %d hd %d sec %d", | |
357 | p ? p->vendor : "", (p && *p->vendor) ? " " : "", | |
358 | p ? p->model | |
359 | : (floppy ? _("3,5\" floppy") : _("Linux custom")), | |
22853e4a KZ |
360 | cylinders, SSWAP16(sunlabel->nacyl), heads, sectors); |
361 | ||
2b6fc908 KZ |
362 | sunlabel->ntrks = SSWAP16(heads); |
363 | sunlabel->nsect = SSWAP16(sectors); | |
364 | sunlabel->ncyl = SSWAP16(cylinders); | |
365 | if (floppy) | |
366 | set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE); | |
367 | else { | |
368 | if (cylinders * heads * sectors >= 150 * 2048) { | |
369 | ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */ | |
370 | } else | |
371 | ndiv = cylinders * 2 / 3; | |
372 | set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE); | |
373 | set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP); | |
374 | sunlabel->infos[1].flags |= 0x01; /* Not mountable */ | |
375 | } | |
376 | set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK); | |
377 | { | |
378 | unsigned short *ush = (unsigned short *)sunlabel; | |
379 | unsigned short csum = 0; | |
380 | while(ush < (unsigned short *)(&sunlabel->csum)) | |
381 | csum ^= *ush++; | |
382 | sunlabel->csum = csum; | |
383 | } | |
22853e4a KZ |
384 | |
385 | set_all_unchanged(); | |
386 | set_changed(0); | |
e8f26419 | 387 | get_boot(create_empty_sun); |
2b6fc908 KZ |
388 | } |
389 | ||
22853e4a KZ |
390 | void |
391 | toggle_sunflags(int i, unsigned char mask) { | |
2b6fc908 KZ |
392 | if (sunlabel->infos[i].flags & mask) |
393 | sunlabel->infos[i].flags &= ~mask; | |
394 | else sunlabel->infos[i].flags |= mask; | |
22853e4a | 395 | set_changed(i); |
2b6fc908 KZ |
396 | } |
397 | ||
22853e4a KZ |
398 | static void |
399 | fetch_sun(uint *starts, uint *lens, uint *start, uint *stop) { | |
2b6fc908 KZ |
400 | int i, continuous = 1; |
401 | *start = 0; *stop = cylinders * heads * sectors; | |
402 | for (i = 0; i < partitions; i++) { | |
22853e4a KZ |
403 | if (sunlabel->partitions[i].num_sectors |
404 | && sunlabel->infos[i].id | |
405 | && sunlabel->infos[i].id != WHOLE_DISK) { | |
2b6fc908 KZ |
406 | starts[i] = SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors; |
407 | lens[i] = SSWAP32(sunlabel->partitions[i].num_sectors); | |
408 | if (continuous) { | |
409 | if (starts[i] == *start) | |
410 | *start += lens[i]; | |
411 | else if (starts[i] + lens[i] >= *stop) | |
412 | *stop = starts[i]; | |
413 | else | |
22853e4a KZ |
414 | continuous = 0; |
415 | /* There will be probably more gaps | |
416 | than one, so lets check afterwards */ | |
2b6fc908 KZ |
417 | } |
418 | } else { | |
419 | starts[i] = 0; | |
420 | lens[i] = 0; | |
421 | } | |
422 | } | |
423 | } | |
424 | ||
425 | static uint *verify_sun_starts; | |
22853e4a KZ |
426 | |
427 | static int | |
428 | verify_sun_cmp(int *a, int *b) { | |
2b6fc908 KZ |
429 | if (*a == -1) return 1; |
430 | if (*b == -1) return -1; | |
431 | if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1; | |
432 | return -1; | |
433 | } | |
434 | ||
22853e4a KZ |
435 | void |
436 | verify_sun(void) { | |
2b6fc908 KZ |
437 | uint starts[8], lens[8], start, stop; |
438 | int i,j,k,starto,endo; | |
439 | int array[8]; | |
440 | ||
441 | verify_sun_starts = starts; | |
442 | fetch_sun(starts,lens,&start,&stop); | |
443 | for (k = 0; k < 7; k++) { | |
444 | for (i = 0; i < 8; i++) { | |
445 | if (k && (lens[i] % (heads * sectors))) { | |
7eda085c | 446 | printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1); |
2b6fc908 KZ |
447 | } |
448 | if (lens[i]) { | |
449 | for (j = 0; j < i; j++) | |
450 | if (lens[j]) { | |
451 | if (starts[j] == starts[i]+lens[i]) { | |
452 | starts[j] = starts[i]; lens[j] += lens[i]; | |
453 | lens[i] = 0; | |
454 | } else if (starts[i] == starts[j]+lens[j]){ | |
455 | lens[j] += lens[i]; | |
456 | lens[i] = 0; | |
457 | } else if (!k) { | |
458 | if (starts[i] < starts[j]+lens[j] && | |
459 | starts[j] < starts[i]+lens[i]) { | |
460 | starto = starts[i]; | |
461 | if (starts[j] > starto) | |
462 | starto = starts[j]; | |
463 | endo = starts[i]+lens[i]; | |
464 | if (starts[j]+lens[j] < endo) | |
465 | endo = starts[j]+lens[j]; | |
7eda085c KZ |
466 | printf(_("Partition %d overlaps with others in " |
467 | "sectors %d-%d\n"), i+1, starto, endo); | |
2b6fc908 KZ |
468 | } |
469 | } | |
470 | } | |
471 | } | |
472 | } | |
473 | } | |
474 | for (i = 0; i < 8; i++) { | |
475 | if (lens[i]) | |
476 | array[i] = i; | |
477 | else | |
478 | array[i] = -1; | |
479 | } | |
480 | qsort(array,SIZE(array),sizeof(array[0]), | |
481 | (int (*)(const void *,const void *)) verify_sun_cmp); | |
482 | if (array[0] == -1) { | |
7eda085c | 483 | printf(_("No partitions defined\n")); |
2b6fc908 KZ |
484 | return; |
485 | } | |
486 | stop = cylinders * heads * sectors; | |
487 | if (starts[array[0]]) | |
7eda085c | 488 | printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]); |
2b6fc908 | 489 | for (i = 0; i < 7 && array[i+1] != -1; i++) { |
7eda085c | 490 | printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]); |
2b6fc908 KZ |
491 | } |
492 | start = starts[array[i]]+lens[array[i]]; | |
493 | if (start < stop) | |
7eda085c | 494 | printf(_("Unused gap - sectors %d-%d\n"),start,stop); |
2b6fc908 KZ |
495 | } |
496 | ||
22853e4a KZ |
497 | void |
498 | add_sun_partition(int n, int sys) { | |
2b6fc908 KZ |
499 | uint start, stop, stop2; |
500 | uint starts[8], lens[8]; | |
501 | int whole_disk = 0; | |
502 | ||
eb63b9b8 | 503 | char mesg[256]; |
2b6fc908 KZ |
504 | int i, first, last; |
505 | ||
506 | if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) { | |
7eda085c KZ |
507 | printf(_("Partition %d is already defined. Delete " |
508 | "it before re-adding it.\n"), n + 1); | |
2b6fc908 KZ |
509 | return; |
510 | } | |
511 | ||
512 | fetch_sun(starts,lens,&start,&stop); | |
513 | if (stop <= start) { | |
514 | if (n == 2) | |
515 | whole_disk = 1; | |
516 | else { | |
7eda085c KZ |
517 | printf(_("Other partitions already cover the whole disk.\nDelete " |
518 | "some/shrink them before retry.\n")); | |
2b6fc908 KZ |
519 | return; |
520 | } | |
521 | } | |
c07ebfa1 | 522 | snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR)); |
2b6fc908 KZ |
523 | for (;;) { |
524 | if (whole_disk) | |
5c36a0eb | 525 | first = read_int(0, 0, 0, 0, mesg); |
2b6fc908 | 526 | else |
5c36a0eb KZ |
527 | first = read_int(scround(start), scround(stop)+1, |
528 | scround(stop), 0, mesg); | |
7eda085c KZ |
529 | if (display_in_cyl_units) |
530 | first *= units_per_sector; | |
2b6fc908 | 531 | else |
5c36a0eb KZ |
532 | /* Starting sector has to be properly aligned */ |
533 | first = (first + heads * sectors - 1) / (heads * sectors); | |
534 | if (n == 2 && first != 0) | |
535 | printf ("\ | |
536 | It is highly recommended that the third partition covers the whole disk\n\ | |
537 | and is of type `Whole disk'\n"); | |
364cda48 KZ |
538 | /* ewt asks to add: "don't start a partition at cyl 0" |
539 | However, edmundo@rano.demon.co.uk writes: | |
540 | "In addition to having a Sun partition table, to be able to | |
541 | boot from the disc, the first partition, /dev/sdX1, must | |
542 | start at cylinder 0. This means that /dev/sdX1 contains | |
543 | the partition table and the boot block, as these are the | |
544 | first two sectors of the disc. Therefore you must be | |
545 | careful what you use /dev/sdX1 for. In particular, you must | |
546 | not use a partition starting at cylinder 0 for Linux swap, | |
547 | as that would overwrite the partition table and the boot | |
548 | block. You may, however, use such a partition for a UFS | |
549 | or EXT2 file system, as these file systems leave the first | |
550 | 1024 bytes undisturbed. */ | |
551 | /* On the other hand, one should not use partitions | |
552 | starting at block 0 in an md, or the label will | |
553 | be trashed. */ | |
2b6fc908 | 554 | for (i = 0; i < partitions; i++) |
5c36a0eb KZ |
555 | if (lens[i] && starts[i] <= first |
556 | && starts[i] + lens[i] > first) | |
2b6fc908 KZ |
557 | break; |
558 | if (i < partitions && !whole_disk) { | |
559 | if (n == 2 && !first) { | |
560 | whole_disk = 1; | |
561 | break; | |
562 | } | |
7eda085c | 563 | printf(_("Sector %d is already allocated\n"), first); |
2b6fc908 KZ |
564 | } else |
565 | break; | |
566 | } | |
567 | stop = cylinders * heads * sectors; | |
568 | stop2 = stop; | |
569 | for (i = 0; i < partitions; i++) { | |
570 | if (starts[i] > first && starts[i] < stop) | |
571 | stop = starts[i]; | |
572 | } | |
c07ebfa1 KZ |
573 | snprintf(mesg, sizeof(mesg), |
574 | _("Last %s or +size or +sizeM or +sizeK"), | |
575 | str_units(SINGULAR)); | |
2b6fc908 | 576 | if (whole_disk) |
5c36a0eb KZ |
577 | last = read_int(scround(stop2), scround(stop2), scround(stop2), |
578 | 0, mesg); | |
2b6fc908 KZ |
579 | else if (n == 2 && !first) |
580 | last = read_int(scround(first), scround(stop2), scround(stop2), | |
5c36a0eb | 581 | scround(first), mesg); |
2b6fc908 KZ |
582 | else |
583 | last = read_int(scround(first), scround(stop), scround(stop), | |
5c36a0eb | 584 | scround(first), mesg); |
7eda085c KZ |
585 | if (display_in_cyl_units) |
586 | last *= units_per_sector; | |
2b6fc908 KZ |
587 | if (n == 2 && !first) { |
588 | if (last >= stop2) { | |
589 | whole_disk = 1; | |
590 | last = stop2; | |
591 | } else if (last > stop) { | |
7eda085c KZ |
592 | printf ( |
593 | _("You haven't covered the whole disk with the 3rd partition, but your value\n" | |
594 | "%d %s covers some other partition. Your entry has been changed\n" | |
595 | "to %d %s\n"), | |
596 | scround(last), str_units(SINGULAR), | |
597 | scround(stop), str_units(SINGULAR)); | |
2b6fc908 KZ |
598 | last = stop; |
599 | } | |
600 | } else if (!whole_disk && last > stop) | |
601 | last = stop; | |
602 | ||
603 | if (whole_disk) sys = WHOLE_DISK; | |
604 | set_sun_partition(n, first, last, sys); | |
605 | } | |
606 | ||
607 | void | |
608 | sun_delete_partition(int i) { | |
609 | if (i == 2 && sunlabel->infos[i].id == WHOLE_DISK && | |
610 | !sunlabel->partitions[i].start_cylinder && | |
5c36a0eb KZ |
611 | SSWAP32(sunlabel->partitions[i].num_sectors) |
612 | == heads * sectors * cylinders) | |
7eda085c | 613 | printf(_("If you want to maintain SunOS/Solaris compatibility, " |
5c36a0eb KZ |
614 | "consider leaving this\n" |
615 | "partition as Whole disk (5), starting at 0, with %u " | |
7eda085c | 616 | "sectors\n"), |
5c36a0eb | 617 | (uint) SSWAP32(sunlabel->partitions[i].num_sectors)); |
2b6fc908 KZ |
618 | sunlabel->infos[i].id = 0; |
619 | sunlabel->partitions[i].num_sectors = 0; | |
620 | } | |
621 | ||
622 | void | |
623 | sun_change_sysid(int i, int sys) { | |
624 | if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) { | |
625 | read_chars( | |
7eda085c | 626 | _("It is highly recommended that the partition at offset 0\n" |
2b6fc908 KZ |
627 | "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n" |
628 | "there may destroy your partition table and bootblock.\n" | |
629 | "Type YES if you're very sure you would like that partition\n" | |
7eda085c | 630 | "tagged with 82 (Linux swap): ")); |
e8f26419 | 631 | if (strcmp (line_ptr, _("YES\n"))) |
2b6fc908 KZ |
632 | return; |
633 | } | |
634 | switch (sys) { | |
635 | case SUNOS_SWAP: | |
636 | case LINUX_SWAP: | |
637 | /* swaps are not mountable by default */ | |
638 | sunlabel->infos[i].flags |= 0x01; | |
639 | break; | |
640 | default: | |
641 | /* assume other types are mountable; | |
642 | user can change it anyway */ | |
643 | sunlabel->infos[i].flags &= ~0x01; | |
644 | break; | |
645 | } | |
646 | sunlabel->infos[i].id = sys; | |
647 | } | |
648 | ||
649 | void | |
650 | sun_list_table(int xtra) { | |
651 | int i, w; | |
652 | char *type; | |
653 | ||
654 | w = strlen(disk_device); | |
655 | if (xtra) | |
7eda085c KZ |
656 | printf( |
657 | _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n" | |
658 | "%d cylinders, %d alternate cylinders, %d physical cylinders\n" | |
659 | "%d extra sects/cyl, interleave %d:1\n" | |
660 | "%s\n" | |
661 | "Units = %s of %d * 512 bytes\n\n"), | |
2b6fc908 KZ |
662 | disk_device, heads, sectors, SSWAP16(sunlabel->rspeed), |
663 | cylinders, SSWAP16(sunlabel->nacyl), | |
664 | SSWAP16(sunlabel->pcylcount), | |
665 | SSWAP16(sunlabel->sparecyl), | |
666 | SSWAP16(sunlabel->ilfact), | |
667 | (char *)sunlabel, | |
7eda085c | 668 | str_units(PLURAL), units_per_sector); |
2b6fc908 | 669 | else |
7eda085c KZ |
670 | printf( |
671 | _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n" | |
672 | "Units = %s of %d * 512 bytes\n\n"), | |
2b6fc908 | 673 | disk_device, heads, sectors, cylinders, |
7eda085c | 674 | str_units(PLURAL), units_per_sector); |
2b6fc908 | 675 | |
7eda085c KZ |
676 | printf(_("%*s Flag Start End Blocks Id System\n"), |
677 | w + 1, _("Device")); | |
2b6fc908 KZ |
678 | for (i = 0 ; i < partitions; i++) { |
679 | if (sunlabel->partitions[i].num_sectors) { | |
680 | __u32 start = SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors; | |
681 | __u32 len = SSWAP32(sunlabel->partitions[i].num_sectors); | |
682 | printf( | |
63cccae4 KZ |
683 | "%s %c%c %9ld %9ld %9ld%c %2x %s\n", |
684 | /* device */ partname(disk_device, i+1, w), | |
2b6fc908 KZ |
685 | /* flags */ (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', |
686 | (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ', | |
5c36a0eb KZ |
687 | /* start */ (long) scround(start), |
688 | /* end */ (long) scround(start+len), | |
689 | /* odd flag on end */ (long) len / 2, len & 1 ? '+' : ' ', | |
2b6fc908 KZ |
690 | /* type id */ sunlabel->infos[i].id, |
691 | /* type name */ (type = partition_type(sunlabel->infos[i].id)) | |
7eda085c | 692 | ? type : _("Unknown")); |
2b6fc908 KZ |
693 | } |
694 | } | |
695 | } | |
696 | ||
697 | void | |
698 | sun_set_alt_cyl(void) { | |
5c36a0eb KZ |
699 | sunlabel->nacyl = |
700 | SSWAP16(read_int(0,SSWAP16(sunlabel->nacyl), 65535, 0, | |
7eda085c | 701 | _("Number of alternate cylinders"))); |
2b6fc908 KZ |
702 | } |
703 | ||
704 | void | |
705 | sun_set_ncyl(int cyl) { | |
706 | sunlabel->ncyl = SSWAP16(cyl); | |
707 | } | |
708 | ||
709 | void | |
710 | sun_set_xcyl(void) { | |
5c36a0eb KZ |
711 | sunlabel->sparecyl = |
712 | SSWAP16(read_int(0, SSWAP16(sunlabel->sparecyl), sectors, 0, | |
7eda085c | 713 | _("Extra sectors per cylinder"))); |
2b6fc908 KZ |
714 | } |
715 | ||
716 | void | |
717 | sun_set_ilfact(void) { | |
5c36a0eb KZ |
718 | sunlabel->ilfact = |
719 | SSWAP16(read_int(1, SSWAP16(sunlabel->ilfact), 32, 0, | |
7eda085c | 720 | _("Interleave factor"))); |
2b6fc908 KZ |
721 | } |
722 | ||
723 | void | |
724 | sun_set_rspeed(void) { | |
5c36a0eb KZ |
725 | sunlabel->rspeed = |
726 | SSWAP16(read_int(1, SSWAP16(sunlabel->rspeed), 100000, 0, | |
7eda085c | 727 | _("Rotation speed (rpm)"))); |
2b6fc908 KZ |
728 | } |
729 | ||
730 | void | |
731 | sun_set_pcylcount(void) { | |
5c36a0eb KZ |
732 | sunlabel->pcylcount = |
733 | SSWAP16(read_int(0, SSWAP16(sunlabel->pcylcount), 65535, 0, | |
7eda085c | 734 | _("Number of physical cylinders"))); |
2b6fc908 KZ |
735 | } |
736 | ||
737 | void | |
738 | sun_write_table(void) { | |
739 | unsigned short *ush = (unsigned short *)sunlabel; | |
740 | unsigned short csum = 0; | |
741 | ||
742 | while(ush < (unsigned short *)(&sunlabel->csum)) | |
743 | csum ^= *ush++; | |
744 | sunlabel->csum = csum; | |
745 | if (lseek(fd, 0, SEEK_SET) < 0) | |
746 | fatal(unable_to_seek); | |
747 | if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE) | |
748 | fatal(unable_to_write); | |
749 | } |