2 /* SmoothWall install program.
4 * This program is distributed under the terms of the GNU General Public
5 * Licence. See the file COPYING for details.
7 * (c) Lawrence Manning, 2001
8 * Contains main entry point, and misc functions.6
18 #include <sys/mount.h>
23 #define INST_FILECOUNT 21000
24 #define UNATTENDED_CONF "/cdrom/boot/unattended.conf"
25 #define LICENSE_FILE "/cdrom/COPYING"
32 extern char url
[STRING_SIZE
];
34 struct nic nics
[20] = { { "" , "" , "" } }; // only defined for compile
35 struct knic knics
[20] = { { "" , "" , "" , "" } }; // only defined for compile
46 static int newtChecklist(const char* title
, const char* message
,
47 unsigned int width
, unsigned int height
, unsigned int num_entries
,
48 const char** entries
, int* states
) {
50 const int list_height
= 4;
52 char cbstates
[num_entries
];
54 for (unsigned int i
= 0; i
< num_entries
; i
++) {
55 cbstates
[i
] = states
[i
] ? '*' : ' ';
58 newtCenteredWindow(width
, height
, title
);
60 newtComponent textbox
= newtTextbox(1, 1, width
- 2, height
- 6 - list_height
,
62 newtTextboxSetText(textbox
, message
);
64 int top
= newtTextboxGetNumLines(textbox
) + 2;
66 newtComponent form
= newtForm(NULL
, NULL
, 0);
68 newtComponent sb
= NULL
;
69 if (list_height
< num_entries
) {
70 sb
= newtVerticalScrollbar(
71 width
- 4, top
+ 1, list_height
,
72 NEWT_COLORSET_CHECKBOX
, NEWT_COLORSET_ACTCHECKBOX
);
74 newtFormAddComponent(form
, sb
);
77 newtComponent subform
= newtForm(sb
, NULL
, 0);
78 newtFormSetBackground(subform
, NEWT_COLORSET_CHECKBOX
);
80 newtFormSetHeight(subform
, list_height
);
81 newtFormSetWidth(subform
, width
- 10);
83 for (unsigned int i
= 0; i
< num_entries
; i
++) {
84 newtComponent cb
= newtCheckbox(4, top
+ i
, entries
[i
], cbstates
[i
],
87 newtFormAddComponent(subform
, cb
);
90 newtFormAddComponents(form
, textbox
, subform
, NULL
);
92 newtComponent btn_okay
= newtButton((width
- 18) / 3, height
- 4, ctr
[TR_OK
]);
93 newtComponent btn_cancel
= newtButton((width
- 18) / 3 * 2 + 9, height
- 4, ctr
[TR_CANCEL
]);
94 newtFormAddComponents(form
, btn_okay
, btn_cancel
, NULL
);
96 newtComponent answer
= newtRunForm(form
);
98 if ((answer
== NULL
) || (answer
== btn_cancel
)) {
103 for (unsigned int i
= 0; i
< num_entries
; i
++) {
104 states
[i
] = (cbstates
[i
] != ' ');
111 newtFormDestroy(form
);
117 static int newtWinOkCancel(const char* title
, const char* message
, int width
, int height
,
118 const char* btn_txt_ok
, const char* btn_txt_cancel
) {
121 newtCenteredWindow(width
, height
, title
);
123 newtComponent form
= newtForm(NULL
, NULL
, 0);
125 newtComponent textbox
= newtTextbox(1, 1, width
- 2, height
- 6, NEWT_FLAG_WRAP
);
126 newtTextboxSetText(textbox
, message
);
127 newtFormAddComponent(form
, textbox
);
129 newtComponent btn_ok
= newtButton((width
- 16) / 3, height
- 4, btn_txt_ok
);
130 newtComponent btn_cancel
= newtButton((width
- 16) / 3 * 2 + 9, height
- 4,
133 newtFormAddComponents(form
, btn_ok
, btn_cancel
, NULL
);
135 newtComponent answer
= newtRunForm(form
);
137 if (answer
== btn_ok
) {
141 newtFormDestroy(form
);
147 static int newtLicenseBox(const char* title
, const char* text
, int width
, int height
) {
150 newtCenteredWindow(width
, height
, title
);
152 newtComponent form
= newtForm(NULL
, NULL
, 0);
154 newtComponent textbox
= newtTextbox(1, 1, width
- 2, height
- 7,
155 NEWT_FLAG_WRAP
|NEWT_FLAG_SCROLL
);
156 newtTextboxSetText(textbox
, text
);
157 newtFormAddComponent(form
, textbox
);
160 newtComponent checkbox
= newtCheckbox(3, height
- 3, ctr
[TR_LICENSE_ACCEPT
],
163 newtComponent btn
= newtButton(width
- 15, height
- 4, ctr
[TR_OK
]);
165 newtFormAddComponents(form
, checkbox
, btn
, NULL
);
167 newtComponent answer
= newtRunForm(form
);
168 if (answer
== btn
&& choice
== '*')
171 newtFormDestroy(form
);
177 int main(int argc
, char *argv
[]) {
178 struct hw
* hw
= hw_init();
180 char discl_msg
[40000] = "Disclaimer\n";
182 char *langnames
[] = { "Deutsch", "English", "Français", "Español", "Nederlands", "Polski", "Русский", "Türkçe", NULL
};
183 char *shortlangnames
[] = { "de", "en", "fr", "es", "nl", "pl", "ru", "tr", NULL
};
184 char **langtrs
[] = { de_tr
, en_tr
, fr_tr
, es_tr
, nl_tr
, pl_tr
, ru_tr
, tr_tr
, NULL
};
185 char* sourcedrive
= NULL
;
187 char commandstring
[STRING_SIZE
];
189 char shortlangname
[10];
190 char message
[STRING_SIZE
];
191 char title
[STRING_SIZE
];
193 FILE *handle
, *cmdfile
, *copying
;
194 char line
[STRING_SIZE
];
197 int serialconsole
= 0;
198 struct keyvalue
*unattendedkv
= initkeyvalues();
199 char restore_file
[STRING_SIZE
] = "";
201 setlocale (LC_ALL
, "");
202 sethostname( SNAME
, 10);
204 /* Log file/terminal stuff. */
207 if (!(flog
= fopen(argv
[1], "w+")))
215 fprintf(flog
, "Install program started.\n");
220 newtDrawRootText(14, 0, NAME
" " VERSION
" - " SLOGAN
);
221 sprintf (title
, "%s %s - %s", NAME
, VERSION
, SLOGAN
);
223 if (! (cmdfile
= fopen("/proc/cmdline", "r")))
225 fprintf(flog
, "Couldn't open commandline: /proc/cmdline\n");
227 fgets(line
, STRING_SIZE
, cmdfile
);
229 // check if we have to make an unattended install
230 if (strstr (line
, "unattended") != NULL
) {
232 runcommandwithstatus("/bin/sleep 10", "WARNING: Unattended installation will start in 10 seconds...");
234 // check if we have to patch for serial console
235 if (strstr (line
, "console=ttyS0") != NULL
) {
240 // Load common modules
241 mysystem("/sbin/modprobe vfat"); // USB key
242 hw_stop_all_raid_arrays();
244 /* German is the default */
245 for (choice
= 0; langnames
[choice
]; choice
++)
247 if (strcmp(langnames
[choice
], "English") == 0)
250 if (!langnames
[choice
])
254 rc
= newtWinMenu("Language selection", "Select the language you wish to use for the " NAME
".", 50, 5, 5, 8,
255 langnames
, &choice
, "Ok", NULL
);
258 ctr
= langtrs
[choice
];
259 strcpy(shortlangname
, shortlangnames
[choice
]);
261 newtPushHelpLine(ctr
[TR_HELPLINE
]);
264 sprintf(message
, ctr
[TR_WELCOME
], NAME
);
265 newtWinMessage(title
, ctr
[TR_OK
], message
);
268 /* Search for a source drive that holds the right
269 * version of the image we are going to install. */
270 sourcedrive
= hw_find_source_medium(hw
);
272 fprintf(flog
, "Source drive: %s\n", sourcedrive
);
274 newtWinMessage(title
, ctr
[TR_OK
], ctr
[TR_NO_LOCAL_SOURCE
]);
275 runcommandwithstatus("/bin/downloadsource.sh", ctr
[TR_DOWNLOADING_ISO
]);
276 if ((handle
= fopen("/tmp/source_device", "r")) == NULL
) {
277 errorbox(ctr
[TR_DOWNLOAD_ERROR
]);
281 fgets(sourcedrive
, 5, handle
);
287 int r
= hw_mount(sourcedrive
, SOURCE_MOUNT_PATH
, "iso9660", MS_RDONLY
);
289 fprintf(flog
, "Could not mount %s to %s\n", sourcedrive
, SOURCE_MOUNT_PATH
);
290 fprintf(flog
, strerror(errno
));
294 /* load unattended configuration */
296 fprintf(flog
, "unattended: Reading unattended.conf\n");
298 (void) readkeyvalues(unattendedkv
, UNATTENDED_CONF
);
299 findkey(unattendedkv
, "RESTORE_FILE", restore_file
);
303 // Read the license file.
304 if (!(copying
= fopen(LICENSE_FILE
, "r"))) {
305 sprintf(discl_msg
, "Could not open license file: %s\n", LICENSE_FILE
);
306 fprintf(flog
, discl_msg
);
308 fread(discl_msg
, 1, 40000, copying
);
311 if (newtLicenseBox(title
, discl_msg
, 75, 20)) {
312 errorbox(ctr
[TR_LICENSE_NOT_ACCEPTED
]);
319 int part_type
= HW_PART_TYPE_NORMAL
;
321 // Scan for disks to install on.
322 struct hw_disk
** disks
= hw_find_disks(hw
);
324 struct hw_disk
** selected_disks
= NULL
;
325 unsigned int num_selected_disks
= 0;
327 // Check how many disks have been found and what
328 // we can do with them.
329 unsigned int num_disks
= hw_count_disks(disks
);
332 // no harddisks found
333 if (num_disks
== 0) {
334 errorbox(ctr
[TR_NO_HARDDISK
]);
337 // exactly one disk has been found
338 } else if (num_disks
== 1) {
339 selected_disks
= hw_select_disks(disks
, NULL
);
341 // more than one usable disk has been found and
342 // the user needs to choose what to do with them
344 const char* disk_names
[num_disks
];
345 int disk_selection
[num_disks
];
347 for (unsigned int i
= 0; i
< num_disks
; i
++) {
348 disk_names
[i
] = &disks
[i
]->description
;
349 disk_selection
[i
] = 0;
352 while (!selected_disks
) {
353 rc
= newtChecklist(ctr
[TR_DISK_SELECTION
], ctr
[TR_DISK_SELECTION_MSG
],
354 50, 20, num_disks
, disk_names
, disk_selection
);
360 // Nothing has been selected
361 } else if (rc
== 0) {
362 errorbox(ctr
[TR_NO_DISK_SELECTED
]);
365 selected_disks
= hw_select_disks(disks
, disk_selection
);
370 num_selected_disks
= hw_count_disks(selected_disks
);
372 if (num_selected_disks
== 1) {
373 snprintf(message
, sizeof(message
), ctr
[TR_DISK_SETUP_DESC
], (*selected_disks
)->description
);
374 rc
= newtWinOkCancel(ctr
[TR_DISK_SETUP
], message
, 50, 10,
375 ctr
[TR_DELETE_ALL_DATA
], ctr
[TR_CANCEL
]);
380 } else if (num_selected_disks
== 2) {
381 snprintf(message
, sizeof(message
), ctr
[TR_RAID_SETUP_DESC
],
382 (*selected_disks
)->description
, (*selected_disks
+ 1)->description
);
383 rc
= newtWinOkCancel(ctr
[TR_RAID_SETUP
], message
, 50, 14,
384 ctr
[TR_DELETE_ALL_DATA
], ctr
[TR_CANCEL
]);
387 part_type
= HW_PART_TYPE_RAID1
;
392 // Currently not supported
394 errorbox(ctr
[TR_DISK_CONFIGURATION_NOT_SUPPORTED
]);
397 if (selected_disks
) {
398 hw_free_disks(selected_disks
);
399 selected_disks
= NULL
;
403 hw_free_disks(disks
);
405 struct hw_destination
* destination
= hw_make_destination(part_type
, selected_disks
);
408 errorbox(ctr
[TR_DISK_TOO_SMALL
]);
412 fprintf(flog
, "Destination drive: %s\n", destination
->path
);
413 fprintf(flog
, " bootldr: %s (%lluMB)\n", destination
->part_bootldr
, BYTES2MB(destination
->size_bootldr
));
414 fprintf(flog
, " boot : %s (%lluMB)\n", destination
->part_boot
, BYTES2MB(destination
->size_boot
));
415 fprintf(flog
, " swap : %s (%lluMB)\n", destination
->part_swap
, BYTES2MB(destination
->size_swap
));
416 fprintf(flog
, " root : %s (%lluMB)\n", destination
->part_root
, BYTES2MB(destination
->size_root
));
417 fprintf(flog
, " data : %s (%lluMB)\n", destination
->part_data
, BYTES2MB(destination
->size_data
));
419 // Warn the user if there is not enough space to create a swap partition
420 if (!unattended
&& !*destination
->part_swap
) {
421 rc
= newtWinChoice(title
, ctr
[TR_OK
], ctr
[TR_CANCEL
], ctr
[TR_CONTINUE_NO_SWAP
]);
427 // Filesystem selection
431 const char* description
;
433 { HW_FS_EXT4
, ctr
[TR_EXT4FS
] },
434 { HW_FS_EXT4_WO_JOURNAL
, ctr
[TR_EXT4FS_WO_JOURNAL
] },
435 { HW_FS_XFS
, ctr
[TR_XFS
] },
436 { HW_FS_REISERFS
, ctr
[TR_REISERFS
] },
439 unsigned int num_filesystems
= sizeof(filesystems
) / sizeof(*filesystems
);
441 char* fs_names
[num_filesystems
];
443 for (unsigned int i
= 0; i
< num_filesystems
; i
++) {
444 if (HW_FS_DEFAULT
== filesystems
[i
].fstype
)
447 fs_names
[i
] = filesystems
[i
].description
;
450 rc
= newtWinMenu(ctr
[TR_CHOOSE_FILESYSTEM
], ctr
[TR_CHOOSE_FILESYSTEM
],
451 50, 5, 5, 6, fs_names
, &fs_choice
, ctr
[TR_OK
], ctr
[TR_CANCEL
], NULL
);
454 destination
->filesystem
= filesystems
[fs_choice
].fstype
;
460 // Setting up RAID if needed.
461 if (destination
->is_raid
) {
462 statuswindow(60, 4, title
, ctr
[TR_BUILDING_RAID
]);
464 rc
= hw_setup_raid(destination
);
466 errorbox(ctr
[TR_UNABLE_TO_BUILD_RAID
]);
473 // Execute the partitioning...
474 statuswindow(60, 4, title
, ctr
[TR_PARTITIONING_DISK
]);
476 rc
= hw_create_partitions(destination
);
478 errorbox(ctr
[TR_UNABLE_TO_PARTITION
]);
484 // Execute the formatting...
485 statuswindow(60, 4, title
, ctr
[TR_CREATING_FILESYSTEMS
]);
487 rc
= hw_create_filesystems(destination
);
489 errorbox(ctr
[TR_UNABLE_TO_CREATE_FILESYSTEMS
]);
493 rc
= hw_mount_filesystems(destination
, DESTINATION_MOUNT_PATH
);
495 errorbox(ctr
[TR_UNABLE_TO_MOUNT_FILESYSTEMS
]);
502 snprintf(commandstring
, STRING_SIZE
,
503 "/bin/tar -C /harddisk -xvf /cdrom/" SNAME
"-" VERSION
".tlz --lzma 2>/dev/null");
505 if (runcommandwithprogress(60, 4, title
, commandstring
, INST_FILECOUNT
,
506 ctr
[TR_INSTALLING_FILES
]))
508 errorbox(ctr
[TR_UNABLE_TO_INSTALL_FILES
]);
513 rc
= hw_write_fstab(destination
);
515 fprintf(flog
, "Could not write /etc/fstab\n");
519 /* Save language und local settings */
520 write_lang_configs(shortlangname
);
522 /* Build cache lang file */
523 snprintf(commandstring
, STRING_SIZE
, "/usr/sbin/chroot /harddisk /usr/bin/perl -e \"require '" CONFIG_ROOT
"/lang.pl'; &Lang::BuildCacheLang\"");
524 if (runcommandwithstatus(commandstring
, ctr
[TR_INSTALLING_LANG_CACHE
]))
526 errorbox(ctr
[TR_UNABLE_TO_INSTALL_LANG_CACHE
]);
530 // Installing bootloader...
531 statuswindow(60, 4, title
, ctr
[TR_INSTALLING_GRUB
]);
533 rc
= hw_install_bootloader(destination
);
535 errorbox(ctr
[TR_UNABLE_TO_INSTALL_GRUB
]);
541 /* Serial console ? */
544 replace("/harddisk/boot/grub/grub.conf", "splashimage", "#splashimage");
545 replace("/harddisk/boot/grub/grub.conf", "#serial", "serial");
546 replace("/harddisk/boot/grub/grub.conf", "#terminal", "terminal");
547 replace("/harddisk/boot/grub/grub.conf", " panic=10 ", " console=ttyS0,115200n8 panic=10 ");
550 replace("/harddisk/etc/inittab", "1:2345:respawn:", "#1:2345:respawn:");
551 replace("/harddisk/etc/inittab", "2:2345:respawn:", "#2:2345:respawn:");
552 replace("/harddisk/etc/inittab", "3:2345:respawn:", "#3:2345:respawn:");
553 replace("/harddisk/etc/inittab", "4:2345:respawn:", "#4:2345:respawn:");
554 replace("/harddisk/etc/inittab", "5:2345:respawn:", "#5:2345:respawn:");
555 replace("/harddisk/etc/inittab", "6:2345:respawn:", "#6:2345:respawn:");
556 replace("/harddisk/etc/inittab", "#7:2345:respawn:", "7:2345:respawn:");
559 /* Set marker that the user has already accepted the gpl */
560 mysystem("/usr/bin/touch /harddisk/var/ipfire/main/gpl_accepted");
562 /* Copy restore file from cdrom */
563 if (unattended
&& (strlen(restore_file
) > 0)) {
564 fprintf(flog
, "unattended: Copy restore file\n");
565 snprintf(commandstring
, STRING_SIZE
,
566 "cp /cdrom/%s /harddisk/var/ipfire/backup", restore_file
);
567 mysystem(commandstring
);
570 // Umount source drive and eject
571 hw_umount(SOURCE_MOUNT_PATH
);
573 snprintf(commandstring
, STRING_SIZE
, "/usr/bin/eject %s", sourcedrive
);
574 mysystem(commandstring
);
577 sprintf(message
, ctr
[TR_CONGRATULATIONS_LONG
],
579 newtWinMessage(ctr
[TR_CONGRATULATIONS
], ctr
[TR_PRESS_OK_TO_REBOOT
], message
);
585 fprintf(flog
, "Install program ended.\n");
588 newtWinMessage(title
, ctr
[TR_OK
], ctr
[TR_PRESS_OK_TO_REBOOT
]);
601 hw_umount_filesystems(destination
, DESTINATION_MOUNT_PATH
);
605 hw_stop_all_raid_arrays();
608 hw_free_disks(selected_disks
);