source: MondoRescue/branches/3.0/mondo/src/mondorestore/mondo-prep.c @ 3044

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