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
243 /* German is the default */
244 for (choice
= 0; langnames
[choice
]; choice
++)
246 if (strcmp(langnames
[choice
], "English") == 0)
249 if (!langnames
[choice
])
253 rc
= newtWinMenu("Language selection", "Select the language you wish to use for the " NAME
".", 50, 5, 5, 8,
254 langnames
, &choice
, "Ok", NULL
);
257 ctr
= langtrs
[choice
];
258 strcpy(shortlangname
, shortlangnames
[choice
]);
260 newtPushHelpLine(ctr
[TR_HELPLINE
]);
263 sprintf(message
, ctr
[TR_WELCOME
], NAME
);
264 newtWinMessage(title
, ctr
[TR_OK
], message
);
267 /* Search for a source drive that holds the right
268 * version of the image we are going to install. */
269 sourcedrive
= hw_find_source_medium(hw
);
271 fprintf(flog
, "Source drive: %s\n", sourcedrive
);
273 newtWinMessage(title
, ctr
[TR_OK
], ctr
[TR_NO_LOCAL_SOURCE
]);
274 runcommandwithstatus("/bin/downloadsource.sh", ctr
[TR_DOWNLOADING_ISO
]);
275 if ((handle
= fopen("/tmp/source_device", "r")) == NULL
) {
276 errorbox(ctr
[TR_DOWNLOAD_ERROR
]);
280 fgets(sourcedrive
, 5, handle
);
286 int r
= hw_mount(sourcedrive
, SOURCE_MOUNT_PATH
, "iso9660", MS_RDONLY
);
288 fprintf(flog
, "Could not mount %s to %s\n", sourcedrive
, SOURCE_MOUNT_PATH
);
289 fprintf(flog
, strerror(errno
));
293 /* load unattended configuration */
295 fprintf(flog
, "unattended: Reading unattended.conf\n");
297 (void) readkeyvalues(unattendedkv
, UNATTENDED_CONF
);
298 findkey(unattendedkv
, "RESTORE_FILE", restore_file
);
302 // Read the license file.
303 if (!(copying
= fopen(LICENSE_FILE
, "r"))) {
304 sprintf(discl_msg
, "Could not open license file: %s\n", LICENSE_FILE
);
305 fprintf(flog
, discl_msg
);
307 fread(discl_msg
, 1, 40000, copying
);
310 if (newtLicenseBox(title
, discl_msg
, 75, 20)) {
311 errorbox(ctr
[TR_LICENSE_NOT_ACCEPTED
]);
318 int part_type
= HW_PART_TYPE_NORMAL
;
320 // Scan for disks to install on.
321 struct hw_disk
** disks
= hw_find_disks(hw
);
323 struct hw_disk
** selected_disks
= NULL
;
324 unsigned int num_selected_disks
= 0;
326 // Check how many disks have been found and what
327 // we can do with them.
328 unsigned int num_disks
= hw_count_disks(disks
);
331 // no harddisks found
332 if (num_disks
== 0) {
333 errorbox(ctr
[TR_NO_HARDDISK
]);
336 // exactly one disk has been found
337 } else if (num_disks
== 1) {
338 selected_disks
= hw_select_disks(disks
, NULL
);
340 // more than one usable disk has been found and
341 // the user needs to choose what to do with them
343 const char* disk_names
[num_disks
];
344 int disk_selection
[num_disks
];
346 for (unsigned int i
= 0; i
< num_disks
; i
++) {
347 disk_names
[i
] = &disks
[i
]->description
;
348 disk_selection
[i
] = 0;
351 while (!selected_disks
) {
352 rc
= newtChecklist(ctr
[TR_DISK_SELECTION
], ctr
[TR_DISK_SELECTION_MSG
],
353 50, 20, num_disks
, disk_names
, disk_selection
);
359 // Nothing has been selected
360 } else if (rc
== 0) {
361 errorbox(ctr
[TR_NO_DISK_SELECTED
]);
364 selected_disks
= hw_select_disks(disks
, disk_selection
);
369 num_selected_disks
= hw_count_disks(selected_disks
);
371 if (num_selected_disks
== 1) {
372 snprintf(message
, sizeof(message
), ctr
[TR_DISK_SETUP_DESC
], (*selected_disks
)->description
);
373 rc
= newtWinOkCancel(ctr
[TR_DISK_SETUP
], message
, 50, 10,
374 ctr
[TR_DELETE_ALL_DATA
], ctr
[TR_CANCEL
]);
379 } else if (num_selected_disks
== 2) {
380 snprintf(message
, sizeof(message
), ctr
[TR_RAID_SETUP_DESC
],
381 (*selected_disks
)->description
, (*selected_disks
+ 1)->description
);
382 rc
= newtWinOkCancel(ctr
[TR_RAID_SETUP
], message
, 50, 10,
383 ctr
[TR_DELETE_ALL_DATA
], ctr
[TR_CANCEL
]);
386 part_type
= HW_PART_TYPE_RAID1
;
391 // Currently not supported
393 errorbox(ctr
[TR_DISK_CONFIGURATION_NOT_SUPPORTED
]);
396 if (selected_disks
) {
397 hw_free_disks(selected_disks
);
398 selected_disks
= NULL
;
402 hw_free_disks(disks
);
404 struct hw_destination
* destination
= hw_make_destination(part_type
, selected_disks
);
407 errorbox(ctr
[TR_DISK_TOO_SMALL
]);
411 fprintf(flog
, "Destination drive: %s\n", destination
->path
);
412 fprintf(flog
, " boot: %s (%lluMB)\n", destination
->part_boot
, BYTES2MB(destination
->size_boot
));
413 fprintf(flog
, " swap: %s (%lluMB)\n", destination
->part_swap
, BYTES2MB(destination
->size_swap
));
414 fprintf(flog
, " root: %s (%lluMB)\n", destination
->part_root
, BYTES2MB(destination
->size_root
));
415 fprintf(flog
, " data: %s (%lluMB)\n", destination
->part_data
, BYTES2MB(destination
->size_data
));
417 // Warn the user if there is not enough space to create a swap partition
418 if (!unattended
&& !*destination
->part_swap
) {
419 rc
= newtWinChoice(title
, ctr
[TR_OK
], ctr
[TR_CANCEL
], ctr
[TR_CONTINUE_NO_SWAP
]);
425 // Filesystem selection
429 const char* description
;
431 { HW_FS_EXT4
, ctr
[TR_EXT4FS
] },
432 { HW_FS_EXT4_WO_JOURNAL
, ctr
[TR_EXT4FS_WO_JOURNAL
] },
433 { HW_FS_REISERFS
, ctr
[TR_REISERFS
] },
436 unsigned int num_filesystems
= sizeof(filesystems
) / sizeof(*filesystems
);
438 char* fs_names
[num_filesystems
];
440 for (unsigned int i
= 0; i
< num_filesystems
; i
++) {
441 if (HW_FS_DEFAULT
== filesystems
[i
].fstype
)
444 fs_names
[i
] = filesystems
[i
].description
;
447 rc
= newtWinMenu(ctr
[TR_CHOOSE_FILESYSTEM
], ctr
[TR_CHOOSE_FILESYSTEM
],
448 50, 5, 5, 6, fs_names
, &fs_choice
, ctr
[TR_OK
], ctr
[TR_CANCEL
], NULL
);
451 destination
->filesystem
= filesystems
[fs_choice
].fstype
;
457 // Execute the partitioning...
458 statuswindow(60, 4, title
, ctr
[TR_PARTITIONING_DISK
]);
460 rc
= hw_create_partitions(destination
);
462 errorbox(ctr
[TR_UNABLE_TO_PARTITION
]);
468 // Execute the formatting...
469 statuswindow(60, 4, title
, ctr
[TR_CREATING_FILESYSTEMS
]);
471 rc
= hw_create_filesystems(destination
);
473 errorbox(ctr
[TR_UNABLE_TO_CREATE_FILESYSTEMS
]);
477 rc
= hw_mount_filesystems(destination
, DESTINATION_MOUNT_PATH
);
479 errorbox(ctr
[TR_UNABLE_TO_MOUNT_FILESYSTEMS
]);
486 snprintf(commandstring
, STRING_SIZE
,
487 "/bin/tar -C /harddisk -xvf /cdrom/" SNAME
"-" VERSION
".tlz --lzma 2>/dev/null");
489 if (runcommandwithprogress(60, 4, title
, commandstring
, INST_FILECOUNT
,
490 ctr
[TR_INSTALLING_FILES
]))
492 errorbox(ctr
[TR_UNABLE_TO_INSTALL_FILES
]);
496 /* Save language und local settings */
497 write_lang_configs(shortlangname
);
499 /* Build cache lang file */
500 snprintf(commandstring
, STRING_SIZE
, "/usr/sbin/chroot /harddisk /usr/bin/perl -e \"require '" CONFIG_ROOT
"/lang.pl'; &Lang::BuildCacheLang\"");
501 if (runcommandwithstatus(commandstring
, ctr
[TR_INSTALLING_LANG_CACHE
]))
503 errorbox(ctr
[TR_UNABLE_TO_INSTALL_LANG_CACHE
]);
507 /* Update /etc/fstab */
508 snprintf(commandstring
, STRING_SIZE
, "/bin/sed -i -e \"s#DEVICE1#UUID=$(/sbin/blkid %s -sUUID | /usr/bin/cut -d'\"' -f2)#g\" /harddisk/etc/fstab", destination
->part_boot
);
509 system(commandstring
);
510 snprintf(commandstring
, STRING_SIZE
, "/bin/sed -i -e \"s#DEVICE2#UUID=$(/sbin/blkid %s -sUUID | /usr/bin/cut -d'\"' -f2)#g\" /harddisk/etc/fstab", destination
->part_swap
);
511 system(commandstring
);
512 snprintf(commandstring
, STRING_SIZE
, "/bin/sed -i -e \"s#DEVICE3#UUID=$(/sbin/blkid %s -sUUID | /usr/bin/cut -d'\"' -f2)#g\" /harddisk/etc/fstab", destination
->part_root
);
513 system(commandstring
);
514 snprintf(commandstring
, STRING_SIZE
, "/bin/sed -i -e \"s#DEVICE4#UUID=$(/sbin/blkid %s -sUUID | /usr/bin/cut -d'\"' -f2)#g\" /harddisk/etc/fstab", destination
->part_data
);
515 system(commandstring
);
517 switch (destination
->filesystem
) {
519 replace("/harddisk/etc/fstab", "FSTYPE", "reiserfs");
520 replace("/harddisk/boot/grub/grub.conf", "MOUNT", "ro");
524 case HW_FS_EXT4_WO_JOURNAL
:
525 replace("/harddisk/etc/fstab", "FSTYPE", "ext4");
526 replace("/harddisk/boot/grub/grub.conf", "MOUNT", "ro");
533 replace("/harddisk/boot/grub/grub.conf", "KVER", KERNEL_VERSION
);
535 snprintf(commandstring
, STRING_SIZE
, "/bin/sed -i -e \"s#root=ROOT#root=UUID=$(/sbin/blkid %s -sUUID | /usr/bin/cut -d'\"' -f2)#g\" /harddisk/boot/grub/grub.conf", destination
->part_root
);
536 system(commandstring
);
538 mysystem("ln -s grub.conf /harddisk/boot/grub/menu.lst");
540 system("/bin/sed -e 's#/harddisk#/#g' -e 's#//#/#g' < /proc/mounts > /harddisk/etc/mtab");
543 * Generate device.map to help grub finding the device to install itself on.
546 if (f
= fopen("/harddisk/boot/grub/device.map", "w")) {
547 fprintf(f
, "(hd0) %s\n", destination
->path
);
551 snprintf(commandstring
, STRING_SIZE
,
552 "/usr/sbin/chroot /harddisk /usr/sbin/grub-install --no-floppy %s", destination
->path
);
553 if (runcommandwithstatus(commandstring
, ctr
[TR_INSTALLING_GRUB
])) {
554 errorbox(ctr
[TR_UNABLE_TO_INSTALL_GRUB
]);
558 /* Serial console ? */
561 replace("/harddisk/boot/grub/grub.conf", "splashimage", "#splashimage");
562 replace("/harddisk/boot/grub/grub.conf", "#serial", "serial");
563 replace("/harddisk/boot/grub/grub.conf", "#terminal", "terminal");
564 replace("/harddisk/boot/grub/grub.conf", " panic=10 ", " console=ttyS0,115200n8 panic=10 ");
567 replace("/harddisk/etc/inittab", "1:2345:respawn:", "#1:2345:respawn:");
568 replace("/harddisk/etc/inittab", "2:2345:respawn:", "#2:2345:respawn:");
569 replace("/harddisk/etc/inittab", "3:2345:respawn:", "#3:2345:respawn:");
570 replace("/harddisk/etc/inittab", "4:2345:respawn:", "#4:2345:respawn:");
571 replace("/harddisk/etc/inittab", "5:2345:respawn:", "#5:2345:respawn:");
572 replace("/harddisk/etc/inittab", "6:2345:respawn:", "#6:2345:respawn:");
573 replace("/harddisk/etc/inittab", "#7:2345:respawn:", "7:2345:respawn:");
576 /* Set marker that the user has already accepted the gpl */
577 mysystem("/usr/bin/touch /harddisk/var/ipfire/main/gpl_accepted");
579 /* Copy restore file from cdrom */
580 if (unattended
&& (strlen(restore_file
) > 0)) {
581 fprintf(flog
, "unattended: Copy restore file\n");
582 snprintf(commandstring
, STRING_SIZE
,
583 "cp /cdrom/%s /harddisk/var/ipfire/backup", restore_file
);
584 mysystem(commandstring
);
587 // Umount source drive and eject
588 hw_umount(SOURCE_MOUNT_PATH
);
590 snprintf(commandstring
, STRING_SIZE
, "/usr/bin/eject %s", sourcedrive
);
591 mysystem(commandstring
);
594 sprintf(message
, ctr
[TR_CONGRATULATIONS_LONG
],
596 newtWinMessage(ctr
[TR_CONGRATULATIONS
], ctr
[TR_PRESS_OK_TO_REBOOT
], message
);
602 fprintf(flog
, "Install program ended.\n");
605 newtWinMessage(title
, ctr
[TR_OK
], ctr
[TR_PRESS_OK_TO_REBOOT
]);
618 hw_umount_filesystems(destination
, DESTINATION_MOUNT_PATH
);
623 hw_free_disks(selected_disks
);