source: branches/3.2/mondo/src/mondorestore/mondo-prep.c @ 3435

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