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

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