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

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