~vcs-imports/ipfire/ipfire-2.x

« back to all changes in this revision

Viewing changes to src/installer/main.c

  • Committer: Dirk Wagner
  • Date: 2014-12-23 08:02:23 UTC
  • mfrom: (4405.56.108)
  • Revision ID: git-v1:601f8347ccb1e9c5e3f250ff26d4097ecd698875
Merge branch 'next' of ssh://git.ipfire.org/pub/git/ipfire-2.x into asterisk-update

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* SmoothWall install program.
 
2
 *
 
3
 * This program is distributed under the terms of the GNU General Public
 
4
 * Licence.  See the file COPYING for details.
 
5
 *
 
6
 * (c) Lawrence Manning, 2001
 
7
 * Contains main entry point, and misc functions.6
 
8
 * 
 
9
 */
 
10
#define _GNU_SOURCE
 
11
 
 
12
#include <assert.h>
 
13
#include <errno.h>
 
14
#include <libsmooth.h>
 
15
#include <stdio.h>
 
16
#include <stdlib.h>
 
17
#include <string.h>
 
18
#include <sys/mount.h>
 
19
 
 
20
#include "hw.h"
 
21
 
 
22
// Translation
 
23
#include <libintl.h>
 
24
#define _(x) dgettext("installer", x)
 
25
 
 
26
#define INST_FILECOUNT 21000
 
27
#define LICENSE_FILE    "/cdrom/COPYING"
 
28
#define SOURCE_TEMPFILE "/tmp/downloads/image.iso"
 
29
 
 
30
extern char url[STRING_SIZE];
 
31
 
 
32
static int newtChecklist(const char* title, const char* message,
 
33
                unsigned int width, unsigned int height, unsigned int num_entries,
 
34
                const char** entries, int* states) {
 
35
        int ret;
 
36
        const int list_height = 4;
 
37
 
 
38
        char cbstates[num_entries];
 
39
 
 
40
        for (unsigned int i = 0; i < num_entries; i++) {
 
41
                cbstates[i] = states[i] ? '*' : ' ';
 
42
        }
 
43
 
 
44
        newtCenteredWindow(width, height, title);
 
45
 
 
46
        newtComponent textbox = newtTextbox(1, 1, width - 2, height - 6 - list_height,
 
47
                NEWT_FLAG_WRAP);
 
48
        newtTextboxSetText(textbox, message);
 
49
 
 
50
        int top = newtTextboxGetNumLines(textbox) + 2;
 
51
 
 
52
        newtComponent form = newtForm(NULL, NULL, 0);
 
53
 
 
54
        newtComponent sb = NULL;
 
55
        if (list_height < num_entries) {
 
56
                sb = newtVerticalScrollbar(
 
57
                        width - 4, top + 1, list_height,
 
58
                        NEWT_COLORSET_CHECKBOX, NEWT_COLORSET_ACTCHECKBOX);
 
59
 
 
60
                newtFormAddComponent(form, sb);
 
61
        }
 
62
 
 
63
        newtComponent subform = newtForm(sb, NULL, 0);
 
64
        newtFormSetBackground(subform, NEWT_COLORSET_CHECKBOX);
 
65
 
 
66
        newtFormSetHeight(subform, list_height);
 
67
        newtFormSetWidth(subform, width - 10);
 
68
 
 
69
        for (unsigned int i = 0; i < num_entries; i++) {
 
70
                newtComponent cb = newtCheckbox(4, top + i, entries[i], cbstates[i],
 
71
                        NULL, &cbstates[i]);
 
72
 
 
73
                newtFormAddComponent(subform, cb);
 
74
        }
 
75
 
 
76
        newtFormAddComponents(form, textbox, subform, NULL);
 
77
 
 
78
        newtComponent btn_okay   = newtButton((width - 18) / 3, height - 4, _("OK"));
 
79
        newtComponent btn_cancel = newtButton((width - 18) / 3 * 2 + 9, height - 4, _("Cancel"));
 
80
        newtFormAddComponents(form, btn_okay, btn_cancel, NULL);
 
81
 
 
82
        newtComponent answer = newtRunForm(form);
 
83
 
 
84
        if ((answer == NULL) || (answer == btn_cancel)) {
 
85
                ret = -1;
 
86
        } else {
 
87
                ret = 0;
 
88
 
 
89
                for (unsigned int i = 0; i < num_entries; i++) {
 
90
                        states[i] = (cbstates[i] != ' ');
 
91
 
 
92
                        if (states[i])
 
93
                                ret++;
 
94
                }
 
95
        }
 
96
 
 
97
        newtFormDestroy(form);
 
98
        newtPopWindow();
 
99
 
 
100
        return ret;
 
101
}
 
102
 
 
103
static int newtWinOkCancel(const char* title, const char* message, int width, int height,
 
104
                const char* btn_txt_ok, const char* btn_txt_cancel) {
 
105
        int ret = 1;
 
106
 
 
107
        unsigned int btn_width_ok = strlen(btn_txt_ok);
 
108
        unsigned int btn_width_cancel = strlen(btn_txt_cancel);
 
109
 
 
110
        // Maybe make the box wider to fix both buttons inside
 
111
        unsigned int min_width = btn_width_ok + btn_width_cancel + 5;
 
112
        if (width < min_width)
 
113
                width = min_width;
 
114
 
 
115
        unsigned int btn_pos_ok = (width / 3) - (btn_width_ok / 2) - 1;
 
116
        unsigned int btn_pos_cancel = (width * 2 / 3) - (btn_width_cancel / 2) - 1;
 
117
 
 
118
        // Move buttons a bit if they overlap
 
119
        while ((btn_pos_ok + btn_width_ok + 5) > btn_pos_cancel) {
 
120
                // Move the cancel button to the right if there is enough space left
 
121
                if ((btn_pos_cancel + btn_width_cancel + 2) < width) {
 
122
                        ++btn_pos_cancel;
 
123
                        continue;
 
124
                }
 
125
 
 
126
                // Move the OK button to the left if possible
 
127
                if (btn_pos_ok > 1) {
 
128
                        --btn_pos_ok;
 
129
                        continue;
 
130
                }
 
131
 
 
132
                // If they still overlap, we cannot fix the situtation
 
133
                // and break. Should actually never get here, because we
 
134
                // adjust the width of the window earlier.
 
135
                break;
 
136
        }
 
137
 
 
138
        newtCenteredWindow(width, height, title);
 
139
 
 
140
        newtComponent form = newtForm(NULL, NULL, 0);
 
141
 
 
142
        newtComponent textbox = newtTextbox(1, 1, width - 2, height - 6, NEWT_FLAG_WRAP);
 
143
        newtTextboxSetText(textbox, message);
 
144
        newtFormAddComponent(form, textbox);
 
145
 
 
146
        newtComponent btn_ok = newtButton(btn_pos_ok, height - 4, btn_txt_ok);
 
147
        newtComponent btn_cancel = newtButton(btn_pos_cancel, height - 4, btn_txt_cancel);
 
148
 
 
149
        newtFormAddComponents(form, btn_ok, btn_cancel, NULL);
 
150
 
 
151
        newtComponent answer = newtRunForm(form);
 
152
 
 
153
        if (answer == btn_ok) {
 
154
                ret = 0;
 
155
        }
 
156
 
 
157
        newtFormDestroy(form);
 
158
        newtPopWindow();
 
159
 
 
160
        return ret;
 
161
}
 
162
 
 
163
static int newtLicenseBox(const char* title, const char* text, int width, int height) {
 
164
        int ret = 1;
 
165
 
 
166
        newtCenteredWindow(width, height, title);
 
167
 
 
168
        newtComponent form = newtForm(NULL, NULL, 0);
 
169
 
 
170
        newtComponent textbox = newtTextbox(1, 1, width - 2, height - 7,
 
171
                NEWT_FLAG_WRAP|NEWT_FLAG_SCROLL);
 
172
        newtTextboxSetText(textbox, text);
 
173
        newtFormAddComponent(form, textbox);
 
174
 
 
175
        char choice;
 
176
        newtComponent checkbox = newtCheckbox(3, height - 3, _("I accept this license"),
 
177
                ' ', " *", &choice);
 
178
 
 
179
        newtComponent btn = newtButton(width - 15, height - 4, _("OK"));
 
180
 
 
181
        newtFormAddComponents(form, checkbox, btn, NULL);
 
182
 
 
183
        newtComponent answer = newtRunForm(form);
 
184
        if (answer == btn && choice == '*')
 
185
                ret = 0;
 
186
 
 
187
        newtFormDestroy(form);
 
188
        newtPopWindow();
 
189
 
 
190
        return ret;
 
191
}
 
192
 
 
193
int write_lang_configs(char* lang) {
 
194
        struct keyvalue *kv = initkeyvalues();
 
195
 
 
196
        /* default stuff for main/settings. */
 
197
        replacekeyvalue(kv, "LANGUAGE", lang);
 
198
        replacekeyvalue(kv, "HOSTNAME", SNAME);
 
199
        replacekeyvalue(kv, "THEME", "ipfire");
 
200
        writekeyvalues(kv, "/harddisk" CONFIG_ROOT "/main/settings");
 
201
        freekeyvalues(kv);
 
202
 
 
203
        return 1;
 
204
}
 
205
 
 
206
static char* get_system_release() {
 
207
        char system_release[STRING_SIZE] = "\0";
 
208
 
 
209
        FILE* f = fopen("/etc/system-release", "r");
 
210
        if (f) {
 
211
                fgets(system_release, sizeof(system_release), f);
 
212
                fclose(f);
 
213
        }
 
214
 
 
215
        return strdup(system_release);
 
216
}
 
217
 
 
218
static char* center_string(const char* str, int width) {
 
219
        unsigned int str_len = strlen(str);
 
220
 
 
221
        unsigned int indent_length = (width - str_len) / 2;
 
222
        char indent[indent_length + 1];
 
223
 
 
224
        for (unsigned int i = 0; i < indent_length; i++) {
 
225
                indent[i] = ' ';
 
226
        }
 
227
        indent[indent_length] = '\0';
 
228
 
 
229
        char* string = NULL;
 
230
        if (asprintf(&string, "%s%s", indent, str) < 0)
 
231
                return NULL;
 
232
 
 
233
        return string;
 
234
}
 
235
 
 
236
#define DEFAULT_LANG "English"
 
237
#define NUM_LANGS 10
 
238
 
 
239
static struct lang {
 
240
        const char* code;
 
241
        char* name;
 
242
} languages[NUM_LANGS + 1] = {
 
243
        { "da.utf8",    "Danish (Dansk)" },
 
244
        { "nl_NL.utf8", "Dutch (Nederlands)" },
 
245
        { "en_US.utf8", "English" },
 
246
        { "fr_FR.utf8", "French (Français)" },
 
247
        { "de_DE.utf8", "German (Deutsch)" },
 
248
        { "pl_PL.utf8", "Polish (Polski)" },
 
249
        { "pt_BR.utf8", "Portuguese (Brasil)" },
 
250
        { "ru_RU.utf8", "Russian (Русский)" },
 
251
        { "es_ES.utf8", "Spanish (Español)" },
 
252
        { "tr_TR.utf8", "Turkish (Türkçe)" },
 
253
        { NULL, NULL },
 
254
};
 
255
 
 
256
static struct config {
 
257
        int unattended;
 
258
        int serial_console;
 
259
        int require_networking;
 
260
        int perform_download;
 
261
        int disable_swap;
 
262
        char download_url[STRING_SIZE];
 
263
        char postinstall[STRING_SIZE];
 
264
} config = {
 
265
        .unattended = 0,
 
266
        .serial_console = 0,
 
267
        .require_networking = 0,
 
268
        .perform_download = 0,
 
269
        .disable_swap = 0,
 
270
        .download_url = DOWNLOAD_URL,
 
271
        .postinstall = "\0",
 
272
};
 
273
 
 
274
static void parse_command_line(struct config* c) {
 
275
        char buffer[STRING_SIZE];
 
276
        char cmdline[STRING_SIZE];
 
277
 
 
278
        FILE* f = fopen("/proc/cmdline", "r");
 
279
        if (!f)
 
280
                return;
 
281
 
 
282
        int r = fread(&cmdline, 1, sizeof(cmdline) - 1, f);
 
283
        if (r > 0) {
 
284
                char* token = strtok(cmdline, " ");
 
285
 
 
286
                while (token) {
 
287
                        strncpy(buffer, token, sizeof(buffer));
 
288
                        char* val = buffer;
 
289
                        char* key = strsep(&val, "=");
 
290
 
 
291
                        // serial console
 
292
                        if ((strcmp(key, "console") == 0) && (strncmp(val, "ttyS", 4) == 0))
 
293
                                c->serial_console = 1;
 
294
 
 
295
                        // enable networking?
 
296
                        else if (strcmp(token, "installer.net") == 0)
 
297
                                c->require_networking = 1;
 
298
 
 
299
                        // unattended mode
 
300
                        else if (strcmp(token, "installer.unattended") == 0)
 
301
                                c->unattended = 1;
 
302
 
 
303
                        // disable swap
 
304
                        else if (strcmp(token, "installer.disable-swap") == 0)
 
305
                                c->disable_swap = 1;
 
306
 
 
307
                        // download url
 
308
                        else if (strcmp(key, "installer.download-url") == 0) {
 
309
                                strncpy(c->download_url, val, sizeof(c->download_url));
 
310
                                c->perform_download = 1;
 
311
 
 
312
                                // Require networking for the download
 
313
                                c->require_networking = 1;
 
314
 
 
315
                        // postinstall script
 
316
                        } else if (strcmp(key, "installer.postinstall") == 0) {
 
317
                                strncpy(c->postinstall, val, sizeof(c->postinstall));
 
318
 
 
319
                                // Require networking for the download
 
320
                                c->require_networking = 1;
 
321
                        }
 
322
 
 
323
                        token = strtok(NULL, " ");
 
324
                }
 
325
        }
 
326
 
 
327
        fclose(f);
 
328
}
 
329
 
 
330
int main(int argc, char *argv[]) {
 
331
        struct hw* hw = hw_init();
 
332
        const char* logfile = NULL;
 
333
 
 
334
        // Read /etc/system-release
 
335
        char* system_release = get_system_release();
 
336
 
 
337
        char discl_msg[40000] = "Disclaimer\n";
 
338
 
 
339
        char* sourcedrive = NULL;
 
340
        int rc = 0;
 
341
        char commandstring[STRING_SIZE];
 
342
        int choice;
 
343
        char language[STRING_SIZE];
 
344
        char message[STRING_SIZE];
 
345
        char title[STRING_SIZE];
 
346
        int allok = 0;
 
347
        FILE *copying;
 
348
 
 
349
        setlocale(LC_ALL, "");
 
350
        sethostname(SNAME, 10);
 
351
 
 
352
        /* Log file/terminal stuff. */
 
353
        FILE* flog = NULL;
 
354
        if (argc >= 2) {
 
355
                logfile = argv[1];
 
356
 
 
357
                if (!(flog = fopen(logfile, "w+")))
 
358
                        return 0;
 
359
        } else {
 
360
                return 0;
 
361
        }
 
362
 
 
363
        fprintf(flog, "Install program started.\n");
 
364
                
 
365
        newtInit();
 
366
        newtCls();
 
367
 
 
368
        // Determine the size of the screen
 
369
        int screen_cols = 0;
 
370
        int screen_rows = 0;
 
371
 
 
372
        newtGetScreenSize(&screen_cols, &screen_rows);
 
373
 
 
374
        // Draw title
 
375
        char* roottext = center_string(system_release, screen_cols);
 
376
        newtDrawRootText(0, 0, roottext);
 
377
 
 
378
        snprintf(title, sizeof(title), "%s - %s", NAME, SLOGAN);
 
379
 
 
380
        // Parse parameters from the kernel command line
 
381
        parse_command_line(&config);
 
382
 
 
383
        if (config.unattended) {
 
384
                splashWindow(title, _("Warning: Unattended installation will start in 10 seconds..."), 10);
 
385
        }
 
386
 
 
387
        // Load common modules
 
388
        mysystem(logfile, "/sbin/modprobe vfat"); // USB key
 
389
        hw_stop_all_raid_arrays(logfile);
 
390
 
 
391
        if (!config.unattended) {
 
392
                // Language selection
 
393
                char* langnames[NUM_LANGS + 1];
 
394
 
 
395
                for (unsigned int i = 0; i < NUM_LANGS; i++) {
 
396
                        if (strcmp(languages[i].name, DEFAULT_LANG) == 0)
 
397
                                choice = i;
 
398
 
 
399
                        langnames[i] = languages[i].name;
 
400
                }
 
401
                langnames[NUM_LANGS] = NULL;
 
402
 
 
403
                rc = newtWinMenu(_("Language selection"), _("Select the language you wish to use for the installation."),
 
404
                        50, 5, 5, 8, langnames, &choice, _("OK"), NULL);
 
405
 
 
406
                assert(choice <= NUM_LANGS);
 
407
 
 
408
                fprintf(flog, "Selected language: %s (%s)\n", languages[choice].name, languages[choice].code);
 
409
                snprintf(language, sizeof(language), "%s", languages[choice].code);
 
410
 
 
411
                setenv("LANGUAGE", language, 1);
 
412
                setlocale(LC_ALL, language);
 
413
        }
 
414
 
 
415
        // Set helpline
 
416
        char* helpline = NULL;
 
417
        if (config.unattended)
 
418
                helpline = center_string(_("Unattended mode"), screen_cols);
 
419
        else
 
420
                helpline = center_string(_("<Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen"), screen_cols);
 
421
 
 
422
        newtPushHelpLine(helpline);
 
423
 
 
424
        if (!config.unattended) {
 
425
                snprintf(message, sizeof(message),
 
426
                        _("Welcome to the %s installation program.\n\n"
 
427
                        "Selecting Cancel on any of the following screens will reboot the computer."), NAME);
 
428
                newtWinMessage(title, _("Start installation"), message);
 
429
        }
 
430
 
 
431
        /* Search for a source drive that holds the right
 
432
         * version of the image we are going to install. */
 
433
        if (!config.perform_download) {
 
434
                sourcedrive = hw_find_source_medium(hw);
 
435
                fprintf(flog, "Source drive: %s\n", sourcedrive);
 
436
        }
 
437
 
 
438
        /* If we could not find a source drive, we will try
 
439
         * downloading the install image */
 
440
        if (!sourcedrive)
 
441
                config.perform_download = 1;
 
442
 
 
443
        if (config.perform_download) {
 
444
                if (!config.unattended) {
 
445
                        // Show the right message to the user
 
446
                        char reason[STRING_SIZE];
 
447
                        if (config.perform_download) {
 
448
                                snprintf(reason, sizeof(reason),
 
449
                                        _("The installer will now try downloading the installation image."));
 
450
                        } else {
 
451
                                snprintf(reason, sizeof(reason),
 
452
                                        _("No source drive could be found.\n\n"
 
453
                                        "You can try downloading the required installation image."));
 
454
                        }
 
455
                        snprintf(message, sizeof(message), "%s %s", reason,
 
456
                                _("Please make sure to connect your machine to a network and "
 
457
                                "the installer will try connect to acquire an IP address."));
 
458
 
 
459
                        rc = newtWinOkCancel(title, message, 55, 12,
 
460
                                _("Download installation image"), _("Cancel"));
 
461
 
 
462
                        if (rc != 0)
 
463
                                goto EXIT;
 
464
                }
 
465
 
 
466
                // Make sure that we enable networking before download
 
467
                config.require_networking = 1;
 
468
        }
 
469
 
 
470
        // Try starting the networking if we require it
 
471
        if (config.require_networking) {
 
472
                while (1) {
 
473
                        statuswindow(60, 4, title, _("Trying to start networking (DHCP)..."));
 
474
 
 
475
                        rc = hw_start_networking(logfile);
 
476
                        newtPopWindow();
 
477
 
 
478
                        // Networking was successfully started
 
479
                        if (rc == 0) {
 
480
                                break;
 
481
 
 
482
                        // An error happened, ask the user what to do
 
483
                        } else {
 
484
                                rc = newtWinOkCancel(title, _("Networking could not be started "
 
485
                                        "but is required to go on with the installation.\n\n"
 
486
                                        "Please connect your machine to a network with a "
 
487
                                        "DHCP server and retry."), 50, 10, _("Retry"), _("Cancel"));
 
488
 
 
489
                                if (rc)
 
490
                                        goto EXIT;
 
491
                        }
 
492
                }
 
493
 
 
494
                // Download the image if required
 
495
                if (config.perform_download) {
 
496
                        fprintf(flog, "Download URL: %s\n", config.download_url);
 
497
                        snprintf(commandstring, sizeof(commandstring), "/usr/bin/downloadsource.sh %s %s",
 
498
                                SOURCE_TEMPFILE, config.download_url);
 
499
 
 
500
                        while (!sourcedrive) {
 
501
                                rc = runcommandwithstatus(commandstring, title, _("Downloading installation image..."), logfile);
 
502
 
 
503
                                FILE* f = fopen(SOURCE_TEMPFILE, "r");
 
504
                                if (f) {
 
505
                                        sourcedrive = strdup(SOURCE_TEMPFILE);
 
506
                                        fclose(f);
 
507
                                } else {
 
508
                                        char reason[STRING_SIZE] = "-";
 
509
                                        if (rc == 2)
 
510
                                                snprintf(reason, sizeof(STRING_SIZE), _("MD5 checksum mismatch"));
 
511
 
 
512
                                        snprintf(message, sizeof(message),
 
513
                                                _("The installation image could not be downloaded.\n  Reason: %s\n\n%s"),
 
514
                                                reason, config.download_url);
 
515
 
 
516
                                        rc = newtWinOkCancel(title, message, 75, 12, _("Retry"), _("Cancel"));
 
517
                                        if (rc)
 
518
                                                goto EXIT;
 
519
                                }
 
520
                        }
 
521
                }
 
522
        }
 
523
 
 
524
        assert(sourcedrive);
 
525
 
 
526
        int r = hw_mount(sourcedrive, SOURCE_MOUNT_PATH, "iso9660", MS_RDONLY);
 
527
        if (r) {
 
528
                snprintf(message, sizeof(message), _("Could not mount %s to %s:\n  %s\n"),
 
529
                        sourcedrive, SOURCE_MOUNT_PATH, strerror(errno));
 
530
                errorbox(message);
 
531
                goto EXIT;
 
532
        }
 
533
 
 
534
        if (!config.unattended) {
 
535
                // Read the license file.
 
536
                if (!(copying = fopen(LICENSE_FILE, "r"))) {
 
537
                        sprintf(discl_msg, "Could not open license file: %s\n", LICENSE_FILE);
 
538
                        fprintf(flog, "%s", discl_msg);
 
539
                } else {
 
540
                        fread(discl_msg, 1, 40000, copying);
 
541
                        fclose(copying);
 
542
 
 
543
                        if (newtLicenseBox(_("License Agreement"), discl_msg, 75, 20)) {
 
544
                                errorbox(_("License not accepted!"));
 
545
 
 
546
                                goto EXIT;
 
547
                        }
 
548
                }
 
549
        }
 
550
 
 
551
        int part_type = HW_PART_TYPE_NORMAL;
 
552
 
 
553
        // Scan for disks to install on.
 
554
        struct hw_disk** disks = hw_find_disks(hw, sourcedrive);
 
555
 
 
556
        struct hw_disk** selected_disks = NULL;
 
557
        unsigned int num_selected_disks = 0;
 
558
 
 
559
        // Check how many disks have been found and what
 
560
        // we can do with them.
 
561
        unsigned int num_disks = hw_count_disks((const struct hw_disk**)disks);
 
562
 
 
563
        while (1) {
 
564
                // no harddisks found
 
565
                if (num_disks == 0) {
 
566
                        errorbox(_("No hard disk found."));
 
567
                        goto EXIT;
 
568
 
 
569
                // exactly one disk has been found
 
570
                // or if we are running in unattended mode, we will select
 
571
                // the first disk and go with that one
 
572
                } else if ((num_disks == 1) || (config.unattended && num_disks >= 1)) {
 
573
                        selected_disks = hw_select_first_disk((const struct hw_disk**)disks);
 
574
 
 
575
                // more than one usable disk has been found and
 
576
                // the user needs to choose what to do with them
 
577
                } else {
 
578
                        const char* disk_names[num_disks];
 
579
                        int disk_selection[num_disks];
 
580
 
 
581
                        for (unsigned int i = 0; i < num_disks; i++) {
 
582
                                disk_names[i] = disks[i]->description;
 
583
                                disk_selection[i] = 0;
 
584
                        }
 
585
 
 
586
                        while (!selected_disks) {
 
587
                                rc = newtChecklist(_("Disk Selection"),
 
588
                                        _("Select the disk(s) you want to install IPFire on. "
 
589
                                        "First those will be partitioned, and then the partitions will have a filesystem put on them.\n\n"
 
590
                                        "ALL DATA ON THE DISK WILL BE DESTROYED."),
 
591
                                        50, 20, num_disks, disk_names, disk_selection);
 
592
 
 
593
                                // Error
 
594
                                if (rc < 0) {
 
595
                                        goto EXIT;
 
596
 
 
597
                                // Nothing has been selected
 
598
                                } else if (rc == 0) {
 
599
                                        errorbox(_("No disk has been selected.\n\n"
 
600
                                                "Please select one or more disks you want to install IPFire on."));
 
601
 
 
602
                                } else {
 
603
                                        selected_disks = hw_select_disks(disks, disk_selection);
 
604
                                }
 
605
                        }
 
606
                }
 
607
 
 
608
                // Don't print the auto-selected harddisk setup in
 
609
                // unattended mode.
 
610
                if (config.unattended)
 
611
                        break;
 
612
 
 
613
                num_selected_disks = hw_count_disks((const struct hw_disk**)selected_disks);
 
614
 
 
615
                if (num_selected_disks == 1) {
 
616
                        snprintf(message, sizeof(message),
 
617
                                _("The installation program will now prepare the chosen harddisk:\n\n  %s\n\n"
 
618
                                "Do you agree to continue?"), (*selected_disks)->description);
 
619
                        rc = newtWinOkCancel(_("Disk Setup"), message, 50, 10,
 
620
                                _("Delete all data"), _("Cancel"));
 
621
 
 
622
                        if (rc == 0)
 
623
                                break;
 
624
 
 
625
                } else if (num_selected_disks == 2) {
 
626
                        snprintf(message, sizeof(message),
 
627
                                _("The installation program will now set up a RAID configuration on the selected harddisks:\n\n  %s\n  %s\n\n"
 
628
                                "Do you agree to continue?"), selected_disks[0]->description, selected_disks[1]->description);
 
629
                        rc = newtWinOkCancel(_("RAID Setup"), message, 50, 14,
 
630
                                _("Delete all data"), _("Cancel"));
 
631
 
 
632
                        if (rc == 0) {
 
633
                                part_type = HW_PART_TYPE_RAID1;
 
634
 
 
635
                                break;
 
636
                        }
 
637
 
 
638
                // Currently not supported
 
639
                } else {
 
640
                        errorbox(_("Your disk configuration is currently not supported."));
 
641
                        fprintf(flog, "Num disks selected: %d\n", num_selected_disks);
 
642
                }
 
643
 
 
644
                if (selected_disks) {
 
645
                        hw_free_disks(selected_disks);
 
646
                        selected_disks = NULL;
 
647
                }
 
648
        }
 
649
 
 
650
        hw_free_disks(disks);
 
651
 
 
652
        struct hw_destination* destination = hw_make_destination(part_type, selected_disks, config.disable_swap);
 
653
 
 
654
        if (!destination) {
 
655
                errorbox(_("Your harddisk is too small."));
 
656
                goto EXIT;
 
657
        }
 
658
 
 
659
        fprintf(flog, "Destination drive: %s\n", destination->path);
 
660
        fprintf(flog, "  bootldr: %s (%lluMB)\n", destination->part_bootldr, BYTES2MB(destination->size_bootldr));
 
661
        fprintf(flog, "  boot   : %s (%lluMB)\n", destination->part_boot, BYTES2MB(destination->size_boot));
 
662
        fprintf(flog, "  swap   : %s (%lluMB)\n", destination->part_swap, BYTES2MB(destination->size_swap));
 
663
        fprintf(flog, "  root   : %s (%lluMB)\n", destination->part_root, BYTES2MB(destination->size_root));
 
664
        fprintf(flog, "  data   : %s (%lluMB)\n", destination->part_data, BYTES2MB(destination->size_data));
 
665
        fprintf(flog, "Memory   : %lluMB\n", BYTES2MB(hw_memory()));
 
666
 
 
667
        // Warn the user if there is not enough space to create a swap partition
 
668
        if (!config.unattended) {
 
669
                if (!config.disable_swap && !*destination->part_swap) {
 
670
                        rc = newtWinChoice(title, _("OK"), _("Cancel"),
 
671
                                _("Your harddisk is very small, but you can continue without a swap partition."));
 
672
 
 
673
                        if (rc != 1)
 
674
                                goto EXIT;
 
675
                }
 
676
        }
 
677
 
 
678
        // Filesystem selection
 
679
        if (!config.unattended) {
 
680
                struct filesystems {
 
681
                        int fstype;
 
682
                        char* description;
 
683
                } filesystems[] = {
 
684
                        { HW_FS_EXT4,            _("ext4 Filesystem") },
 
685
                        { HW_FS_EXT4_WO_JOURNAL, _("ext4 Filesystem without journal") },
 
686
                        { HW_FS_XFS,             _("XFS Filesystem") },
 
687
                        { HW_FS_REISERFS,        _("ReiserFS Filesystem") },
 
688
                        { 0, NULL },
 
689
                };
 
690
                unsigned int num_filesystems = sizeof(filesystems) / sizeof(*filesystems);
 
691
 
 
692
                char* fs_names[num_filesystems];
 
693
                int fs_choice = 0;
 
694
                for (unsigned int i = 0; i < num_filesystems; i++) {
 
695
                        if (HW_FS_DEFAULT == filesystems[i].fstype)
 
696
                                fs_choice = i;
 
697
 
 
698
                        fs_names[i] = filesystems[i].description;
 
699
                }
 
700
 
 
701
                rc = newtWinMenu(_("Filesystem Selection"), _("Please choose your filesystem:"),
 
702
                        50, 5, 5, 6, fs_names, &fs_choice, _("OK"), _("Cancel"), NULL);
 
703
 
 
704
                if (rc == 2)
 
705
                        goto EXIT;
 
706
 
 
707
                destination->filesystem = filesystems[fs_choice].fstype;
 
708
        }
 
709
 
 
710
        // Setting up RAID if needed.
 
711
        if (destination->is_raid) {
 
712
                statuswindow(60, 4, title, _("Building RAID..."));
 
713
 
 
714
                rc = hw_setup_raid(destination, logfile);
 
715
                if (rc) {
 
716
                        errorbox(_("Unable to build the RAID."));
 
717
                        goto EXIT;
 
718
                }
 
719
 
 
720
                newtPopWindow();
 
721
        } else {
 
722
                // We will have to destroy all RAID setups that may have
 
723
                // been on the devices that we want to use now.
 
724
                hw_destroy_raid_superblocks(destination, logfile);
 
725
        }
 
726
 
 
727
        // Execute the partitioning...
 
728
        statuswindow(60, 4, title, _("Partitioning disk..."));
 
729
 
 
730
        rc = hw_create_partitions(destination, logfile);
 
731
        if (rc) {
 
732
                errorbox(_("Unable to partition the disk."));
 
733
                goto EXIT;
 
734
        }
 
735
 
 
736
        newtPopWindow();
 
737
 
 
738
        // Execute the formatting...
 
739
        statuswindow(60, 4, title, _("Creating filesystems..."));
 
740
 
 
741
        rc = hw_create_filesystems(destination, logfile);
 
742
        if (rc) {
 
743
                errorbox(_("Unable to create filesystems."));
 
744
                goto EXIT;
 
745
        }
 
746
 
 
747
        rc = hw_mount_filesystems(destination, DESTINATION_MOUNT_PATH);
 
748
        if (rc) {
 
749
                errorbox(_("Unable to mount filesystems."));
 
750
                goto EXIT;
 
751
        }
 
752
 
 
753
        newtPopWindow();
 
754
 
 
755
        // Extract files...
 
756
        snprintf(commandstring, STRING_SIZE,
 
757
                "/bin/tar -C /harddisk  -xvf /cdrom/distro.img --lzma 2>/dev/null");
 
758
 
 
759
        if (runcommandwithprogress(60, 4, title, commandstring, INST_FILECOUNT,
 
760
                        _("Installing the system..."), logfile)) {
 
761
                errorbox(_("Unable to install the system."));
 
762
                goto EXIT;
 
763
        }
 
764
 
 
765
        // Write fstab
 
766
        rc = hw_write_fstab(destination);
 
767
        if (rc) {
 
768
                fprintf(flog, "Could not write /etc/fstab\n");
 
769
                goto EXIT;
 
770
        }
 
771
 
 
772
        /* Save language und local settings */
 
773
        write_lang_configs(language);
 
774
 
 
775
        /* Build cache lang file */
 
776
        snprintf(commandstring, STRING_SIZE, "/usr/sbin/chroot /harddisk /usr/bin/perl -e \"require '" CONFIG_ROOT "/lang.pl'; &Lang::BuildCacheLang\"");
 
777
        if (runcommandwithstatus(commandstring, title, _("Installing the language cache..."), logfile)) {
 
778
                errorbox(_("Unable to install the language cache."));
 
779
                goto EXIT;
 
780
        }
 
781
 
 
782
        // Installing bootloader...
 
783
        statuswindow(60, 4, title, _("Installing the bootloader..."));
 
784
 
 
785
        /* Serial console ? */
 
786
        if (config.serial_console) {
 
787
                /* grub */
 
788
                FILE* f = fopen(DESTINATION_MOUNT_PATH "/etc/default/grub", "a");
 
789
                if (!f) {
 
790
                        errorbox(_("Unable to open /etc/default/grub for writing."));
 
791
                        goto EXIT;
 
792
                }
 
793
 
 
794
                fprintf(f, "GRUB_TERMINAL=\"serial\"\n");
 
795
                fprintf(f, "GRUB_SERIAL_COMMAND=\"serial --unit=0 --speed=%d\"\n", SERIAL_BAUDRATE);
 
796
                fclose(f);
 
797
 
 
798
                replace(DESTINATION_MOUNT_PATH "/etc/default/grub", "panic=10", "panic=10 console=ttyS0,115200n8");
 
799
 
 
800
                /* inittab */
 
801
                replace("/harddisk/etc/inittab", "1:2345:respawn:", "#1:2345:respawn:");
 
802
                replace("/harddisk/etc/inittab", "2:2345:respawn:", "#2:2345:respawn:");
 
803
                replace("/harddisk/etc/inittab", "3:2345:respawn:", "#3:2345:respawn:");
 
804
                replace("/harddisk/etc/inittab", "4:2345:respawn:", "#4:2345:respawn:");
 
805
                replace("/harddisk/etc/inittab", "5:2345:respawn:", "#5:2345:respawn:");
 
806
                replace("/harddisk/etc/inittab", "6:2345:respawn:", "#6:2345:respawn:");
 
807
                replace("/harddisk/etc/inittab", "#7:2345:respawn:", "7:2345:respawn:");
 
808
        }
 
809
 
 
810
        rc = hw_install_bootloader(destination, logfile);
 
811
        if (rc) {
 
812
                errorbox(_("Unable to install the bootloader."));
 
813
                goto EXIT;
 
814
        }
 
815
 
 
816
        newtPopWindow();
 
817
 
 
818
        /* Set marker that the user has already accepted the gpl */
 
819
        mysystem(logfile, "/usr/bin/touch /harddisk/var/ipfire/main/gpl_accepted");
 
820
 
 
821
        /* Copy restore file from cdrom */
 
822
        char* backup_file = hw_find_backup_file(logfile, SOURCE_MOUNT_PATH);
 
823
        if (backup_file) {
 
824
                rc = 0;
 
825
                if (!config.unattended) {
 
826
                        rc = newtWinOkCancel(title, _("A backup file has been found on the installation image.\n\n"
 
827
                                "Do you want to restore the backup?"), 50, 10, _("Yes"), _("No"));
 
828
                }
 
829
 
 
830
                if (rc == 0) {
 
831
                        rc = hw_restore_backup(logfile, backup_file, DESTINATION_MOUNT_PATH);
 
832
 
 
833
                        if (rc) {
 
834
                                errorbox(_("An error occured when the backup file was restored."));
 
835
                                goto EXIT;
 
836
                        }
 
837
                }
 
838
 
 
839
                free(backup_file);
 
840
        }
 
841
 
 
842
        // Download and execute the postinstall script
 
843
        if (*config.postinstall) {
 
844
                snprintf(commandstring, sizeof(commandstring),
 
845
                        "/usr/bin/execute-postinstall.sh %s %s", DESTINATION_MOUNT_PATH, config.postinstall);
 
846
 
 
847
                if (runcommandwithstatus(commandstring, title, _("Running post-install script..."), logfile)) {
 
848
                        errorbox(_("Post-install script failed."));
 
849
                        goto EXIT;
 
850
                }
 
851
        }
 
852
 
 
853
        // Umount the destination drive
 
854
        statuswindow(60, 4, title, _("Umounting filesystems..."));
 
855
 
 
856
        rc = hw_umount_filesystems(destination, DESTINATION_MOUNT_PATH);
 
857
        if (rc) {
 
858
                // Show an error message if filesystems could not be umounted properly
 
859
                snprintf(message, sizeof(message),
 
860
                        _("Could not umount all filesystems successfully:\n\n  %s"), strerror(errno));
 
861
                errorbox(message);
 
862
                goto EXIT;
 
863
        }
 
864
 
 
865
        // Umount source drive and eject
 
866
        hw_umount(SOURCE_MOUNT_PATH);
 
867
 
 
868
        // Free downloaded ISO image
 
869
        if (strcmp(sourcedrive, SOURCE_TEMPFILE) == 0) {
 
870
                rc = unlink(sourcedrive);
 
871
                if (rc)
 
872
                        fprintf(flog, "Could not free downloaded ISO image: %s\n", sourcedrive);
 
873
 
 
874
        // or eject real images
 
875
        } else {
 
876
                snprintf(commandstring, STRING_SIZE, "/usr/bin/eject %s", sourcedrive);
 
877
                mysystem(logfile, commandstring);
 
878
        }
 
879
        newtPopWindow();
 
880
 
 
881
        // Stop the RAID array if we are using RAID
 
882
        if (destination->is_raid)
 
883
                hw_stop_all_raid_arrays(logfile);
 
884
 
 
885
        // Show a short message that the installation went well and
 
886
        // wait a moment so that all disk caches get flushed.
 
887
        if (config.unattended) {
 
888
                splashWindow(title, _("Unattended installation has finished. The system will be shutting down in a moment..."), 5);
 
889
 
 
890
        } else {
 
891
                snprintf(message, sizeof(message), _(
 
892
                        "%s was successfully installed!\n\n"
 
893
                        "Please remove any installation mediums from this system and hit the reboot button. "
 
894
                        "Once the system has restarted you will be asked to setup networking and system passwords. "
 
895
                        "After that, you should point your web browser at https://%s:444 (or what ever you name "
 
896
                        "your %s) for the web configuration console."), NAME, SNAME, NAME);
 
897
                newtWinMessage(_("Congratulations!"), _("Reboot"), message);
 
898
        }
 
899
 
 
900
        allok = 1;
 
901
 
 
902
EXIT:
 
903
        fprintf(flog, "Install program ended.\n");
 
904
        fflush(flog);
 
905
        fclose(flog);
 
906
 
 
907
        if (!allok)
 
908
                newtWinMessage(title, _("OK"), _("Setup has failed. Press Ok to reboot."));
 
909
 
 
910
        newtFinished();
 
911
 
 
912
        // Free resources
 
913
        if (system_release)
 
914
                free(system_release);
 
915
 
 
916
        if (roottext)
 
917
                free(roottext);
 
918
 
 
919
        if (helpline)
 
920
                free(helpline);
 
921
 
 
922
        if (sourcedrive)
 
923
                free(sourcedrive);
 
924
 
 
925
        if (destination)
 
926
                free(destination);
 
927
 
 
928
        hw_stop_all_raid_arrays(logfile);
 
929
 
 
930
        if (selected_disks)
 
931
                hw_free_disks(selected_disks);
 
932
 
 
933
        if (hw)
 
934
                hw_free(hw);
 
935
 
 
936
        fcloseall();
 
937
 
 
938
        if (allok == 1)
 
939
                return 0;
 
940
 
 
941
        return 1;
 
942
}