source: MondoRescue/branches/3.1/mondo/src/mondorestore/mondo-prep.c@ 2937

Last change on this file since 2937 was 2937, checked in by Bruno Cornec, 12 years ago

svn merge -r 2849:2935 ../3.0

  • Adds 3 binaries called potentially by udev o support USB key mount at restore time (Victor Gattegno)
  • mindi only sets the boot flag of a USB device if none is present already (should avoid flip/flop situation)
  • Fix a compatibility bug in analyze-my-lvm whete exclude lists with '|' was incorrectly analyzed (' ' still expected)
  • Precise that -J is not supported by mondorestore yet.
  • Fix a compatibility bug in mindi where exclude lists with '|' was incorrectly analyzed (' ' still expected)
  • Install an MBR on USB devices when possible
  • Improve error message in case mondorestore isn't found
  • Adds support for more virtio devices for KVM restore
  • Improve mbr.bin handling
  • Fix an issue in test of FindKernel for Xen and non Xen cases
    • Fix #492 by removing an extra useless fi
    • Move fvat nd fat modules to CDROM_MODS in order to have them in the initrd to support saving logs to a USB device e.g.
    • Fix an error when dmidecode reports comments before system name
    • Fix previous broken patch on comment management for bkphw
    • Improve msgs printed during kbd analysis
    • Fix a small remaining pb with new comment support
    • Try to again improve the mount/umount stuff in mondo -Adds mention to OEL, CentOS, ScientifLinux as RHEL clones
  • Fix a panadoid_free done on the wrong variable (solve a memory leak)
  • Solve #495 by skipping the potential (auto-read-only) when analyzin /proc/mdstat result
  • Fix some markup in man pages
  • adds the post-nuke script sample for Debian (Guillaume Pernot/Andrée Leidenfrost)
  • Avoid a useless umount when changing of afio set, let insist_on_cd check and perform if needed
  • Copy everything under .ssh of root account to allow for sshfs mount without passwd at restore time.
  • Adds support for bnx2i driver
  • Try to fix #496 by supporting the protocol in the output of the mount command (sshfs#...)
  • Uses the -d option of the mount command to avoid leaving loop devices in use. Probably provoked by the usage of a more recent busybox, but anyway that option doesn't hurt, and does nothing for non-loop devices. Should fix the problems reported on the ML with NFS and more than 8 ISO images (8 being the default number of loop devices available)
  • Attempt to fix #436 by adding some newtDrawForm where appropriate.
  • Fix bugs in the kernel detection routine of mindi (some echo were done without capturing their output, confusing the return). This should also help the Xen detection issue
  • Change the logging function to be nearer from 2.2.10, and start using some
  • Initialize some global fields with an empty string, now that newt Draws more regularly progress forms
  • Mindi progression still not good, but showing now 3% when calling mindi. Would need a specific handling for the progress bar to evolve more afterwards
  • Add compatibility with the latest SSSTK + PSP content for HP ProLiant + branding homogeneous now. We only take conrep out of the SSSTK pending a package availability. Using hpacuscripting now. Review of parameters called following test made.
  • Fix #501 by pushing BOOT_SIZE to 36864 for certain Ubuntu cases
  • Fix some remaining inconsistencis in the ProLiant HW backup. ready for usage.
  • Fix an issue on udevadm call (needs an intermediate variable)
  • Fix a remaining ProLiant tool call
  • Remove again some wrong variable initialization for Net in order to not have strange messages now we call Draw more often
  • Adds support for hwaddr (MAC addresses) at restore time, and map to the correct NIC if it's found at restore time (based on code from Stefan Heijmans)
  • Try to Fix #499 by changing init in order to never exit, and rebooting using sysrq in /proc (not portable). Maybe should move to using a real init, and a separated rcS script.
  • Fixes the shell msg error by using setsid as per Busybox FAQ
  • Fix #491 by correctly checking Xen kernel used for a dom0 env (apollo13)
  • Improves logging in Die()
  • Improve again ProLiant HW support, by adding references to the yet to come SSSTK rpm so that conrep is called at its future right place.
  • Improve mindi support for kernel 3.x
  • Fix #499 for good, by using a real init from busybox and moving our init script to etc/init.d/rcS. We also now call the reboot from busybox to exit, which indeed reset the system correctly (in a VM at least which wasn't the case before). Reauires a new mindi-busybox as well.
  • Attempt to solve #503 by handling /lib64 separately for udev and only if not a link (to /lib) for Ubuntu 64
  • Improve again previous tests for bug #503
  • Improve -d option description for NFS
  • Allow http download for ftp content
  • New italian mirror
  • Fix #505 by documenting environment variables
    • Fix a bug where on OBDR mode compression was turned off to create the OBDR content but not back on (report from the mailing list)
  • solve http://trac.mondorescue.org/ticket/520 by Victor Gattegno
  • Fix #524 as option -U needs a size also
  • Removes useless gendf option
  • Fix #511 now stabgrub is called also after conf file modifications
  • Adds support for SUID binaries
  • remove a useless xenkernelname variable from mindi
  • Should fix #512 by clearing old scratchdir before changing to a new
  • Simplify the function engaging SCSI for Smart Array controllers, and support as many controller as we have
  • Add some binaries used on SLES 10 by udev
  • Fix a syntax issue in newt-specific.c
  • Fix a memory free bug where a used variable was freed to early
  • Fix a memory free bug where a used variable was misused in asprintf/free
  • Fix #498 by using an external program (hpsa_obdr_mode) which can set the mode of the tape to CD-ROM or Sequential at will.

That program will have to be downloaded from http://cciss.sf.net

  • Adds support for the route command in mindi-busybox
  • Force block size back to 32768 in OBDR mode after skipping the 2 tape marks, to read the additional rootfs data corerctly - Fix #498 for good it seems
  • Adds support for a new pata_atiixp driver
  • Fix #525 and improve printing when no /etc/raidtab, but still md devices
  • Exclude /run similarly to /sys and /proc
  • Fix a bug in mindi when having multiple swap partiions with same starting string (/dev/dm-1 and /dev/dm-16). We now add a space in the grep to avoid mischoice.
  • Fix grub installation if we had to go in the hack part which wasn't using the correct variables to make decisions !
  • Remove all mention of mondorescue.com from code
  • Fix some website typo on the download page and precise that we now develop on Mageia
  • Exclude sysfs devpts and tmpfs partitions found in RHEL 6.2 from analyze by mindi (made error messages)
  • Force activation of first partition which should not be optional as everything is destroyed before
  • Fix a bug in analyze-my-lvm where LVs were created in random order (the one of lvscan) instead of using the dm-xxx order, which creates issues at restore time between the mapping created then and the one we had at backup time which could be inconssistent

-mondoarchive now exists if the mt command is missing when needed

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