source: MondoRescue/branches/stable/mondo/src/mondorestore/mondo-prep.c@ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

  • Property svn:keywords set to Id
File size: 70.2 KB
Line 
1/***************************************************************************
2 * $Id: mondo-prep.c 1770 2007-11-06 10:01:53Z bruno $
3*/
4
5/**
6 * @file
7 * Functions for prepping hard drives: partitioning, formatting, etc.
8 */
9
10
11#include "my-stuff.h"
12#include "mondostructures.h"
13#include "mondoprep.h"
14#include "libmondo.h"
15#include "mondo-rstr-tools-EXT.h"
16
17#include <sys/ioctl.h>
18#include <linux/hdreg.h>
19#include <math.h>
20#include <unistd.h>
21#include "mr_mem.h"
22#include "mr_msg.h"
23#include "mr_gettext.h"
24
25
26#define FDISK_LOG "/tmp/fdisk.log"
27
28#ifdef __FreeBSD__
29#define DKTYPENAMES
30#define FSTYPENAMES
31#include <sys/disklabel.h>
32#include <sys/disk.h>
33#include <err.h>
34#include <libgen.h>
35#define OSSWAP(x,y) y
36#else
37#define OSSWAP(x,y) x
38#endif
39
40#define ARCHIVES_PATH MNT_CDROM"/archives"
41#define MONDO_WAS_HERE "MONDOWOZEREMONDOWOZEREMONDOWOZEREhahahaMOJOJOJO"
42
43//static char cvsid[] = "$Id: mondo-prep.c 1770 2007-11-06 10:01:53Z bruno $";
44
45extern char *g_mountlist_fname;
46extern long g_current_progress, g_maximum_progress;
47extern bool g_text_mode;
48extern void pause_for_N_seconds(int, char *);
49extern char *MONDO_LOGFILE;
50
51FILE *g_fprep = NULL;
52int g_partition_table_locked_up = 0;
53
54
55void wipe_MBRs_and_reboot_if_necessary(struct mountlist_itself *mountlist)
56{
57 char *command = NULL;
58 int lino = 0;
59 int res = 0;
60 FILE *fout = NULL;
61 char *buf = NULL;
62 struct list_of_disks *drivelist = NULL;
63
64 // If LVMs are present and a zero-and-reboot wasn't recently undertaken
65 // then zero & insist on reboot.
66 if (does_file_exist("/tmp/i-want-my-lvm")) // FIXME - cheating :)
67 {
68 drivelist = mr_malloc(sizeof(struct list_of_disks));
69 make_list_of_drives_in_mountlist(mountlist, drivelist);
70 for (lino = 0; lino < drivelist->entries; lino++) {
71 mr_asprintf(&command,
72 "dd if=%s bs=512 count=1 2> /dev/null | grep \"%s\"",
73 drivelist->el[lino].device, MONDO_WAS_HERE);
74 res = run_program_and_log_output(command, 1);
75 mr_free(command);
76 if (!res) {
77 mr_msg(1, "Found MONDO_WAS_HERE marker on drive#%d (%s)",
78 lino, drivelist->el[lino].device);
79 break;
80 }
81 }
82
83 if (lino == drivelist->entries) {
84 // zero & reboot
85 log_to_screen
86 (_
87 ("I am sorry for the inconvenience but I must ask you to reboot."));
88 log_to_screen(_
89 ("I need to reset the Master Boot Record; in order to be"));
90 log_to_screen(_
91 ("sure the kernel notices, I must reboot after doing it."));
92 log_to_screen("Please hit 'Enter' to reboot.");
93 for (lino = 0; lino < drivelist->entries; lino++) {
94 mr_asprintf(&buf, "%s\n", MONDO_WAS_HERE);
95 fout = fopen(drivelist->el[lino].device, "w+");
96 if (!fout) {
97 mr_msg(1, "Unable to open+wipe %s",
98 drivelist->el[lino].device);
99 } else {
100 if (1 != fwrite(buf, strlen(buf)+1, 1, fout)) {
101 mr_msg(1, "Failed to wipe %s",
102 drivelist->el[lino].device);
103 } else {
104 mr_msg(1, "Successfully wiped %s",
105 drivelist->el[lino].device);
106 }
107 fclose(fout);
108 }
109 mr_free(buf);
110 }
111 sync();
112 sync();
113 sync();
114 popup_and_OK
115 (_
116 ("I must reboot now. Please leave the boot media in the drive and repeat your actions - e.g. type 'nuke' - and it should work fine."));
117 system("reboot");
118 }
119 }
120// Still here? Cool!
121 mr_msg(1, "Cool. I didn't have to wipe anything.");
122}
123
124
125int fput_string_one_char_at_a_time(FILE * fout, char *str)
126{
127 int i = 0, j = 0;
128 FILE *fq = NULL;
129
130 if (ferror(fout)) {
131 return (-1);
132 }
133 mr_msg(5, "Writing string '%s', one char at a time", str);
134 j = strlen(str);
135 for (i = 0; i < j; i++) {
136 mr_msg(6, "Writing %d ('%c')", str[i], str[i]);
137 if ((fq = fopen(FDISK_LOG, "a+"))) {
138 fputc(str[i], fq);
139 fclose(fq);
140 }
141 fputc(str[i], fout);
142 fflush(fout);
143 usleep(1000L * 100L);
144 if (str[i] < 32) {
145 usleep(1000L * 10L);
146 }
147 }
148 mr_msg(5, "Returning");
149
150 return (i);
151}
152
153
154/**
155 * @addtogroup prepGroup
156 * @{
157 */
158/**
159 * Execute the commands in /tmp/i-want-my-lvm.
160 * These should probably be commands to set up LVM.
161 * @return The number of errors encountered (0 for success).
162 */
163int do_my_funky_lvm_stuff(bool just_erase_existing_volumes,
164 bool vacuum_pack)
165{
166 char *tmp = NULL;
167 char *tmp1 = NULL;
168 char *incoming = NULL;
169 char *command = NULL;
170 char *lvscan_sz = NULL;
171 char *lvremove_sz = NULL;
172 char *pvscan_sz = NULL;
173 char *vgscan_sz = NULL;
174 char *vgchange_sz = NULL;
175 char *vgremove_sz = NULL;
176 char *p = NULL;
177 char *q = NULL;
178
179 /** int ***************************************************/
180 int retval = 0;
181 int res = 0;
182 int i = 0;
183 int lvmversion = 1;
184 long extents = 0L;
185 fpos_t orig_pos;
186 size_t n = 0;
187 size_t n1 = 0;
188
189 /** pointers **********************************************/
190 FILE *fin = NULL;
191
192 /** end *****************************************************/
193
194#ifdef __FreeBSD__
195 return (0);
196#endif
197
198 if (!(fin = fopen("/tmp/i-want-my-lvm", "r"))) {
199 log_OS_error("/tmp/i-want-my-lvm");
200 return (1);
201 }
202
203 iamhere("STARTING");
204 mr_msg(1, "OK, opened i-want-my-lvm. Shutting down LVM volumes...");
205 if (find_home_of_exe("lvm")) // found it :) cool
206 {
207 mr_asprintf(&lvscan_sz, "lvm lvscan");
208 mr_asprintf(&lvremove_sz, "lvm lvremove");
209 mr_asprintf(&vgscan_sz, "lvm vgscan");
210 mr_asprintf(&pvscan_sz, "lvm pvscan");
211 mr_asprintf(&vgchange_sz, "lvm vgchange");
212 mr_asprintf(&vgremove_sz, "lvm vgremove");
213 } else {
214 mr_asprintf(&lvscan_sz, "lvscan");
215 mr_asprintf(&lvremove_sz, "lvremove");
216 mr_asprintf(&vgscan_sz, "vgscan");
217 mr_asprintf(&pvscan_sz, "pvscan");
218 mr_asprintf(&vgchange_sz, "vgchange");
219 mr_asprintf(&vgremove_sz, "vgremove");
220 }
221 mr_asprintf(&command,
222 "for i in `%s | cut -d\"'\" -f2 | sort -r` ; do echo \"Shutting down lv $i\" >> %s ; %s -f $i; done", lvscan_sz, MONDO_LOGFILE, lvremove_sz);
223 mr_free(lvscan_sz);
224 mr_free(lvremove_sz);
225
226 run_program_and_log_output(command, 5);
227 mr_free(command);
228
229 sleep(1);
230 mr_asprintf(&command,
231 "for i in `%s | grep -i lvm | cut -d'\"' -f2` ; do %s -a n $i ; %s $i; echo \"Shutting down vg $i\" >> %s ; done", vgscan_sz, vgchange_sz, vgremove_sz, MONDO_LOGFILE);
232 mr_free(vgchange_sz);
233 mr_free(vgremove_sz);
234
235 run_program_and_log_output(command, 5);
236 mr_free(command);
237
238 if (just_erase_existing_volumes) {
239 paranoid_fclose(fin);
240 mr_msg(1, "Closed i-want-my-lvm. Finished erasing LVMs.");
241 sync();
242 sync();
243 sync();
244 sleep(1);
245 iamhere("ENDING");
246 mr_msg(1, "Not many errors. Returning 0.");
247 return (0);
248 }
249
250 mr_msg(1, "OK, rewound i-want-my-lvm. Doing funky stuff...");
251 rewind(fin);
252 for (mr_getline(&incoming, &n1, fin); !feof(fin); mr_getline(&incoming, &n1, fin)) {
253 fgetpos(fin, &orig_pos);
254 /* we want to execute lines begining with a # */
255 if (incoming[0] != '#') {
256 continue;
257 }
258 if ((p = strstr(incoming, "vgcreate"))) {
259 // include next line(s) if they end in /dev (cos we've got a broken i-want-my-lvm)
260 for (mr_getline(&tmp, &n, fin); !feof(fin); mr_getline(&tmp, &n, fin)) {
261 if (tmp[0] == '#') {
262 fsetpos(fin, &orig_pos);
263 break;
264 } else {
265 fgetpos(fin, &orig_pos);
266 mr_strcat(incoming, tmp);
267 }
268 }
269 mr_free(tmp);
270
271 for (q = incoming; *q != '\0'; q++) {
272 if (*q < 32) {
273 *q = ' ';
274 }
275 }
276 mr_asprintf(&tmp1, p + strlen("vgcreate") + 1);
277 for (q = tmp1; *q > 32; q++);
278 *q = '\0';
279 mr_msg(1, "Deleting old entries at /dev/%s", tmp1);
280 mr_asprintf(&command, "rm -Rf /dev/%s", tmp1);
281 mr_free(tmp1);
282
283 run_program_and_log_output(command, 1);
284 mr_free(command);
285
286 run_program_and_log_output(vgscan_sz, 1);
287 run_program_and_log_output(pvscan_sz, 1);
288 mr_msg(3,
289 "After working around potentially broken i-want-my-lvm, incoming[] is now '%s'",
290 incoming);
291 }
292 for (p = incoming + 1; *p == ' '; p++);
293 mr_asprintf(&command,p);
294 for (p = command; *p != '\0'; p++);
295 for (; (*(p - 1) < 32) && (p > command) ; p--);
296 *p = '\0';
297
298 /* BERLIOS: we should rather define LVMv1 or v2 and use it */
299 res = run_program_and_log_output(command, 5);
300 if (res > 0 && (p = strstr(command, "lvm "))) {
301 *p = *(p + 1) = *(p + 2) = ' ';
302 res = run_program_and_log_output(command, 5);
303 }
304 mr_msg(0, "%s --> %d", command, res);
305 if (res > 0) {
306 res = 1;
307 }
308 if (res && strstr(command, "lvcreate") && vacuum_pack) {
309 res = 0;
310 if (strstr(command, "lvm lvcreate"))
311 lvmversion = 2;
312 if (lvmversion == 2) {
313 mr_asprintf(&tmp1, "tail -n5 %s | grep Insufficient | tail -n1", MONDO_LOGFILE);
314 mr_asprintf(&tmp, call_program_and_get_last_line_of_output(tmp1));
315 free(tmp1);
316 } else {
317 mr_asprintf(&tmp1, "tail -n5 %s | grep lvcreate | tail -n1", MONDO_LOGFILE);
318 mr_asprintf(&tmp, call_program_and_get_last_line_of_output(tmp1));
319 free(tmp1);
320 }
321 for (p = tmp; *p != '\0' && !isdigit(*p); p++);
322 extents = atol(p);
323 mr_msg(5, "p='%s' --> extents=%ld", p, extents);
324 mr_free(tmp);
325
326 p = strstr(command, "-L");
327 if (!p) {
328 mr_msg(0, "Fiddlesticks. '%s' returned %d", command, res);
329 } else {
330 if (lvmversion == 2) {
331 *p++ = '-';
332 *p++ = 'l';
333 *p++ = ' ';
334 for (q = p; *q != ' '; q++) {
335 *q = ' ';
336 }
337 /* BERLIOS: Dangerous: no size control !! */
338 sprintf(p, "%ld", extents);
339 i = strlen(p);
340 *(p + i) = ' ';
341 } else {
342 p++;
343 p++;
344 p++;
345 for (q = p; *q != ' '; q++) {
346 *(q - 1) = ' ';
347 }
348 /* BERLIOS: Dangerous: no size control !! */
349 sprintf(p, "%ld%c", extents, 'm');
350 i = strlen(p);
351 *(p + i) = ' ';
352 }
353 mr_msg(5, "Retrying with '%s'", command);
354 res = run_program_and_log_output(command, 5);
355 if (res > 0) {
356 res = 1;
357 }
358 if (g_fprep) {
359 fprintf(g_fprep, "%s\n", command);
360 }
361 mr_msg(0, "%s --> %d", command, res);
362 if (!res) {
363 mr_msg(5, "Yep! This time, it succeeded.");
364 }
365 }
366 }
367 if (strstr(command, "vgcreate")) {
368 mr_msg(0, "In case you're interested...");
369 run_program_and_log_output(vgscan_sz, 1);
370 run_program_and_log_output(pvscan_sz, 1);
371 }
372 if (res != 0 && !strstr(command, "insmod")) {
373 retval++;
374 }
375 mr_asprintf(&tmp, "echo \"%s\" >> /tmp/out.sh", command);
376 system(tmp);
377 mr_free(tmp);
378 sleep(1);
379 }
380 paranoid_fclose(fin);
381 mr_free(vgscan_sz);
382 mr_free(pvscan_sz);
383 mr_free(command);
384 mr_free(incoming);
385
386 mr_msg(1, "Closed i-want-my-lvm. Finished doing funky stuff.");
387 sync();
388 sync();
389 sync();
390 sleep(1);
391 iamhere("ENDING");
392 if (retval > 2) {
393 mr_msg(1, "%d errors. I'm reporting this.", retval);
394 return (retval);
395 } else {
396 mr_msg(1, "Not many errors. Returning 0.");
397 return (0);
398 }
399}
400
401
402/**
403 * Add RAID partitions while copying @p old_mountlist to @p new_mountlist.
404 * We go through @p old_mountlist and check if any RAID device (/dev/md? on Linux)
405 * is in it; if it is, then we put the disks contained within that RAID device
406 * into the mountlist as well.
407 * @param old_mountlist The mountlist to read.
408 * @param new_mountlist The mountlist to write, with the RAID partitions added.
409 * @return 0 for success, nonzero for failure.
410 */
411int extrapolate_mountlist_to_include_raid_partitions(struct mountlist_itself
412 *new_mountlist, struct mountlist_itself
413 *old_mountlist)
414{
415 FILE *fin = NULL;
416 int lino = 0;
417 int j = 0;
418 char *incoming = NULL;
419 char *p = NULL;
420 size_t n = 0;
421
422 /** init *************************************************************/
423 new_mountlist->entries = 0;
424
425 /** end **************************************************************/
426
427 assert(new_mountlist != NULL);
428 assert(old_mountlist != NULL);
429
430#ifdef __FreeBSD__
431 log_to_screen
432 (_
433 ("I don't know how to extrapolate the mountlist on FreeBSD. Sorry."));
434 return (1);
435#endif
436
437 for (lino = 0; lino < old_mountlist->entries; lino++) {
438 if (strstr(old_mountlist->el[lino].device, RAID_DEVICE_STUB)) // raid
439 {
440 if (!does_file_exist("/etc/raidtab")) {
441 log_to_screen
442 (_
443 ("Cannot find /etc/raidtab - cannot extrapolate the fdisk entries"));
444 finish(1);
445 }
446 if (!(fin = fopen("/etc/raidtab", "r"))) {
447 log_OS_error("Cannot open /etc/raidtab");
448 finish(1);
449 }
450 for (mr_getline(&incoming, &n, fin); !feof(fin)
451 && !strstr(incoming, old_mountlist->el[lino].device);
452 mr_getline(&incoming, &n, fin));
453 if (!feof(fin)) {
454 log_it("Investigating %s",
455 old_mountlist->el[lino].device);
456 for (mr_getline(&incoming, &n, fin); !feof(fin)
457 && !strstr(incoming, "raiddev");
458 mr_getline(&incoming, &n, fin)) {
459 if (strstr(incoming, OSSWAP("device", "drive"))
460 && !strchr(incoming, '#')) {
461 for (p = incoming + strlen(incoming);
462 (*(p - 1) <= 32) && (p >= incoming) ; p--);
463 *p = '\0';
464 for (p--; (p >= incoming) && (*(p - 1) > 32); p--);
465 log_it("Extrapolating %s", p);
466 for (j = 0;
467 j < new_mountlist->entries
468 && strcmp(new_mountlist->el[j].device, p);
469 j++);
470 if (j >= new_mountlist->entries) {
471 strcpy(new_mountlist->
472 el[new_mountlist->entries].device, p);
473 strcpy(new_mountlist->
474 el[new_mountlist->entries].mountpoint,
475 "raid");
476 strcpy(new_mountlist->
477 el[new_mountlist->entries].format,
478 "raid");
479 new_mountlist->el[new_mountlist->entries].
480 size = old_mountlist->el[lino].size;
481 new_mountlist->entries++;
482 } else {
483 log_it("Not adding %s to mountlist: it's already there", p);
484 }
485 }
486 }
487 }
488 mr_free(incoming);
489
490 paranoid_fclose(fin);
491 } else {
492 strcpy(new_mountlist->el[new_mountlist->entries].device,
493 old_mountlist->el[lino].device);
494 strcpy(new_mountlist->el[new_mountlist->entries].mountpoint,
495 old_mountlist->el[lino].mountpoint);
496 strcpy(new_mountlist->el[new_mountlist->entries].format,
497 old_mountlist->el[lino].format);
498 new_mountlist->el[new_mountlist->entries].size =
499 old_mountlist->el[lino].size;
500 new_mountlist->entries++;
501 }
502 }
503 return (0);
504}
505
506
507/**
508 * Create @p RAID device using information from @p structure.
509 * This will create the specified RAID devive using information provided in
510 * raidlist by means of the mdadm tool.
511 * @param raidlist The structure containing all RAID information
512 * @param device The RAID device to create.
513 * @return 0 for success, nonzero for failure.
514 */
515int create_raid_device_via_mdadm(struct raidlist_itself *raidlist, char *device)
516{
517 /** int **************************************************************/
518 int i = 0;
519 int j = 0;
520 int res = 0;
521
522 /** buffers ***********************************************************/
523 char *devices = NULL;
524 char *level = NULL;
525 char *program = NULL;
526
527 // leave straight away if raidlist is initial or has no entries
528 if (!raidlist || raidlist->entries == 0) {
529 mr_msg(1, "No RAID arrays found.");
530 return 1;
531 } else {
532 mr_msg(1, "%d RAID arrays found.", raidlist->entries);
533 }
534 // find raidlist entry for requested device
535 for (i = 0; i < raidlist->entries; i++) {
536 if (!strcmp(raidlist->el[i].raid_device, device)) break;
537 }
538 // check whether RAID device was found in raidlist
539 if (i == raidlist->entries) {
540 mr_msg(1, "RAID device %s not found in list.", device);
541 return 1;
542 }
543 // create device list from normal disks followed by spare ones
544 mr_asprintf(&devices, raidlist->el[i].data_disks.el[0].device);
545 for (j = 1; j < raidlist->el[i].data_disks.entries; j++) {
546 mr_strcat(devices, " %s", raidlist->el[i].data_disks.el[j].device);
547 }
548 for (j = 0; j < raidlist->el[i].spare_disks.entries; j++) {
549 mr_strcat(devices, " %s", raidlist->el[i].spare_disks.el[j].device);
550 }
551 // translate RAID level
552 if (raidlist->el[i].raid_level == -2) {
553 mr_asprintf(&level, "multipath");
554 } else if (raidlist->el[i].raid_level == -1) {
555 mr_asprintf(&level, "linear");
556 } else {
557 mr_asprintf(&level, "raid%d", raidlist->el[i].raid_level);
558 }
559 // create RAID device:
560 // - RAID device, number of devices and devices mandatory
561 // - parity algorithm, chunk size and spare devices optional
562 // - faulty devices ignored
563 // - persistent superblock always used as this is recommended
564 mr_asprintf(&program,
565 "mdadm --create --force --run --auto=yes %s --level=%s --raid-devices=%d",
566 raidlist->el[i].raid_device, level,
567 raidlist->el[i].data_disks.entries);
568 mr_free(level);
569 if (raidlist->el[i].parity != -1) {
570 switch(raidlist->el[i].parity) {
571 case 0:
572 mr_strcat(program, " --parity=%s", "la");
573 break;
574 case 1:
575 mr_strcat(program, " --parity=%s", "ra");
576 break;
577 case 2:
578 mr_strcat(program, " --parity=%s", "ls");
579 break;
580 case 3:
581 mr_strcat(program, " --parity=%s", "rs");
582 break;
583 default:
584 fatal_error("Unknown RAID parity algorithm.");
585 break;
586 }
587 }
588 if (raidlist->el[i].chunk_size != -1) {
589 mr_strcat(program, " --chunk=%d", raidlist->el[i].chunk_size);
590 }
591 if (raidlist->el[i].spare_disks.entries > 0) {
592 mr_strcat(program, " --spare-devices=%d", raidlist->el[i].spare_disks.entries);
593 }
594 mr_strcat(program, " %s", devices);
595 res = run_program_and_log_output(program, 1);
596 // free memory
597 mr_free(devices);
598 mr_free(program);
599 // return to calling instance
600 return(res);
601}
602
603
604/**
605 * Format @p device as a @p format filesystem.
606 * This will use the format command returned by which_format_command_do_i_need().
607 * If @p device is an LVM PV, it will not be formatted, and LVM will be started
608 * (if not already done). If it's an imagedev, software RAID component, or
609 * (under BSD) swap partition, no format will be done.
610 * @param device The device to format.
611 * @param format The filesystem type to format it as.
612 * @return 0 for success, nonzero for failure.
613 */
614int format_device(char *device, char *format, struct raidlist_itself *raidlist)
615{
616 /** int **************************************************************/
617 int res = 0;
618 int retval = 0;
619#ifdef __FreeBSD__
620 static bool vinum_started_yet = FALSE;
621#endif
622
623 /** buffers ***********************************************************/
624 char *program = NULL;
625 char *program2 = NULL;
626 char *tmp = NULL;
627#ifdef __FreeBSD__
628 char *line = NULL;
629 char *status = NULL;
630 FILE *pin = NULL;
631 FILE *fin = NULL;
632 size_t n = 0;
633 size_t n1 = 0;
634#endif
635
636 /** end ****************************************************************/
637
638 assert_string_is_neither_NULL_nor_zerolength(device);
639 assert(format != NULL);
640
641 if (strstr(format, "raid")) { // do not form RAID disks; do it to /dev/md* instead
642 log_it("Not formatting %s (it is a RAID disk)", device);
643 return (0);
644 }
645#ifdef __FreeBSD__
646 if (strcmp(format, "swap") == 0) {
647 log_it("Not formatting %s - it's swap", device);
648 return (0);
649 }
650#endif
651 if (strlen(format) <= 2) {
652 mr_asprintf(&tmp,
653 "%s has a really small format type ('%s') - this is probably a hexadecimal string, which would suggest the partition is an image --- I shouldn't format it",
654 device, format);
655 return (0);
656 }
657 if (is_this_device_mounted(device)) {
658 log_to_screen(_("%s is mounted - cannot format it "), device);
659 return (1);
660 }
661 if (strstr(device, RAID_DEVICE_STUB)) {
662 newtSuspend();
663#ifdef __FreeBSD__
664 if (!vinum_started_yet) {
665 if (!does_file_exist("/tmp/raidconf.txt")) {
666 log_to_screen
667 (_
668 ("/tmp/raidconf.txt does not exist. I therefore cannot start Vinum."));
669 } else {
670 int res;
671 res =
672 run_program_and_log_output
673 ("vinum create /tmp/raidconf.txt", TRUE);
674 if (res) {
675 log_to_screen
676 (_
677 ("`vinum create /tmp/raidconf.txt' returned errors. Please fix them and re-run mondorestore."));
678 finish(1);
679 }
680 vinum_started_yet = TRUE;
681 }
682 }
683
684 if (vinum_started_yet) {
685 log_to_screen(_("Initializing Vinum device %s (this may take a *long* time)"),
686 device);
687
688 /* format raid partition */
689 mr_asprintf(&program,
690 "for plex in `vinum lv -r %s | grep '^P' | tr '\t' ' ' | tr -s ' ' | cut -d' ' -f2`; do echo $plex; done > /tmp/plexes",
691 basename(device));
692 system(program);
693
694 if (g_fprep) {
695 fprintf(g_fprep, "%s\n", program);
696 }
697 mr_free(program);
698
699 fin = fopen("/tmp/plexes", "r");
700 while (mr_getline(&line, &n, fin)) {
701 if (strchr(line, '\n'))
702 *(strchr(line, '\n')) = '\0'; // get rid of the \n on the end
703
704 mr_asprintf(&tmp, "Initializing plex: %s", line);
705 open_evalcall_form(tmp);
706 mr_free(tmp);
707
708 mr_asprintf(&tmp, "vinum init %s", line);
709 system(tmp);
710 mr_free(tmp);
711
712 while (1) {
713 mr_asprintf(&tmp,
714 "vinum lp -r %s | grep '^S' | head -1 | tr -s ' ' | cut -d: -f2 | cut -f1 | sed 's/^ //' | sed 's/I //' | sed 's/%%//'",
715 line);
716 pin = popen(tmp, "r");
717 mr_free(tmp);
718
719 mr_getline(&status, &n1, pin);
720 pclose(pin);
721
722 if (!strcmp(status, "up")) {
723 break; /* it's done */
724 }
725 update_evalcall_form(atoi(status));
726 usleep(250000);
727 mr_free(status);
728 }
729 close_evalcall_form();
730 }
731 mr_free(line);
732
733 fclose(fin);
734 unlink("/tmp/plexes");
735 /* retval+=res; */
736 }
737#else
738 log_to_screen(_("Initializing RAID device %s"), device);
739
740 // Shouldn't be necessary.
741 log_to_screen(_("Stopping %s"), device);
742 stop_raid_device(device);
743 sync();
744 sleep(1);
745
746 mr_msg(1, "Making %s", device);
747 // use mkraid if it exists, otherwise use mdadm
748 if (run_program_and_log_output("which mkraid", FALSE)) {
749 res = create_raid_device_via_mdadm(raidlist, device);
750 mr_msg(1, "Creating RAID device %s via mdadm returned %d", device, res);
751 } else {
752 mr_asprintf(&program, "mkraid --really-force %s", device);
753 res = run_program_and_log_output(program, 1);
754 mr_msg(1, "%s returned %d", program, res);
755 sync();
756 sleep(3);
757 start_raid_device(device);
758 if (g_fprep) {
759 fprintf(g_fprep, "%s\n", program);
760 }
761 mr_free(program);
762 }
763 sync();
764 sleep(2);
765#endif
766 sync();
767 sleep(1);
768 newtResume();
769 }
770
771 if (!strcmp(format, "lvm")) {
772 mr_msg(1, "Don't format %s - it's part of an lvm volume", device);
773 return (0);
774 }
775 malloc_string(program2);
776 res = which_format_command_do_i_need(format, program2);
777 mr_asprintf(&tmp, "%s %s", program2, device);
778 if (strstr(program2, "kludge")) {
779 mr_strcat(tmp, " /");
780 }
781 mr_free(program2);
782
783 mr_asprintf(&program, "sh -c 'echo -en \"y\\ny\\ny\\n\" | %s'", tmp);
784 mr_free(tmp);
785
786 mr_asprintf(&tmp, _("Formatting %s as %s"), device, format);
787 update_progress_form(tmp);
788
789 res = run_program_and_log_output(program, FALSE);
790 if (res && strstr(program, "kludge")) {
791 mr_free(tmp);
792 mr_asprintf(&tmp, _("Kludge failed; using regular mkfs.%s to format %s"), format, device);
793 mr_free(program);
794#ifdef __FreeBSD__
795 mr_asprintf(&program, "newfs_msdos -F 32 %s", device);
796#else
797#ifdef __IA64__
798 /* For EFI partitions take fat16
799 * as we want to make small ones */
800 mr_asprintf(&program, "mkfs -t %s -F 16 %s", format, device);
801#else
802 mr_asprintf(&program, "mkfs -t %s -F 32 %s", format, device);
803#endif
804#endif
805 res = run_program_and_log_output(program, FALSE);
806 if (g_fprep) {
807 fprintf(g_fprep, "%s\n", program);
808 }
809 }
810 mr_free(program);
811
812 retval += res;
813 if (retval) {
814 mr_strcat(tmp, _("...failed"));
815 } else {
816 mr_strcat(tmp, _("...OK"));
817 }
818 log_to_screen(tmp);
819 mr_free(tmp);
820
821 sync();
822 sleep(1);
823 return (retval);
824}
825
826
827/**
828 * Format all drives (except those excluded by format_device()) in @p mountlist.
829 * @param mountlist The mountlist containing partitions to be formatted.
830 * @param interactively If TRUE, then prompt the user before each partition.
831 * @return The number of errors encountered (0 for success).
832 */
833int format_everything(struct mountlist_itself *mountlist,
834 bool interactively, struct raidlist_itself *raidlist)
835{
836 /** int **************************************************************/
837 int retval = 0;
838 int lino = 0;
839 int res = 0;
840
841 /** long *************************************************************/
842 long progress_step = 0L;
843
844 /** bools ************************************************************/
845 bool do_it = FALSE;
846
847 /** buffers **********************************************************/
848 char *tmp = NULL;
849
850 /** pointers *********************************************************/
851 struct mountlist_line *me = NULL; // mountlist entry
852 /** end **************************************************************/
853
854 assert(mountlist != NULL);
855 log_it("format_everything (mountlist, interactively = %s",
856 (interactively) ? "true" : "false");
857 mvaddstr_and_log_it(g_currentY, 0, _("Formatting partitions "));
858 open_progress_form(_("Formatting partitions"),
859 _("I am now formatting your hard disk partitions."),
860 _("This may take up to five minutes."), "",
861 mountlist->entries + 1);
862
863 progress_step =
864 (mountlist->entries >
865 0) ? g_maximum_progress / mountlist->entries : 1;
866 // start soft-raids now (because LVM might depend on them)
867 // ...and for simplicity's sake, let's format them at the same time :)
868 mr_msg(1, "Stopping all RAID devices");
869 stop_all_raid_devices(mountlist);
870 sync();
871 sync();
872 sync();
873 sleep(2);
874 mr_msg(1, "Prepare soft-RAIDs"); // prep and format too
875 for (lino = 0; lino < mountlist->entries; lino++) {
876 me = &mountlist->el[lino]; // the current mountlist entry
877 mr_msg(2, "Examining %s", me->device);
878 if (!strncmp(me->device, "/dev/md", 7)) {
879 if (interactively) {
880 // ask user if we should format the current device
881 mr_asprintf(&tmp, "Shall I format %s (%s) ?", me->device,
882 me->mountpoint);
883 do_it = ask_me_yes_or_no(tmp);
884 mr_free(tmp);
885 } else {
886 do_it = TRUE;
887 }
888 if (do_it) {
889 // NB: format_device() also stops/starts RAID device if necessary
890 retval += format_device(me->device, me->format, raidlist);
891 }
892 g_current_progress += progress_step;
893 }
894 }
895 sync();
896 sync();
897 sync();
898 sleep(2);
899 // This last step is probably necessary
900 // log_to_screen("Re-starting software RAIDs...");
901 // start_all_raid_devices(mountlist);
902 // system("sync"); system("sync"); system("sync");
903 // sleep(5);
904 // do LVMs now
905 mr_msg(1, "Creating LVMs");
906 if (does_file_exist("/tmp/i-want-my-lvm")) {
907 wait_until_software_raids_are_prepped(100);
908 log_to_screen(_("Configuring LVM"));
909 if (!g_text_mode) {
910 newtSuspend();
911 }
912 res = do_my_funky_lvm_stuff(FALSE, TRUE);
913 if (!g_text_mode) {
914 newtResume();
915 }
916 if (!res) {
917 log_to_screen("LVM initialized OK");
918 } else {
919 log_to_screen("Failed to initialize LVM");
920 }
921 if (res) {
922 retval++;
923 }
924 sleep(3);
925 }
926 // do regulars at last
927 sleep(2); // woo!
928 mr_msg(1, "Formatting regulars");
929 for (lino = 0; lino < mountlist->entries; lino++) {
930 me = &mountlist->el[lino]; // the current mountlist entry
931 if (!strcmp(me->mountpoint, "image")) {
932 log_it("Not formatting %s - it's an image", me->device);
933 } else if (!strcmp(me->format, "raid")) {
934 log_it("Not formatting %s - it's a raid-let", me->device);
935 continue;
936 } else if (!strcmp(me->format, "lvm")) {
937 log_it("Not formatting %s - it's an LVM", me->device);
938 continue;
939 } else if (!strncmp(me->device, "/dev/md", 7)) {
940 log_it("Already formatted %s - it's a soft-RAID dev", me->device);
941 continue;
942 } else if (!does_file_exist(me->device)
943 && strncmp(me->device, "/dev/hd", 7)
944 && strncmp(me->device, "/dev/sd", 7)) {
945 log_it("Not formatting %s yet - doesn't exist - probably an LVM", me->device);
946 continue;
947 } else {
948 if (interactively) {
949 // ask user if we should format the current device
950 mr_asprintf(&tmp, "Shall I format %s (%s) ?", me->device,
951 me->mountpoint);
952 do_it = ask_me_yes_or_no(tmp);
953 mr_free(tmp);
954 } else {
955 do_it = TRUE;
956 }
957
958 if (do_it)
959 retval += format_device(me->device, me->format, raidlist);
960 }
961
962 // update progress bar
963 g_current_progress += progress_step;
964 }
965
966
967 // update progress bar to 100% to compensate for
968 // rounding errors of the progress_step calculation
969 if (lino >= mountlist->entries)
970 g_current_progress = g_maximum_progress;
971
972 close_progress_form();
973
974 if (retval) {
975 mvaddstr_and_log_it(g_currentY++, 74, _("Failed."));
976 log_to_screen
977 (_
978 ("Errors occurred during the formatting of your hard drives."));
979 } else {
980 mvaddstr_and_log_it(g_currentY++, 74, _("Done."));
981 }
982
983 log_it("format_everything () - %s",
984 (retval) ? "failed!" : "finished successfully");
985
986 if (g_partition_table_locked_up > 0) {
987 if (retval > 0 && !interactively) {
988//123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
989 log_to_screen
990 (_
991 ("Partition table locked up %d times. At least one 'mkfs' (format) command"),
992 g_partition_table_locked_up);
993 log_to_screen(_
994 ("failed. I think these two events are related. Sometimes, fdisk's ioctl() call"));
995 log_to_screen(_
996 ("to refresh its copy of the partition table causes the kernel to lock the "));
997 log_to_screen(_
998 ("partition table. I believe this has just happened."));
999 if (ask_me_yes_or_no
1000 (_
1001 ("Please choose 'yes' to reboot and try again; or 'no' to ignore this warning and continue.")))
1002 {
1003 sync();
1004 sync();
1005 sync();
1006 system("reboot");
1007 }
1008 } else {
1009 log_to_screen
1010 (_
1011 ("Partition table locked up %d time%c. However, disk formatting succeeded."),
1012 g_partition_table_locked_up,
1013 (g_partition_table_locked_up == 1) ? '.' : 's');
1014 }
1015 }
1016 newtSuspend();
1017 system("clear");
1018 newtResume();
1019 return (retval);
1020}
1021
1022
1023/**
1024 * Create small dummy partitions to fill in the gaps in partition numbering for @p drivename.
1025 * Each partition created is 32k in size.
1026 * @param drivename The drive to create the dummy partitions on.
1027 * @param devno_we_must_allow_for The lowest-numbered real partition; create
1028 * dummies up to (this - 1).
1029 * @return The number of errors encountered (0 for success).
1030 */
1031int make_dummy_partitions(FILE * pout_to_fdisk, char *drivename,
1032 int devno_we_must_allow_for)
1033{
1034 /** int **************************************************************/
1035 int current_devno = 0;
1036 int previous_devno = 0;
1037 int retval = 0;
1038 int res = 0;
1039
1040 /** end **************************************************************/
1041
1042 assert_string_is_neither_NULL_nor_zerolength(drivename);
1043
1044 if (devno_we_must_allow_for >= 5) {
1045 log_it("Making dummy primary 1 on %s", drivename);
1046 g_maximum_progress++;
1047 res =
1048 partition_device(pout_to_fdisk, drivename, 1, 0, "ext2",
1049 32000);
1050 retval += res;
1051 previous_devno = 1;
1052 current_devno = 5;
1053 } else {
1054 previous_devno = 0;
1055 current_devno = 1;
1056 }
1057 for (; current_devno < devno_we_must_allow_for; current_devno++) {
1058 log_it("Creating dummy partition %d on %s", current_devno, drivename);
1059 g_maximum_progress++;
1060 res =
1061 partition_device(pout_to_fdisk, drivename, current_devno,
1062 previous_devno, OSSWAP("ext2", "ufs"), 32000);
1063 retval += res;
1064 previous_devno = current_devno;
1065 }
1066 return (previous_devno);
1067}
1068
1069
1070/**
1071 * Decide whether @p mountlist contains any RAID devices.
1072 * @param mountlist The mountlist to examine.
1073 * @return TRUE if it does, FALSE if it doesn't.
1074 */
1075bool mountlist_contains_raid_devices(struct mountlist_itself * mountlist)
1076{
1077 /** int *************************************************************/
1078 int i;
1079 int matching = 0;
1080
1081 /** end **************************************************************/
1082
1083 assert(mountlist != NULL);
1084
1085 for (i = 0; i < mountlist->entries; i++) {
1086 if (strstr(mountlist->el[i].device, RAID_DEVICE_STUB)) {
1087 matching++;
1088 }
1089 }
1090 if (matching) {
1091 return (TRUE);
1092 } else {
1093 return (FALSE);
1094 }
1095}
1096
1097
1098/* The following 2 functions are stolen from /usr/src/sbin/disklabel/disklabel.c */
1099#ifdef __FreeBSD__
1100static void display_disklabel(FILE * f, const struct disklabel *lp)
1101{
1102 int i, j;
1103 const struct partition *pp;
1104
1105 fprintf(f, "# %s\n", "Generated by Mondo Rescue");
1106 if (lp->d_type < DKMAXTYPES)
1107 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
1108 else
1109 fprintf(f, "type: %u\n", lp->d_type);
1110 fprintf(f, "disk: %.*s\n", (int) sizeof(lp->d_typename),
1111 lp->d_typename);
1112 fprintf(f, "label: %.*s\n", (int) sizeof(lp->d_packname),
1113 lp->d_packname);
1114 fprintf(f, "flags:");
1115 if (lp->d_flags & D_REMOVABLE)
1116 fprintf(f, " removeable");
1117 if (lp->d_flags & D_ECC)
1118 fprintf(f, " ecc");
1119 if (lp->d_flags & D_BADSECT)
1120 fprintf(f, " badsect");
1121 fprintf(f, "\n");
1122 fprintf(f, "bytes/sector: %lu\n", (u_long) lp->d_secsize);
1123 fprintf(f, "sectors/track: %lu\n", (u_long) lp->d_nsectors);
1124 fprintf(f, "tracks/cylinder: %lu\n", (u_long) lp->d_ntracks);
1125 fprintf(f, "sectors/cylinder: %lu\n", (u_long) lp->d_secpercyl);
1126 fprintf(f, "cylinders: %lu\n", (u_long) lp->d_ncylinders);
1127 fprintf(f, "sectors/unit: %lu\n", (u_long) lp->d_secperunit);
1128 fprintf(f, "rpm: %u\n", lp->d_rpm);
1129 fprintf(f, "interleave: %u\n", lp->d_interleave);
1130 fprintf(f, "trackskew: %u\n", lp->d_trackskew);
1131 fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
1132 fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
1133 (u_long) lp->d_headswitch);
1134 fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
1135 (u_long) lp->d_trkseek);
1136 fprintf(f, "drivedata: ");
1137 for (i = NDDATA - 1; i >= 0; i--)
1138 if (lp->d_drivedata[i])
1139 break;
1140 if (i < 0)
1141 i = 0;
1142 for (j = 0; j <= i; j++)
1143 fprintf(f, "%lu ", (u_long) lp->d_drivedata[j]);
1144 fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
1145 fprintf(f,
1146 "# size offset fstype [fsize bsize bps/cpg]\n");
1147 pp = lp->d_partitions;
1148 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1149 if (pp->p_size) {
1150 fprintf(f, " %c: %8lu %8lu ", 'a' + i, (u_long) pp->p_size,
1151 (u_long) pp->p_offset);
1152 if (pp->p_fstype < FSMAXTYPES)
1153 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
1154 else
1155 fprintf(f, "%8d", pp->p_fstype);
1156 switch (pp->p_fstype) {
1157
1158 case FS_UNUSED: /* XXX */
1159 fprintf(f, " %5lu %5lu %5.5s ", (u_long) pp->p_fsize,
1160 (u_long) (pp->p_fsize * pp->p_frag), "");
1161 break;
1162
1163 case FS_BSDFFS:
1164 fprintf(f, " %5lu %5lu %5u ", (u_long) pp->p_fsize,
1165 (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1166 break;
1167
1168 case FS_BSDLFS:
1169 fprintf(f, " %5lu %5lu %5d", (u_long) pp->p_fsize,
1170 (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1171 break;
1172
1173 default:
1174 fprintf(f, "%20.20s", "");
1175 break;
1176 }
1177 fprintf(f, "\t# (Cyl. %4lu",
1178 (u_long) (pp->p_offset / lp->d_secpercyl));
1179 if (pp->p_offset % lp->d_secpercyl)
1180 putc('*', f);
1181 else
1182 putc(' ', f);
1183 fprintf(f, "- %lu",
1184 (u_long) ((pp->p_offset + pp->p_size +
1185 lp->d_secpercyl - 1) / lp->d_secpercyl -
1186 1));
1187 if (pp->p_size % lp->d_secpercyl)
1188 putc('*', f);
1189 fprintf(f, ")\n");
1190 }
1191 }
1192 fflush(f);
1193}
1194
1195static struct disklabel *get_virgin_disklabel(char *dkname)
1196{
1197 static struct disklabel loclab;
1198 struct partition *dp = NULL;
1199 char *lnamebuf = NULL;
1200 int f;
1201 u_int secsize, u;
1202 off_t mediasize;
1203
1204 mr_asprintf(&lnamebuf, "%s", dkname);
1205 if ((f = open(lnamebuf, O_RDONLY)) == -1) {
1206 warn("cannot open %s", lnamebuf);
1207 mr_free(lnamebuf);
1208 return (NULL);
1209 }
1210 mr_free(lnamebuf);
1211
1212 /* New world order */
1213 if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0)
1214 || (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
1215 close(f);
1216 return (NULL);
1217 }
1218 memset(&loclab, 0, sizeof loclab);
1219 loclab.d_magic = DISKMAGIC;
1220 loclab.d_magic2 = DISKMAGIC;
1221 loclab.d_secsize = secsize;
1222 loclab.d_secperunit = mediasize / secsize;
1223
1224 /*
1225 * Nobody in these enligthened days uses the CHS geometry for
1226 * anything, but nontheless try to get it right. If we fail
1227 * to get any good ideas from the device, construct something
1228 * which is IBM-PC friendly.
1229 */
1230 if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1231 loclab.d_nsectors = u;
1232 else
1233 loclab.d_nsectors = 63;
1234 if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1235 loclab.d_ntracks = u;
1236 else if (loclab.d_secperunit <= 63 * 1 * 1024)
1237 loclab.d_ntracks = 1;
1238 else if (loclab.d_secperunit <= 63 * 16 * 1024)
1239 loclab.d_ntracks = 16;
1240 else
1241 loclab.d_ntracks = 255;
1242 loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1243 loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1244 loclab.d_npartitions = MAXPARTITIONS;
1245
1246 /* Various (unneeded) compat stuff */
1247 loclab.d_rpm = 3600;
1248 loclab.d_bbsize = BBSIZE;
1249 loclab.d_interleave = 1;;
1250 strncpy(loclab.d_typename, "amnesiac", sizeof(loclab.d_typename));
1251
1252 dp = &loclab.d_partitions[RAW_PART];
1253 dp->p_size = loclab.d_secperunit;
1254 loclab.d_checksum = dkcksum(&loclab);
1255 close(f);
1256 return (&loclab);
1257}
1258
1259/* End stolen from /usr/src/sbin/disklabel/disklabel.c. */
1260
1261char *canonical_name(char *drivename)
1262{
1263 if (drivename) {
1264 if (strncmp(drivename, "/dev/", 5) == 0) {
1265 return drivename + 5;
1266 }
1267 }
1268 return drivename;
1269}
1270
1271/**
1272 * (BSD only) Create a disklabel on @p drivename according to @p mountlist.
1273 * @param mountlist The mountlist to get the subpartition information from.
1274 * @param drivename The drive or slice to create a disklabel on.
1275 * @param ret If non-NULL, store the created disklabel here.
1276 * @return The number of errors encountered (0 for success).
1277 */
1278int label_drive_or_slice(struct mountlist_itself *mountlist,
1279 char *drivename, struct disklabel *ret)
1280{
1281 char *subdev_str = NULL;
1282 char *command = NULL;
1283 struct disklabel *lp = NULL;
1284 int i, lo = 0;
1285 int retval = 0;
1286 char c = ' ';
1287 FILE *ftmp = NULL;
1288
1289 lp = get_virgin_disklabel(drivename);
1290 for (c = 'a'; c <= 'z'; ++c) {
1291 int idx;
1292 mr_asprintf(&subdev_str, "%s%c", drivename, c);
1293 if ((idx = find_device_in_mountlist(mountlist, subdev_str)) < 0) {
1294 lp->d_partitions[c - 'a'].p_size = 0;
1295 lp->d_partitions[c - 'a'].p_fstype = FS_UNUSED;
1296 } else {
1297 lo = c - 'a';
1298 lp->d_partitions[c - 'a'].p_size = mountlist->el[idx].size * 2;
1299 lp->d_partitions[c - 'a'].p_fsize = 0;
1300 lp->d_partitions[c - 'a'].p_frag = 0;
1301 lp->d_partitions[c - 'a'].p_cpg = 0;
1302 if (!strcmp(mountlist->el[idx].format, "ufs")
1303 || !strcmp(mountlist->el[idx].format, "ffs")
1304 || !strcmp(mountlist->el[idx].format, "4.2BSD")) {
1305 lp->d_partitions[c - 'a'].p_fstype = FS_BSDFFS;
1306 lp->d_partitions[c - 'a'].p_fsize = 2048;
1307 lp->d_partitions[c - 'a'].p_frag = 8;
1308 lp->d_partitions[c - 'a'].p_cpg = 64;
1309 } else if (!strcasecmp(mountlist->el[idx].format, "raid")
1310 || !strcasecmp(mountlist->el[idx].format, "vinum")) {
1311 lp->d_partitions[c - 'a'].p_fstype = FS_VINUM;
1312 } else if (!strcmp(mountlist->el[idx].format, "swap")) {
1313 lp->d_partitions[c - 'a'].p_fstype = FS_SWAP;
1314 } else
1315 lp->d_partitions[c - 'a'].p_fstype = FS_OTHER;
1316 }
1317 mr_free(subdev_str);
1318 }
1319
1320 // fix up the offsets
1321 lp->d_partitions[0].p_offset = 0;
1322 lp->d_partitions[RAW_PART].p_offset = 0;
1323 lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
1324 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1325
1326 for (i = 1; i < lp->d_npartitions; ++i) {
1327 int lastone;
1328 if ((i == RAW_PART) || (lp->d_partitions[i].p_size == 0))
1329 continue;
1330 for (lastone = i - 1; lastone >= 0; lastone--) {
1331 if ((lp->d_partitions[lastone].p_size)
1332 && (lastone != RAW_PART))
1333 break;
1334 }
1335 lp->d_partitions[i].p_offset =
1336 lp->d_partitions[lastone].p_offset +
1337 lp->d_partitions[lastone].p_size;
1338 }
1339 if (lp->d_partitions[lo].p_offset + lp->d_partitions[lo].p_size >
1340 lp->d_secperunit) {
1341 lp->d_partitions[lo].p_size =
1342 lp->d_secperunit - lp->d_partitions[lo].p_offset;
1343 }
1344
1345 ftmp = fopen("/tmp/disklabel", "w");
1346 display_disklabel(ftmp, lp);
1347 fclose(ftmp);
1348 mr_asprintf(&command, "disklabel -wr %s auto", canonical_name(drivename));
1349 retval += run_program_and_log_output(command, TRUE);
1350 mr_free(command);
1351
1352 mr_asprintf(&command, "disklabel -R %s /tmp/disklabel",
1353 canonical_name(drivename));
1354 retval += run_program_and_log_output(command, TRUE);
1355 mr_free(command);
1356 if (ret)
1357 *ret = *lp;
1358 return retval;
1359}
1360#endif
1361
1362
1363/**
1364 * Partition @p drivename based on @p mountlist.
1365 * @param mountlist The mountlist to use to guide the partitioning.
1366 * @param drivename The drive to partition.
1367 * @return 0 for success, nonzero for failure.
1368 */
1369int partition_drive(struct mountlist_itself *mountlist, char *drivename)
1370{
1371 /** int *************************************************************/
1372 int current_devno = 0;
1373 int previous_devno = 0;
1374 int lino = 0;
1375 int retval = 0;
1376 int i = 0;
1377 FILE *pout_to_fdisk = NULL;
1378
1379#ifdef __FreeBSD__
1380 bool fbsd_part = FALSE;
1381 char *subdev_str = NULL;
1382#endif
1383
1384 /** long long *******************************************************/
1385 long long partsize;
1386
1387 /** buffers *********************************************************/
1388 char *device_str = NULL;
1389 char *format = NULL;
1390 char *tmp = NULL;
1391
1392 /** end *************************************************************/
1393
1394 assert(mountlist != NULL);
1395 assert_string_is_neither_NULL_nor_zerolength(drivename);
1396
1397 log_it("Partitioning drive %s", drivename);
1398
1399#if __FreeBSD__
1400 log_it("(Not opening fdisk now; that's the Linux guy's job)");
1401 pout_to_fdisk = NULL;
1402#else
1403 make_hole_for_file(FDISK_LOG);
1404 mr_asprintf(&tmp, "parted2fdisk %s >> %s 2>> %s", drivename, FDISK_LOG,
1405 FDISK_LOG);
1406 pout_to_fdisk = popen(tmp, "w");
1407 mr_free(tmp);
1408
1409 if (!pout_to_fdisk) {
1410 log_to_screen(_("Cannot call parted2fdisk to configure %s"),
1411 drivename);
1412 return (1);
1413 }
1414#endif
1415
1416 malloc_string(device_str);
1417
1418 for (current_devno = 1; current_devno < 99; current_devno++) {
1419 build_partition_name(device_str, drivename, current_devno);
1420 lino = find_device_in_mountlist(mountlist, device_str);
1421
1422 if (lino < 0) {
1423 // device not found in mountlist
1424#if __FreeBSD__
1425 // If this is the first partition (just as a sentinel value),
1426 // then see if the user has picked 'dangerously-dedicated' mode.
1427 // If so, then we just call label_drive_or_slice() and return.
1428 char c = ' ';
1429 char *command = NULL;
1430
1431 if (current_devno == 1) {
1432 // try DangerouslyDedicated mode
1433 for (c = 'a'; c <= 'z'; c++) {
1434 mr_asprintf(&subdev_str, "%s%c", drivename, c);
1435 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1436 fbsd_part = TRUE;
1437 }
1438 mr_free(subdev_str);
1439 }
1440 if (fbsd_part) {
1441 int r = label_drive_or_slice(mountlist,
1442 drivename,
1443 0);
1444 mr_asprintf(&command, "disklabel -B %s",
1445 basename(drivename));
1446 if (system(command)) {
1447 log_to_screen
1448 (_
1449 ("Warning! Unable to make the drive bootable."));
1450 }
1451 mr_free(command);
1452 mr_free(device_str);
1453 return r;
1454 }
1455 }
1456 for (c = 'a'; c <= 'z'; c++) {
1457 mr_asprintf(&subdev_str, "%s%c", device_str, c);
1458 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1459 fbsd_part = TRUE;
1460 }
1461 mr_free(subdev_str);
1462 }
1463 // Now we check the subpartitions of the current partition.
1464 if (fbsd_part) {
1465 int i, line;
1466
1467 mr_asprintf(&format, "ufs");
1468 partsize = 0;
1469 for (i = 'a'; i < 'z'; ++i) {
1470 mr_asprintf(&subdev_str, "%s%c", device_str, i);
1471 line = find_device_in_mountlist(mountlist, subdev_str);
1472 mr_free(subdev_str);
1473
1474 if (line > 0) {
1475 // We found one! Add its size to the total size.
1476 partsize += mountlist->el[line].size;
1477 }
1478 }
1479 } else {
1480 continue;
1481 }
1482#else
1483 continue;
1484#endif
1485 }
1486
1487 /* OK, we've found partition /dev/hdxN in mountlist; let's prep it */
1488 /* For FreeBSD, that is /dev/adXsY */
1489
1490 log_it("Found partition %s in mountlist", device_str);
1491 if (!previous_devno) {
1492
1493 log_it("Wiping %s's partition table", drivename);
1494#if __FreeBSD__
1495 // FreeBSD doesn't let you write to blk devices in <512byte chunks.
1496 file = open(drivename, O_WRONLY);
1497 if (!file) {
1498 log_to_screen(_("Warning - unable to open %s for wiping it's partition table"), drivename);
1499 }
1500
1501 for (i = 0; i < 512; i++) {
1502 if (!write(file, "\0", 1)) {
1503 log_to_screen(_("Warning - unable to write to %s"), drivename);
1504 }
1505 }
1506 sync();
1507#else
1508 iamhere("New, kernel-friendly partition remover");
1509 for (i = 20; i > 0; i--) {
1510 fprintf(pout_to_fdisk, "d\n%d\n", i);
1511 fflush(pout_to_fdisk);
1512 }
1513#endif
1514 if (current_devno > 1) {
1515 previous_devno =
1516 make_dummy_partitions(pout_to_fdisk, drivename,
1517 current_devno);
1518 }
1519 }
1520#ifdef __FreeBSD__
1521 if (!fbsd_part) {
1522#endif
1523 mr_free(format);
1524 mr_asprintf(&format, mountlist->el[lino].format);
1525 partsize = mountlist->el[lino].size;
1526
1527#ifdef __FreeBSD__
1528 }
1529#endif
1530
1531#ifndef __IA64__
1532 if (current_devno == 5 && previous_devno == 4) {
1533 log_to_screen
1534 (_
1535 ("You must leave at least one partition spare as the Extended partition."));
1536 mr_free(device_str);
1537 mr_free(format);
1538 return (1);
1539 }
1540#endif
1541
1542 retval +=
1543 partition_device(pout_to_fdisk, drivename, current_devno,
1544 previous_devno, format, partsize);
1545
1546#ifdef __FreeBSD__
1547 if ((current_devno <= 4) && fbsd_part) {
1548 mr_asprintf(&tmp, "disklabel -B %s", basename(device_str));
1549 retval += label_drive_or_slice(mountlist, device_str, 0);
1550 if (system(tmp)) {
1551 log_to_screen
1552 (_("Warning! Unable to make the slice bootable."));
1553 }
1554 mr_free(tmp);
1555 }
1556#endif
1557
1558 previous_devno = current_devno;
1559 }
1560 mr_free(device_str);
1561 mr_free(format);
1562
1563 if (pout_to_fdisk) {
1564 // mark relevant partition as bootable
1565 mr_asprintf(&tmp, "a\n%s\n",
1566 call_program_and_get_last_line_of_output
1567 ("make-me-bootable /tmp/mountlist.txt dummy"));
1568 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1569 mr_free(tmp);
1570
1571 // close fdisk
1572 fput_string_one_char_at_a_time(pout_to_fdisk, "w\n");
1573 sync();
1574 paranoid_pclose(pout_to_fdisk);
1575 mr_msg(0,
1576 "------------------- fdisk.log looks like this ------------------");
1577 mr_asprintf(&tmp, "cat %s >> %s", FDISK_LOG, MONDO_LOGFILE);
1578 system(tmp);
1579 mr_free(tmp);
1580
1581 mr_msg(0,
1582 "------------------- end of fdisk.log... word! ------------------");
1583 mr_asprintf(&tmp, "tail -n6 %s | grep -F \"16: \"", FDISK_LOG);
1584 if (!run_program_and_log_output(tmp, 5)) {
1585 g_partition_table_locked_up++;
1586 log_to_screen
1587 (_
1588 ("A flaw in the Linux kernel has locked the partition table."));
1589 }
1590 mr_free(tmp);
1591 }
1592 return (retval);
1593}
1594
1595
1596/**
1597 * Create partition number @p partno on @p drive with @p fdisk.
1598 * @param drive The drive to create the partition on.
1599// * @param partno The partition number of the new partition (1-4 are primary, >=5 is logical).
1600 * @param prev_partno The partition number of the most recently prepped partition.
1601 * @param format The filesystem type of this partition (used to set the type).
1602 * @param partsize The size of the partition in @e bytes.
1603 * @return 0 for success, nonzero for failure.
1604 */
1605int partition_device(FILE * pout_to_fdisk, const char *drive, int partno,
1606 int prev_partno, const char *format,
1607 long long partsize)
1608{
1609 /** int **************************************************************/
1610 int retval = 0;
1611 int res = 0;
1612
1613 /** buffers **********************************************************/
1614 char *program = NULL;
1615 char *partition_name = NULL;
1616 char *tmp = NULL;
1617 char *output = NULL;
1618
1619 /** pointers **********************************************************/
1620 char *p = NULL;
1621 char *part_table_fmt = NULL;
1622 FILE *fout = NULL;
1623
1624 /** end ***************************************************************/
1625
1626 assert_string_is_neither_NULL_nor_zerolength(drive);
1627 assert(format != NULL);
1628
1629 log_it("partition_device('%s', %d, %d, '%s', %lld) --- starting",
1630 drive, partno, prev_partno, format, partsize);
1631
1632 if (!strncmp(drive, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
1633 log_it("Not partitioning %s - it is a virtual drive", drive);
1634 return (0);
1635 }
1636
1637 malloc_string(partition_name);
1638
1639 build_partition_name(partition_name, drive, partno);
1640 if (partsize <= 0) {
1641 mr_asprintf(&tmp, "Partitioning device %s (max size)", partition_name);
1642 } else {
1643 mr_asprintf(&tmp, "Partitioning device %s (%lld MB)", partition_name,
1644 (long long) partsize / 1024);
1645 }
1646 update_progress_form(tmp);
1647 log_it(tmp);
1648 mr_free(tmp);
1649
1650 if (is_this_device_mounted(partition_name)) {
1651 log_to_screen("%s is mounted, and should not be partitioned",
1652 partition_name);
1653 mr_free(partition_name);
1654 return (1);
1655 }
1656
1657 p = (char *) strrchr(partition_name, '/');
1658
1659 /* BERLIOS: should not be called each time */
1660 part_table_fmt = which_partition_format(drive);
1661 /* make it a primary/extended/logical */
1662 if (partno <= 4) {
1663 mr_asprintf(&output,"n\np\n%d\n", partno);
1664 } else {
1665 /* MBR needs an extended partition if more than 4 partitions */
1666 if (strcmp(part_table_fmt, "MBR") == 0) {
1667 if (partno == 5) {
1668 if (prev_partno >= 4) {
1669 log_to_screen
1670 (_
1671 ("You need to leave at least one partition free, for 'extended/logical'"));
1672 mr_free(partition_name);
1673 return (1);
1674 } else {
1675 mr_asprintf(&output,"n\ne\n%d\n\n\n",prev_partno + 1);
1676 }
1677 }
1678 mr_strcat(output, "n\nl\n");
1679 } else {
1680 /* GPT allows more than 4 primary partitions */
1681 mr_asprintf(&output,"n\np\n%d\n",partno);
1682 }
1683 }
1684 /*start block (ENTER for next free blk */
1685 mr_strcat(output, "\n");
1686 if (partsize > 0) {
1687 if (!strcmp(format, "7")) {
1688 mr_msg(1, "Adding 512K, just in case");
1689 partsize += 512;
1690 }
1691 mr_strcat(output, "+%lldK", (long long) (partsize));
1692 }
1693 mr_strcat(output, "\n");
1694#if 0
1695/*
1696#endif
1697 log_it("PARTSIZE = +%ld",(long)partsize);
1698 log_it("---fdisk command---");
1699 log_it(output);
1700 log_it("---end of fdisk---");
1701#if 0
1702*/
1703#endif
1704
1705
1706 if (pout_to_fdisk) {
1707 mr_msg(1, "Doing the new all-in-one fdisk thing");
1708 mr_msg(1, "output = '%s'", output);
1709 fput_string_one_char_at_a_time(pout_to_fdisk, output);
1710 fput_string_one_char_at_a_time(pout_to_fdisk, "\n\np\n");
1711 mr_asprintf(&tmp, last_line_of_file(FDISK_LOG));
1712 if (strstr(tmp, " (m ")) {
1713 mr_msg(1, "Successfully created partition %d on %s", partno, drive);
1714 } else {
1715 mr_msg(1, "last line = %s", tmp);
1716 mr_msg(1, "Failed to create partition %d on %s; sending 'Enter'...", partno, drive);
1717 }
1718 mr_free(tmp);
1719
1720 if (!retval) {
1721 mr_msg(1, "Trying to set partition %d type now on %s", partno, drive);
1722 retval =
1723 set_partition_type(pout_to_fdisk, drive, partno, format,
1724 partsize);
1725 if (retval) {
1726 mr_msg(1, "Failed. Trying again...");
1727 retval =
1728 set_partition_type(pout_to_fdisk, drive, partno,
1729 format, partsize);
1730 }
1731 }
1732 if (retval) {
1733 mr_msg(1, "...but failed to set type");
1734 }
1735 } else {
1736 mr_strcat(output, "w\n\n");
1737 mr_asprintf(&program, "parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE,
1738 MONDO_LOGFILE);
1739
1740 if (g_fprep) {
1741 fprintf(g_fprep, "echo \"%s\" | %s\n", output, program);
1742 }
1743 /* write to disk; close fdisk's stream */
1744 if (!(fout = popen(program, "w"))) {
1745 log_OS_error("can't popen-out to program");
1746 } else {
1747 fputs(output, fout);
1748 paranoid_pclose(fout);
1749 }
1750 mr_free(program);
1751
1752 if (!does_partition_exist(drive, partno) && partsize > 0) {
1753 log_it("Vaccum-packing");
1754 g_current_progress--;
1755 res =
1756 partition_device(pout_to_fdisk, drive, partno, prev_partno,
1757 format, -1);
1758 if (res) {
1759 log_it("Failed to vacuum-pack %s", partition_name);
1760 retval++;
1761 } else {
1762 retval = 0;
1763 }
1764 }
1765 if (does_partition_exist(drive, partno)) {
1766 retval =
1767 set_partition_type(pout_to_fdisk, drive, partno, format,
1768 partsize);
1769 if (retval) {
1770 log_it("Partitioned %s but failed to set its type",
1771 partition_name);
1772 } else {
1773 if (partsize > 0) {
1774 log_to_screen(_("Partition %s created+configured OK"),
1775 partition_name);
1776 } else {
1777 log_it("Returning from a successful vacuum-pack");
1778 }
1779 }
1780 } else {
1781 mr_asprintf(&tmp, "Failed to partition %s", partition_name);
1782 if (partsize > 0) {
1783 log_to_screen(tmp);
1784 } else {
1785 log_it(tmp);
1786 }
1787 mr_free(tmp);
1788 retval++;
1789 }
1790 }
1791 g_current_progress++;
1792 log_it("partition_device() --- leaving");
1793 mr_free(partition_name);
1794 mr_free(output);
1795 return (retval);
1796}
1797
1798
1799/**
1800 * Create all partitions listed in @p mountlist.
1801 * @param mountlist The mountlist to use to guide the partitioning.
1802 * @return The number of errors encountered (0 for success).
1803 * @note This sets the partition types but doesn't actually do the formatting.
1804 * Use format_everything() for that.
1805 */
1806int partition_everything(struct mountlist_itself *mountlist)
1807{
1808 /** int ************************************************************/
1809 int lino = 0;
1810 int retval = 0;
1811 int i = 0;
1812 int res = 0;
1813
1814 /** buffer *********************************************************/
1815 struct list_of_disks *drivelist = NULL;
1816
1817 /** end ************************************************************/
1818
1819 drivelist = mr_malloc(sizeof(struct list_of_disks));
1820 assert(mountlist != NULL);
1821
1822 log_it("partition_everything() --- starting");
1823 mvaddstr_and_log_it(g_currentY, 0, "Partitioning hard drives ");
1824 if (mountlist_contains_raid_devices(mountlist)) {
1825 /* mountlist=&new_mtlist; */
1826 /* extrapolate_mountlist_to_include_raid_partitions(mountlist,orig_mtlist); */
1827 mr_msg(0,
1828 "Mountlist, including the partitions incorporated in RAID devices:-");
1829 for (i = 0; i < mountlist->entries; i++) {
1830 log_it(mountlist->el[i].device);
1831 }
1832 mr_msg(0, "End of mountlist.");
1833 }
1834 mr_msg(0, "Stopping all LVMs, just in case");
1835 if (!g_text_mode) {
1836 newtSuspend();
1837 }
1838 do_my_funky_lvm_stuff(TRUE, FALSE); // just remove old partitions
1839 if (!g_text_mode) {
1840 newtResume();
1841 }
1842 mr_msg(0, "Stopping all software RAID devices, just in case");
1843 stop_all_raid_devices(mountlist);
1844 mr_msg(0, "Done.");
1845
1846 open_progress_form(_("Partitioning devices"),
1847 _("I am now going to partition all your drives."),
1848 _("This should not take more than five minutes."),
1849 "", mountlist->entries);
1850
1851 make_list_of_drives_in_mountlist(mountlist, drivelist);
1852
1853 /* partition each drive */
1854 for (lino = 0; lino < drivelist->entries; lino++) {
1855 res = partition_drive(mountlist, drivelist->el[lino].device);
1856 retval += res;
1857 }
1858 close_progress_form();
1859 if (retval) {
1860 mvaddstr_and_log_it(g_currentY++, 74, _("Failed."));
1861 log_to_screen
1862 (_
1863 ("Errors occurred during the partitioning of your hard drives."));
1864 } else {
1865 mvaddstr_and_log_it(g_currentY++, 74, _("Done."));
1866 paranoid_system("rm -f /tmp/fdisk*.log 2> /dev/null");
1867 }
1868 newtSuspend();
1869 system("clear");
1870 newtResume();
1871 mr_free(drivelist);
1872 return (retval);
1873}
1874
1875
1876/**
1877 * Set the type of partition number @p partno on @p drive to @p format.
1878 * @param drive The drive to change the type of a partition on.
1879 * @param partno The partition number on @p drive to change the type of.
1880 * @param format The filesystem type this partition will eventually contain.
1881 * @param partsize The size of this partition, in @e bytes (used for vfat
1882 * type calculations).
1883 * @return 0 for success, nonzero for failure.
1884 */
1885int set_partition_type(FILE * pout_to_fdisk, const char *drive, int partno,
1886 const char *format, long long partsize)
1887{
1888 /** buffers *********************************************************/
1889 char *partition = NULL;
1890 char *command = NULL;
1891 char *output = NULL;
1892 char *tmp = NULL;
1893 char *partcode = NULL;
1894
1895 /** pointers *********************************************************/
1896 char *p = NULL;
1897 FILE *fout = NULL;
1898
1899 /** int **************************************************************/
1900 int res = 0;
1901
1902 /** end **************************************************************/
1903
1904 assert_string_is_neither_NULL_nor_zerolength(drive);
1905 assert(format != NULL);
1906
1907 malloc_string(partition);
1908
1909 build_partition_name(partition, drive, partno);
1910 p = (char *) strrchr(partition, '/');
1911 if (strcmp(format, "swap") == 0) {
1912 mr_asprintf(&partcode, "82");
1913 } else if (strcmp(format, "vfat") == 0) {
1914 if (partsize / 1024 > 8192) {
1915 mr_asprintf(&partcode, "c");
1916 } else {
1917 mr_asprintf(&partcode, "b");
1918 }
1919 } else if (strcmp(format, "ext2") == 0
1920 || strcmp(format, "reiserfs") == 0
1921 || strcmp(format, "ext3") == 0
1922 || strcmp(format, "xfs") == 0
1923 || strcmp(format, "jfs") == 0) {
1924 mr_asprintf(&partcode, "83");
1925 } else if (strcmp(format, "minix") == 0) {
1926 mr_asprintf(&partcode, "81");
1927 } else if (strcmp(format, "vmfs") == 0) {
1928 strcpy(partcode, "fb");
1929 } else if (strcmp(format, "raid") == 0) {
1930 mr_asprintf(&partcode, "fd");
1931 } else if ((strcmp(format, "ufs") == 0)
1932 || (strcmp(format, "ffs") == 0)) { /* raid autodetect */
1933 mr_asprintf(&partcode, "a5");
1934 } else if (strcmp(format, "lvm") == 0) {
1935 mr_asprintf(&partcode, "8e");
1936 } else if (format[0] == '\0') { /* LVM physical partition */
1937 mr_asprintf(&partcode, "");
1938 } else if (strlen(format) >= 1 && strlen(format) <= 2) {
1939 mr_asprintf(&partcode, format);
1940 } else {
1941 /* probably an image */
1942 mr_asprintf(&tmp,
1943 "Unknown format ('%s') - using supplied string anyway",
1944 format);
1945 mvaddstr_and_log_it(g_currentY++, 0, tmp);
1946 mr_free(tmp);
1947#ifdef __FreeBSD__
1948 mr_asprintf(&partcode, format); // was a5
1949#else
1950 mr_asprintf(&partcode, format); // was 83
1951#endif
1952 }
1953 mr_asprintf(&tmp, "Setting %s's type to %s (%s)", partition, format,
1954 partcode);
1955 mr_msg(1, tmp);
1956 mr_free(tmp);
1957
1958 if (partcode[0] != '\0' && strcmp(partcode, "83")) { /* no need to set type if 83: 83 is default */
1959
1960 if (pout_to_fdisk) {
1961 res = 0;
1962 fput_string_one_char_at_a_time(pout_to_fdisk, "t\n");
1963 if (partno > 1
1964 || strstr(last_line_of_file(FDISK_LOG), " (1-4)")) {
1965 mr_msg(5, "Specifying partno (%d) - yay", partno);
1966 mr_asprintf(&tmp, "%d\n", partno);
1967 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1968 mr_msg(5, "A - last line = '%s'",
1969 last_line_of_file(FDISK_LOG));
1970 mr_free(tmp);
1971 }
1972
1973 mr_asprintf(&tmp, "%s\n", partcode);
1974 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1975 mr_free(tmp);
1976
1977 mr_msg(5, "B - last line = '%s'",
1978 last_line_of_file(FDISK_LOG));
1979
1980 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
1981 mr_msg(5, "C - last line = '%s'",
1982 last_line_of_file(FDISK_LOG));
1983
1984 mr_asprintf(&tmp, last_line_of_file(FDISK_LOG));
1985 if (!strstr(tmp, " (m ")) {
1986 mr_msg(1, "last line = '%s'; part type set failed", tmp);
1987 res++;
1988 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
1989 }
1990 mr_free(tmp);
1991 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
1992 } else {
1993 mr_asprintf(&output, "t\n%d\n%s\nw\n", partno, partcode);
1994 mr_asprintf(&command, "parted2fdisk %s >> %s 2>> %s", drive,
1995 MONDO_LOGFILE, MONDO_LOGFILE);
1996 mr_msg(5, "output = '%s'", output);
1997 mr_msg(5, "partno=%d; partcode=%s", partno, partcode);
1998 mr_msg(5, "command = '%s'", command);
1999 fout = popen(command, "w");
2000 if (!fout) {
2001 log_OS_error(command);
2002 res = 1;
2003 } else {
2004 res = 0;
2005 fprintf(fout, output);
2006 paranoid_pclose(fout);
2007 }
2008 mr_free(command);
2009 mr_free(output);
2010 }
2011 /* BERLIOS: Useless as command not initialized in all cases
2012 if (res) {
2013 log_OS_error(command);
2014 }
2015 */
2016 }
2017
2018 mr_free(partition);
2019 mr_free(partcode);
2020
2021 return (res);
2022}
2023
2024
2025int start_raid_device(char *raid_device)
2026{
2027 /** int *************************************************************/
2028 int res = 0;
2029 int retval = 0;
2030
2031 /** buffers *********************************************************/
2032 char *program = NULL;
2033
2034 /** end *************************************************************/
2035
2036 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2037
2038#ifdef __FreeBSD__
2039 if (is_this_device_mounted(raid_device)) {
2040 log_it("Can't start %s when it's mounted!", raid_device);
2041 return 1;
2042 }
2043 mr_asprintf(&program, "vinum start -f %s", raid_device);
2044#else
2045 // use raidstart if it exists, otherwise use mdadm
2046 if (run_program_and_log_output("which raidstart", FALSE)) {
2047 // BERLIOS: Not sure it's sufficient
2048 mr_asprintf(&program, "mdadm -A %s", raid_device);
2049 } else {
2050 mr_asprintf(&program, "raidstart %s", raid_device);
2051 }
2052#endif
2053 mr_msg(1, "program = %s", program);
2054 res = run_program_and_log_output(program, 1);
2055 if (g_fprep) {
2056 fprintf(g_fprep, "%s\n", program);
2057 }
2058 mr_free(program);
2059
2060 if (res) {
2061 mr_msg(1, "Warning - failed to start RAID device %s",
2062 raid_device);
2063 }
2064 retval += res;
2065 sleep(1);
2066 return (retval);
2067}
2068
2069
2070/**
2071 * Stop @p raid_device using @p raidstop.
2072 * @param raid_device The software RAID device to stop.
2073 * @return 0 for success, nonzero for failure.
2074 */
2075int stop_raid_device(char *raid_device)
2076{
2077 /** int *************************************************************/
2078 int res = 0;
2079 int retval = 0;
2080
2081 /** buffers *********************************************************/
2082 char *program = NULL;
2083
2084 /** end *************************************************************/
2085
2086 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2087
2088#ifdef __FreeBSD__
2089 if (is_this_device_mounted(raid_device)) {
2090 log_it("Can't stop %s when it's mounted!", raid_device);
2091 return 1;
2092 }
2093 mr_asprintf(&program, "vinum stop -f %s", raid_device);
2094#else
2095 // use raidstop if it exists, otherwise use mdadm
2096 if (run_program_and_log_output("which raidstop", FALSE)) {
2097 mr_asprintf(&program, "mdadm -S %s", raid_device);
2098 } else {
2099 mr_asprintf(&program, "raidstop %s", raid_device);
2100 }
2101#endif
2102 mr_msg(1, "program = %s", program);
2103 res = run_program_and_log_output(program, 1);
2104 if (g_fprep) {
2105 fprintf(g_fprep, "%s\n", program);
2106 }
2107 mr_free(program);
2108
2109 if (res) {
2110 mr_msg(1, "Warning - failed to stop RAID device %s", raid_device);
2111 }
2112 retval += res;
2113 return (retval);
2114}
2115
2116
2117int start_all_raid_devices(struct mountlist_itself *mountlist)
2118{
2119 int i = 0;
2120 int retval = 0;
2121 int res = 0;
2122
2123 for (i = 0; i < mountlist->entries; i++) {
2124 if (!strncmp
2125 (mountlist->el[i].device, RAID_DEVICE_STUB,
2126 strlen(RAID_DEVICE_STUB))) {
2127 mr_msg(1, "Starting %s", mountlist->el[i].device);
2128 res = start_raid_device(mountlist->el[i].device);
2129 retval += res;
2130 }
2131 }
2132 if (retval) {
2133 mr_msg(1, "Started all s/w raid devices OK");
2134 } else {
2135 mr_msg(1, "Failed to start some/all s/w raid devices");
2136 }
2137 return (retval);
2138}
2139
2140
2141/**
2142 * Stop all software RAID devices listed in @p mountlist.
2143 * @param mountlist The mountlist to stop the RAID devices in.
2144 * @return The number of errors encountered (0 for success).
2145 * @bug @p mountlist is not used.
2146 */
2147int stop_all_raid_devices(struct mountlist_itself *mountlist)
2148{
2149 /** int *************************************************************/
2150 int retval = 0;
2151#ifndef __FreeBSD__
2152 int res = 0;
2153#endif
2154
2155 /** char ************************************************************/
2156 char *incoming = NULL;
2157#ifndef __FreeBSD__
2158 char *dev = NULL;
2159#endif
2160 /** pointers ********************************************************/
2161#ifndef __FreeBSD__
2162 char *p = NULL;
2163#endif
2164 FILE *fin = NULL;
2165 int i = 0;
2166 size_t n = 0;
2167
2168 /** end ****************************************************************/
2169
2170 assert(mountlist != NULL);
2171
2172 for (i = 0; i < 3; i++) {
2173#ifdef __FreeBSD__
2174 fin =
2175 popen
2176 ("vinum list | grep '^[PVS]' | sed 's/S/1/;s/P/2/;s/V/3/' | sort | cut -d' ' -f2",
2177 "r");
2178 if (!fin) {
2179 return (1);
2180 }
2181 for (mr_getline(&incoming, &n, fin); !feof(fin);
2182 mr_getline(&incoming, &n, fin)) {
2183 retval += stop_raid_device(incoming);
2184 }
2185#else
2186 fin = fopen(MDSTAT_FILE, "r");
2187 if (!fin) {
2188 log_OS_error(MDSTAT_FILE);
2189 return (1);
2190 }
2191 for (mr_getline(&incoming, &n, fin); !feof(fin);
2192 mr_getline(&incoming, &n, fin)) {
2193 for (p = incoming;
2194 *p != '\0' && (*p != 'm' || *(p + 1) != 'd'
2195 || !isdigit(*(p + 2))); p++);
2196 if (*p != '\0') {
2197 mr_asprintf(&dev, "/dev/%s", p);
2198 /* BERLIOS : 32 Hard coded value */
2199 for (p = dev; *p > 32; p++);
2200 *p = '\0';
2201 res = stop_raid_device(dev);
2202 mr_free(dev);
2203 }
2204 }
2205#endif
2206 mr_free(incoming);
2207 }
2208 paranoid_fclose(fin);
2209 if (retval) {
2210 mr_msg(1, "Warning - unable to stop some RAID devices");
2211 }
2212 sync();
2213 sync();
2214 sync();
2215 sleep(1);
2216 return (retval);
2217}
2218
2219
2220/**
2221 * Decide which command we need to use to format a device of type @p format.
2222 * @param format The filesystem type we are about to format.
2223 * @param program Where to put the binary name for this format.
2224 * @return 0 for success, nonzero for failure.
2225 */
2226int which_format_command_do_i_need(char *format, char *program)
2227{
2228 /** int *************************************************************/
2229 int res = 0;
2230
2231 /** end ***************************************************************/
2232
2233 assert_string_is_neither_NULL_nor_zerolength(format);
2234 assert(program != NULL);
2235
2236 if (strcmp(format, "swap") == 0) {
2237#ifdef __FreeBSD__
2238 strcpy(program, "true");
2239#else
2240 strcpy(program, "mkswap");
2241#endif
2242 } else if (strcmp(format, "vfat") == 0) {
2243 strcpy(program, "format-and-kludge-vfat");
2244#ifndef __FreeBSD__
2245 } else if (strcmp(format, "reiserfs") == 0) {
2246 strcpy(program, "mkreiserfs -ff");
2247 } else if (strcmp(format, "xfs") == 0) {
2248 strcpy(program, "mkfs.xfs -f -q");
2249 } else if (strcmp(format, "jfs") == 0) {
2250 strcpy(program, "mkfs.jfs");
2251 } else if (strcmp(format, "ext3") == 0) {
2252 strcpy(program, "mkfs -t ext3 -F -q");
2253 } else if (strcmp(format, "minix") == 0) {
2254 strcpy(program, "mkfs.minix");
2255 } else if (strcmp(format, "vmfs") == 0) {
2256 strcpy(program, "mkfs -t vmfs");
2257#endif
2258 } else if (strcmp(format, "ext2") == 0) {
2259 strcpy(program, "mke2fs -F -q");
2260 } else {
2261#ifdef __FreeBSD__
2262 sprintf(program, "newfs_%s", format);
2263#else
2264 sprintf(program, "mkfs -t %s -c", format); // -c checks for bad blocks
2265#endif
2266 log_it("Unknown format (%s) - assuming '%s' will do", format,
2267 program);
2268 res = 0;
2269 }
2270 return (res);
2271}
2272
2273
2274/**
2275 * Calculate the probable size of @p drive_name by adding up sizes in
2276 * @p mountlist.
2277 * @param mountlist The mountlist to use to calculate the size.
2278 * @param drive_name The drive to calculate the original size of.
2279 * @return The size of @p drive_name in kilobytes.
2280 */
2281long calc_orig_size_of_drive_from_mountlist(struct mountlist_itself
2282 *mountlist, char *drive_name)
2283{
2284 /** long ************************************************************/
2285 long original_size_of_drive = 0L;
2286
2287 /** int *************************************************************/
2288 int partno = 0;
2289
2290 /** end *************************************************************/
2291
2292 assert(mountlist != NULL);
2293 assert_string_is_neither_NULL_nor_zerolength(drive_name);
2294
2295 for (original_size_of_drive = 0, partno = 0;
2296 partno < mountlist->entries; partno++) {
2297 if (strncmp
2298 (mountlist->el[partno].device, drive_name,
2299 strlen(drive_name)) == 0) {
2300 original_size_of_drive += mountlist->el[partno].size;
2301 } else {
2302 log_to_screen("Skipping %s", mountlist->el[partno].device);
2303 }
2304 }
2305 original_size_of_drive = original_size_of_drive / 1024;
2306 return (original_size_of_drive);
2307}
2308
2309
2310/**
2311 * Resize a drive's entries in @p mountlist proportionately to fit its new size.
2312 * There are a few problems with this function:
2313 * - It won't work if there was any unallocated space on the user's hard drive
2314 * when it was backed up.
2315 * - It won't work if the user's hard drive lies about its size (more common
2316 * than you'd think).
2317 *
2318 * @param mountlist The mountlist to use for resizing @p drive_name.
2319 * @param drive_name The drive to resize.
2320 */
2321void resize_drive_proportionately_to_suit_new_drives(struct mountlist_itself
2322 *mountlist,
2323 char *drive_name)
2324{
2325 /** int *************************************************************/
2326 int partno = 0, lastpart = 0;
2327 /** remove driveno, noof_drives stan benoit apr 2002**/
2328
2329 /** float ***********************************************************/
2330 float factor;
2331 float new_size;
2332
2333 /** long *************************************************************/
2334 long newsizL = 0L;
2335 long current_size_of_drive = 0L;
2336 long original_size_of_drive = 0L;
2337 long final_size = 0L; /* all in Megabytes */
2338 struct mountlist_reference *drivemntlist = NULL;
2339
2340 /** structures *******************************************************/
2341
2342 /** end **************************************************************/
2343
2344 assert(mountlist != NULL);
2345 assert_string_is_neither_NULL_nor_zerolength(drive_name);
2346
2347 if (strlen(drive_name) >= strlen(RAID_DEVICE_STUB)) {
2348 if (strncmp(drive_name, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))
2349 == 0) {
2350 return;
2351 }
2352 }
2353
2354 current_size_of_drive = get_phys_size_of_drive(drive_name);
2355
2356 if (current_size_of_drive <= 0) {
2357 log_it("Not resizing to match %s - can't find drive", drive_name);
2358 return;
2359 }
2360 log_to_screen("Expanding entries to suit drive %s (%ld MB)", drive_name,
2361 current_size_of_drive);
2362
2363 drivemntlist = mr_malloc(sizeof(struct mountlist_reference));
2364 drivemntlist->el =
2365 mr_malloc(sizeof(struct mountlist_line *) * MAX_TAPECATALOG_ENTRIES);
2366
2367 create_mountlist_for_drive(mountlist, drive_name, drivemntlist);
2368
2369 for (partno = 0; partno < drivemntlist->entries; partno++) {
2370 original_size_of_drive += drivemntlist->el[partno]->size;
2371 }
2372 original_size_of_drive = original_size_of_drive / 1024;
2373
2374 if (original_size_of_drive <= 0) {
2375 log_to_screen(_("Cannot resize %s's entries. Drive not found."),
2376 drive_name);
2377 return;
2378 }
2379 factor =
2380 (float) (current_size_of_drive) / (float) (original_size_of_drive);
2381 log_to_screen(_("Disk %s was %ld MB; is now %ld MB; factor = %f"),
2382 drive_name, original_size_of_drive, current_size_of_drive,
2383 factor);
2384
2385 lastpart = drivemntlist->entries - 1;
2386 for (partno = 0; partno < drivemntlist->entries; partno++) {
2387 /* the 'atoi' thing is to make sure we don't try to resize _images_, whose formats will be numeric */
2388 if (!atoi(drivemntlist->el[partno]->format)) {
2389 new_size = (float) (drivemntlist->el[partno]->size) * factor;
2390 } else {
2391 new_size = drivemntlist->el[partno]->size;
2392 }
2393
2394 if (!strcmp(drivemntlist->el[partno]->mountpoint, "image")) {
2395 mr_msg(1, "Skipping %s (%s) because it's an image",
2396 drivemntlist->el[partno]->device,
2397 drivemntlist->el[partno]->mountpoint);
2398 newsizL = (long) new_size; // It looks wrong but it's not
2399 } else {
2400 newsizL = (long) new_size;
2401 }
2402 log_to_screen(_("Changing %s from %lld KB to %ld KB"),
2403 drivemntlist->el[partno]->device,
2404 drivemntlist->el[partno]->size, newsizL);
2405 drivemntlist->el[partno]->size = newsizL;
2406 }
2407 final_size = get_phys_size_of_drive(drive_name);
2408 log_to_screen(_("final_size = %ld MB"), final_size);
2409}
2410
2411
2412/**
2413 * Resize all partitions in @p mountlist proportionately (each one
2414 * grows or shrinks by the same percentage) to fit them into the new
2415 * drives (presumably different from the old ones).
2416 * @param mountlist The mountlist to resize the drives in.
2417 */
2418void resize_mountlist_proportionately_to_suit_new_drives(struct mountlist_itself
2419 *mountlist)
2420{
2421 /** buffers *********************************************************/
2422 struct list_of_disks *drivelist = NULL;
2423
2424 /** int *************************************************************/
2425 int driveno = 0;
2426
2427 /** end *************************************************************/
2428
2429 drivelist = mr_malloc(sizeof(struct list_of_disks));
2430
2431 if (g_mountlist_fname[0] == '\0') {
2432 log_it
2433 ("resize_mountlist_prop...() - warning - mountlist fname is blank");
2434 log_it("That does NOT affect the functioning of this subroutine.");
2435 }
2436 iamhere("Resizing mountlist");
2437 make_list_of_drives_in_mountlist(mountlist, drivelist);
2438 iamhere("Back from MLoDiM");
2439 for (driveno = 0; driveno < drivelist->entries; driveno++) {
2440 resize_drive_proportionately_to_suit_new_drives(mountlist,
2441 drivelist->
2442 el[driveno].
2443 device);
2444 }
2445 log_to_screen(_("Mountlist adjusted to suit current hard drive(s)"));
2446 mr_free(drivelist);
2447}
2448
2449/**
2450 * Create a mountlist_reference structure for @p drive_name in @p mountlist.
2451 * @param mountlist The complete mountlist to get the drive references from.
2452 * @param drive_name The drive to put in @p drivemntlist.
2453 * @param drivemntlist The mountlist_reference structure to put the drive's entries in.
2454 * @note @p drivemntlist and @p drivemntlist->el must be allocated by the caller.
2455 * @author Ralph Grewe
2456 */
2457void create_mountlist_for_drive(struct mountlist_itself *mountlist,
2458 char *drive_name,
2459 struct mountlist_reference *drivemntlist)
2460{
2461 int partno = 0;
2462 char *tmp_drive_name = NULL, *c = NULL;
2463
2464 assert(mountlist != NULL);
2465 assert(drive_name != NULL);
2466 assert(drivemntlist != NULL);
2467
2468 mr_msg(1, "Creating list of partitions for drive %s", drive_name);
2469
2470 mr_asprintf(&tmp_drive_name, drive_name);
2471
2472 /* devfs devices? */
2473 c = strrchr(tmp_drive_name, '/');
2474 if (c && strncmp(c, "/disc", 5) == 0) {
2475 /* yup its devfs, change the "disc" to "part" so the existing code works */
2476 strncpy(c + 1, "part", (size_t)5);
2477 }
2478 drivemntlist->entries = 0;
2479 for (partno = 0; partno < mountlist->entries; partno++) {
2480 if (strncmp
2481 (mountlist->el[partno].device, tmp_drive_name,
2482 strlen(tmp_drive_name)) == 0) {
2483 drivemntlist->el[drivemntlist->entries] =
2484 &mountlist->el[partno];
2485 drivemntlist->entries++;
2486 }
2487 }
2488 mr_free(tmp_drive_name);
2489}
2490
2491/* @} - end of prepGroup */
Note: See TracBrowser for help on using the repository browser.