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

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