Revert "rc-update del takes only the initscript name as argument"
[pentoo:pentoo-installer.git] / setup
1 #!/bin/bash
2 # This script is released under the GNU General Public License 3.0
3 # Check the COPYING file included with this distribution
4
5 ANSWER="/tmp/.setup"
6 TITLE="Pentoo Installation"
7 # use the first VT not dedicated to a running console
8 LOG="/dev/tty8"
9 DESTDIR="/mnt/gentoo"
10 EDITOR=
11
12 # clock
13 HARDWARECLOCK=
14 TIMEZONE=
15
16 # partitions
17 PART_ROOT=
18
19 # default filesystem specs (the + is bootable flag)
20 # <mountpoint>:<partsize>:<fstype>[:+]
21 DEFAULTFS="/boot:32:ext2:+ swap:256:swap /:7500:ext4 /home:*:ext4"
22
23 # install stages
24 S_CLOCK=0       # clock and timezone
25 S_PART=0        # partitioning
26 S_MKFS=0        # formatting
27 S_MKFSAUTO=0    # auto fs part/formatting TODO: kill this
28 S_CONFIG=0      # configuration editing
29 S_GRUB=0        # TODO: kill this - if using grub
30 S_BOOT=""       # bootloader installed (set to loader name instead of 1)
31
32
33 # main menu selection tracker
34 CURRENT_SELECTION=""
35
36 # DIALOG()
37 # an el-cheapo dialog wrapper
38 #
39 # parameters: see dialog(1)
40 # returns: whatever dialog did
41 DIALOG() {
42     dialog --backtitle "$TITLE" --aspect 15 "$@"
43     return $?
44 }
45
46 # chroot_mount()
47 # prepares target system as a chroot
48 #
49 chroot_mount()
50 {
51     [ -e "${DESTDIR}/sys" ] || mkdir "${DESTDIR}/sys"
52     [ -e "${DESTDIR}/proc" ] || mkdir "${DESTDIR}/proc"
53     [ -e "${DESTDIR}/dev" ] || mkdir "${DESTDIR}/dev"
54     mount -t sysfs sysfs "${DESTDIR}/sys"
55     mount -t proc proc "${DESTDIR}/proc"
56     mount -o bind /dev "${DESTDIR}/dev"
57 }
58
59 # chroot_umount()
60 # tears down chroot in target system
61 #
62 chroot_umount()
63 {
64     umount $DESTDIR/proc
65     umount $DESTDIR/sys
66     umount $DESTDIR/dev
67 }
68
69 finddisks() {
70     workdir="$PWD"
71     cd /sys/block
72     # ide devices
73     for dev in $(ls | egrep '^hd'); do
74         if [ "$(cat $dev/device/media)" = "disk" ]; then
75             echo "/dev/$dev"
76             [ "$1" ] && echo $1
77         fi
78     done
79     #scsi/sata devices
80     for dev in $(ls | egrep '^sd'); do
81         # TODO: what is the significance of 5?
82         if ! [ "$(cat $dev/device/type)" = "5" ]; then
83             echo "/dev/$dev"
84             [ "$1" ] && echo $1
85         fi
86     done
87     # cciss controllers
88     if [ -d /dev/cciss ] ; then
89         cd /dev/cciss
90         for dev in $(ls | egrep -v 'p'); do
91             echo "/dev/cciss/$dev"
92             [ "$1" ] && echo $1
93         done
94     fi
95     # Smart 2 controllers
96     if [ -d /dev/ida ] ; then
97         cd /dev/ida
98         for dev in $(ls | egrep -v 'p'); do
99             echo "/dev/ida/$dev"
100             [ "$1" ] && echo $1
101         done
102     fi
103     cd "$workdir"
104 }
105
106 # getuuid()
107 # converts /dev/[hs]d?[0-9] devices to UUIDs
108 #
109 # parameters: device file
110 # outputs:    UUID on success
111 #             nothing on failure
112 # returns:    nothing
113 getuuid()
114 {
115     if [ "${1%%/[hs]d?[0-9]}" != "${1}" ]; then
116         echo "$(blkid -s UUID -o value ${1})"
117     fi
118 }
119
120 findpartitions() {
121     workdir="$PWD"
122     for devpath in $(finddisks); do
123         disk=$(echo $devpath | sed 's|.*/||')
124         cd /sys/block/$disk
125         for part in $disk*; do
126             # check if not already assembled to a raid device
127             if ! [ "$(cat /proc/mdstat 2>/dev/null | grep $part)" -o "$(fstype 2>/dev/null </dev/$part | grep "lvm2")" -o "$(sfdisk -c /dev/$disk $(echo $part | sed -e "s#$disk##g") 2>/dev/null | grep "5")" ]; then
128                 if [ -d $part ]; then
129                     echo "/dev/$part"
130                     [ "$1" ] && echo $1
131                 fi
132             fi
133         done
134     done
135     # include any mapped devices
136     for devpath in $(ls /dev/mapper 2>/dev/null | grep -v control); do
137         echo "/dev/mapper/$devpath"
138         [ "$1" ] && echo $1
139     done
140     # include any raid md devices
141     for devpath in $(ls -d /dev/md* | grep '[0-9]' 2>/dev/null); do
142         if cat /proc/mdstat | grep -qw $(echo $devpath | sed -e 's|/dev/||g'); then
143         echo "$devpath"
144         [ "$1" ] && echo $1
145         fi
146     done
147     # inlcude cciss controllers
148     if [ -d /dev/cciss ] ; then
149         cd /dev/cciss
150         for dev in $(ls | egrep 'p'); do
151             echo "/dev/cciss/$dev"
152             [ "$1" ] && echo $1
153         done
154     fi
155     # inlcude Smart 2 controllers
156     if [ -d /dev/ida ] ; then
157         cd /dev/ida
158         for dev in $(ls | egrep 'p'); do
159             echo "/dev/ida/$dev"
160             [ "$1" ] && echo $1
161         done
162     fi
163     cd "$workdir"
164 }
165
166 get_grub_map() {
167     rm /tmp/dev.map
168     DIALOG --infobox "Generating GRUB device map...\nThis could take a while.\n\n Please be patient." 0 0
169     $DESTDIR/sbin/grub --no-floppy --device-map /tmp/dev.map >/tmp/grub.log 2>&1 <<EOF
170 quit
171 EOF
172 }
173
174 mapdev() {
175     partition_flag=0
176     device_found=0
177     devs=$(cat /tmp/dev.map | grep -v fd | sed 's/ *\t/ /' | sed ':a;$!N;$!ba;s/\n/ /g')
178     linuxdevice=$(echo $1 | cut -b1-8)
179     if [ "$(echo $1 | egrep '[0-9]$')" ]; then
180         # /dev/hdXY
181         pnum=$(echo $1 | cut -b9-)
182         pnum=$(($pnum-1))
183         partition_flag=1
184     fi
185     for  dev in $devs
186     do
187         if [ "(" = $(echo $dev | cut -b1) ]; then
188         grubdevice="$dev"
189         else
190         if [ "$dev" = "$linuxdevice" ]; then
191             device_found=1
192             break
193         fi
194        fi
195     done
196     if [ "$device_found" = "1" ]; then
197         if [ "$partition_flag" = "0" ]; then
198             echo "$grubdevice"
199         else
200             grubdevice_stringlen=${#grubdevice}
201             grubdevice_stringlen=$(($grubdevice_stringlen - 1))
202             grubdevice=$(echo $grubdevice | cut -b1-$grubdevice_stringlen)
203             echo "$grubdevice,$pnum)"
204         fi
205     else
206         echo "DEVICE NOT FOUND"
207     fi
208 }
209
210 printk()
211 {
212     case $1 in
213         "on")  echo 4 >/proc/sys/kernel/printk ;;
214         "off") echo 0 >/proc/sys/kernel/printk ;;
215     esac
216 }
217
218 # geteditor()
219 # prompts the user to choose an editor
220 # sets EDITOR global variable
221 #
222 geteditor() {
223     DIALOG --menu "Select a Text Editor to Use" 10 35 3 \
224         "1" "nano (easier)" \
225         "2" "vi" 2>$ANSWER
226     case $(cat $ANSWER) in
227         "1") EDITOR="nano" ;;
228         "2") EDITOR="vi" ;;
229         *)   EDITOR="nano" ;;
230     esac
231 }
232
233 # _mkfs()
234 # Create and mount filesystems in our destination system directory.
235 #
236 # args:
237 #  domk: Whether to make the filesystem or use what is already there
238 #  device: Device filesystem is on
239 #  fstype: type of filesystem located at the device (or what to create)
240 #  dest: Mounting location for the destination system
241 #  mountpoint: Mount point inside the destination system, e.g. '/boot'
242
243 # returns: 1 on failure
244 _mkfs() {
245     local _domk=$1
246     local _device=$2
247     local _fstype=$3
248     local _dest=$4
249     local _mountpoint=$5
250
251     # we have two main cases: "swap" and everything else.
252     if [ "${_fstype}" = "swap" ]; then
253         swapoff ${_device} >/dev/null 2>&1
254         if [ "${_domk}" = "yes" ]; then
255             mkswap ${_device} >$LOG 2>&1
256             if [ $? != 0 ]; then
257                 DIALOG --msgbox "Error creating swap: mkswap ${_device}" 0 0
258                 return 1
259             fi
260         fi
261         swapon ${_device} >$LOG 2>&1
262         if [ $? != 0 ]; then
263             DIALOG --msgbox "Error activating swap: swapon ${_device}" 0 0
264             return 1
265         fi
266     else
267         # make sure the fstype is one we can handle
268         local knownfs=0
269         for fs in xfs jfs reiserfs ext2 ext3 ext4 vfat; do
270             [ "${_fstype}" = "${fs}" ] && knownfs=1 && break
271         done
272         if [ $knownfs -eq 0 ]; then
273             DIALOG --msgbox "unknown fstype ${_fstype} for ${_device}" 0 0
274             return 1
275         fi
276         # if we were tasked to create the filesystem, do so
277         if [ "${_domk}" = "yes" ]; then
278             local ret
279             case ${_fstype} in
280                 xfs)      mkfs.xfs -f ${_device} >$LOG 2>&1; ret=$? ;;
281                 jfs)      yes | mkfs.jfs ${_device} >$LOG 2>&1; ret=$? ;;
282                 reiserfs) yes | mkreiserfs ${_device} >$LOG 2>&1; ret=$? ;;
283                 ext2)     mke2fs "${_device}" >$LOG 2>&1; ret=$? ;;
284                 ext3)     mke2fs -j ${_device} >$LOG 2>&1; ret=$? ;;
285                 ext4)     mke2fs -t ext4 ${_device} >$LOG 2>&1; ret=$? ;;
286                 vfat)     mkfs.vfat ${_device} >$LOG 2>&1; ret=$? ;;
287                 # don't handle anything else here, we will error later
288             esac
289             if [ $ret != 0 ]; then
290                 DIALOG --msgbox "Error creating filesystem ${_fstype} on ${_device}" 0 0
291                 return 1
292             fi
293             sleep 2
294         fi
295         # create our mount directory
296         mkdir -p ${_dest}${_mountpoint}
297         # mount the bad boy
298         mount -t ${_fstype} ${_device} ${_dest}${_mountpoint} >$LOG 2>&1
299         if [ $? != 0 ]; then
300             DIALOG --msgbox "Error mounting ${_dest}${_mountpoint}" 0 0
301             return 1
302         fi
303     fi
304
305     # add to temp fstab
306     echo -n "${_device} ${_mountpoint} ${_fstype} defaults 0 " >>/tmp/.fstab
307
308     if [ "${_fstype}" = "swap" ]; then
309         echo "0" >>/tmp/.fstab
310     else
311         echo "1" >>/tmp/.fstab
312     fi
313 }
314
315 # Disable swap and all mounted partitions for the destination system. Unmount
316 # the destination root partition last!
317 _umountall()
318 {
319     DIALOG --infobox "Disabling swapspace, unmounting already mounted disk devices..." 0 0
320     swapoff -a >/dev/null 2>&1
321     umount $(mount | grep -v "${DESTDIR} " | grep "${DESTDIR}" | sed 's|\ .*||g') >/dev/null 2>&1
322     umount $(mount | grep "${DESTDIR} " | sed 's|\ .*||g') >/dev/null 2>&1
323 }
324
325 # _getdisccapacity()
326 #
327 # parameters: device file
328 # outputs:    disc capacity in bytes
329 _getdisccapacity()
330 {
331     fdisk -l $1 2>/dev/null | sed -n '2p' | cut -d' ' -f5
332 }
333
334 # Get a list of available disks for use in the "Available disks" dialogs. This
335 # will print the disks as follows, getting size info from _getdisccapacity():
336 #   /dev/sda: 625000 MiB (610 GiB)
337 #   /dev/sdb: 476940 MiB (465 GiB)
338 _getavaildisks()
339 {
340     for DISC in $(finddisks); do
341         DISC_SIZE=$(_getdisccapacity $DISC)
342         echo "$DISC: $((DISC_SIZE / 2**20)) MiB ($((DISC_SIZE / 2**30)) GiB)\n"
343     done
344 }
345
346 autoprepare()
347 {
348     DISCS=$(finddisks)
349     if [ $(echo $DISCS | wc -w) -gt 1 ]; then
350         DIALOG --msgbox "Available Disks:\n\n$(_getavaildisks)\n" 0 0
351         DIALOG --menu "Select the hard drive to use" 14 55 7 $(finddisks _) 2>$ANSWER || return 1
352         DISC=$(cat $ANSWER)
353     else
354         DISC=$DISCS
355     fi
356     SET_DEFAULTFS=""
357     BOOT_PART_SET=""
358     SWAP_PART_SET=""
359     ROOT_PART_SET=""
360     CHOSEN_FS=""
361     # disk size in MiB
362     DISC_SIZE=$(($(_getdisccapacity $DISC) / 2**20))
363     while [ "$SET_DEFAULTFS" = "" ]; do
364         FSOPTS="ext2 ext2 ext3 ext3 ext4 ext4"
365         [ "$(which mkreiserfs 2>/dev/null)" ] && FSOPTS="$FSOPTS reiserfs Reiser3"
366         [ "$(which mkfs.xfs 2>/dev/null)" ]   && FSOPTS="$FSOPTS xfs XFS"
367         [ "$(which mkfs.jfs 2>/dev/null)" ]   && FSOPTS="$FSOPTS jfs JFS"
368         while [ "$BOOT_PART_SET" = "" ]; do
369             DIALOG --inputbox "Enter the size (MiB) of your /boot partition.  Minimum value is 16.\n\nDisk space left: $DISC_SIZE MiB" 10 65 "32" 2>$ANSWER || return 1
370             BOOT_PART_SIZE="$(cat $ANSWER)"
371             if [ "$BOOT_PART_SIZE" = "" ]; then
372                 DIALOG --msgbox "ERROR: You have entered an invalid size, please enter again." 0 0
373             else
374                 if [ "$BOOT_PART_SIZE" -ge "$DISC_SIZE" -o "$BOOT_PART_SIZE" -lt "16" -o "$SBOOT_PART_SIZE" = "$DISC_SIZE" ]; then
375                     DIALOG --msgbox "ERROR: You have entered a too large size, please enter again." 0 0
376                 else
377                     BOOT_PART_SET=1
378                 fi
379             fi
380         done
381         DISC_SIZE=$(($DISC_SIZE-$BOOT_PART_SIZE))
382         while [ "$SWAP_PART_SET" = "" ]; do
383             DIALOG --inputbox "Enter the size (MiB) of your swap partition.  Minimum value is > 0.\n\nDisk space left: $DISC_SIZE MiB" 10 65 "256" 2>$ANSWER || return 1
384             SWAP_PART_SIZE=$(cat $ANSWER)
385             if [ "$SWAP_PART_SIZE" = "" -o  "$SWAP_PART_SIZE" -le "0" ]; then
386                 DIALOG --msgbox "ERROR: You have entered an invalid size, please enter again." 0 0
387             else
388                 if [ "$SWAP_PART_SIZE" -ge "$DISC_SIZE" ]; then
389                     DIALOG --msgbox "ERROR: You have entered a too large size, please enter again." 0 0
390                 else
391                     SWAP_PART_SET=1
392                 fi
393             fi
394         done
395         DISC_SIZE=$(($DISC_SIZE-$SWAP_PART_SIZE))
396         while [ "$ROOT_PART_SET" = "" ]; do
397             DIALOG --inputbox "Enter the size (MiB) of your / partition.  The /home partition will use the remaining space.\n\nDisk space left:  $DISC_SIZE MiB" 10 65 "7500" 2>$ANSWER || return 1
398             ROOT_PART_SIZE=$(cat $ANSWER)
399             if [ "$ROOT_PART_SIZE" = "" -o "$ROOT_PART_SIZE" -le "0" ]; then
400                 DIALOG --msgbox "ERROR: You have entered an invalid size, please enter again." 0 0
401             else
402                 if [ "$ROOT_PART_SIZE" -ge "$DISC_SIZE" ]; then
403                     DIALOG --msgbox "ERROR: You have entered a too large size, please enter again." 0 0
404                 else
405                     DIALOG --yesno "$(($DISC_SIZE-$ROOT_PART_SIZE)) MiB will be used for your /home partition.  Is this OK?" 0 0 && ROOT_PART_SET=1
406                 fi
407             fi
408         done
409         while [ "$CHOSEN_FS" = "" ]; do
410             DIALOG --menu "Select a filesystem for / and /home:" 13 45 6 $FSOPTS 2>$ANSWER || return 1
411             FSTYPE=$(cat $ANSWER)
412             DIALOG --yesno "$FSTYPE will be used for / and /home. Is this OK?" 0 0 && CHOSEN_FS=1
413         done
414         SET_DEFAULTFS=1
415     done
416
417     DIALOG --defaultno --yesno "$DISC will be COMPLETELY ERASED!  Are you absolutely sure?" 0 0 \
418     || return 1
419
420     DEVICE=$DISC
421     FSSPECS=$(echo $DEFAULTFS | sed -e "s|/:7500:ext3|/:$ROOT_PART_SIZE:$FSTYPE|g" -e "s|/home:\*:ext3|/home:\*:$FSTYPE|g" -e "s|swap:256|swap:$SWAP_PART_SIZE|g" -e "s|/boot:32|/boot:$BOOT_PART_SIZE|g")
422     sfdisk_input=""
423
424     # we assume a /dev/hdX format (or /dev/sdX)
425     PART_ROOT="${DEVICE}3"
426
427     if [ "$S_MKFS" = "1" ]; then
428         DIALOG --msgbox "You have already prepared your filesystems manually" 0 0
429         return 0
430     fi
431
432     # validate DEVICE
433     if [ ! -b "$DEVICE" ]; then
434       DIALOG --msgbox "Device '$DEVICE' is not valid" 0 0
435       return 1
436     fi
437
438     # validate DEST
439     if [ ! -d "$DESTDIR" ]; then
440         DIALOG --msgbox "Destination directory '$DESTDIR' is not valid" 0 0
441         return 1
442     fi
443
444     # / required
445     if [ $(echo $FSSPECS | grep '/:' | wc -l) -ne 1 ]; then
446         DIALOG --msgbox "Need exactly one root partition" 0 0
447         return 1
448     fi
449
450     rm -f /tmp/.fstab
451
452     _umountall
453
454     # setup input var for sfdisk
455     for fsspec in $FSSPECS; do
456         fssize=$(echo $fsspec | tr -d ' ' | cut -f2 -d:)
457         if [ "$fssize" = "*" ]; then
458                 fssize_spec=';'
459         else
460                 fssize_spec=",$fssize"
461         fi
462         fstype=$(echo $fsspec | tr -d ' ' | cut -f3 -d:)
463         if [ "$fstype" = "swap" ]; then
464                 fstype_spec=",S"
465         else
466                 fstype_spec=","
467         fi
468         bootflag=$(echo $fsspec | tr -d ' ' | cut -f4 -d:)
469         if [ "$bootflag" = "+" ]; then
470             bootflag_spec=",*"
471         else
472             bootflag_spec=""
473         fi
474         sfdisk_input="${sfdisk_input}${fssize_spec}${fstype_spec}${bootflag_spec}\n"
475     done
476     sfdisk_input=$(printf "$sfdisk_input")
477
478     # invoke sfdisk
479     printk off
480     DIALOG --infobox "Partitioning $DEVICE" 0 0
481     sfdisk $DEVICE -uM >$LOG 2>&1 <<EOF
482 $sfdisk_input
483 EOF
484     if [ $? -gt 0 ]; then
485         DIALOG --msgbox "Error partitioning $DEVICE (see $LOG for details)" 0 0
486         printk on
487         return 1
488     fi
489     printk on
490
491     # need to mount root first, then do it again for the others
492     part=1
493     for fsspec in $FSSPECS; do
494         mountpoint=$(echo $fsspec | tr -d ' ' | cut -f1 -d:)
495         fstype=$(echo $fsspec | tr -d ' ' | cut -f3 -d:)
496         if echo $mountpoint | tr -d ' ' | grep '^/$' 2>&1 > /dev/null; then
497             _mkfs yes ${DEVICE}${part} "$fstype" "$DESTDIR" "$mountpoint" || return 1
498         fi
499         part=$(($part + 1))
500     done
501
502     # make other filesystems
503     part=1
504     for fsspec in $FSSPECS; do
505         mountpoint=$(echo $fsspec | tr -d ' ' | cut -f1 -d:)
506         fstype=$(echo $fsspec | tr -d ' ' | cut -f3 -d:)
507         if [ $(echo $mountpoint | tr -d ' ' | grep '^/$' | wc -l) -eq 0 ]; then
508             _mkfs yes ${DEVICE}${part} "$fstype" "$DESTDIR" "$mountpoint" || return 1
509         fi
510         part=$(($part + 1))
511     done
512
513     DIALOG --msgbox "Auto-prepare was successful" 0 0
514     S_MKFSAUTO=1
515 }
516
517 partition() {
518     if [ "$S_MKFSAUTO" = "1" ]; then
519         DIALOG --msgbox "You have already prepared your filesystems with Auto-prepare" 0 0
520         return 0
521     fi
522
523     _umountall
524
525     # Select disk to partition
526     DISCS=$(finddisks _)
527     DISCS="$DISCS OTHER - DONE +"
528     DIALOG --msgbox "Available Disks:\n\n$(_getavaildisks)\n" 0 0
529     DISC=""
530     while true; do
531         # Prompt the user with a list of known disks
532         DIALOG --menu "Select the disk you want to partition (select DONE when finished)" 14 55 7 $DISCS 2>$ANSWER || return 1
533         DISC=$(cat $ANSWER)
534         if [ "$DISC" = "OTHER" ]; then
535             DIALOG --inputbox "Enter the full path to the device you wish to partition" 8 65 "/dev/sda" 2>$ANSWER || return 1
536             DISC=$(cat $ANSWER)
537         fi
538         # Leave our loop if the user is done partitioning
539         [ "$DISC" = "DONE" ] && break
540         # Partition disc
541         DIALOG --msgbox "Now you'll be put into the cfdisk program where you can partition your hard drive. You should make a swap partition and as many data partitions as you will need.  NOTE: cfdisk may tell you to reboot after creating partitions.  If you need to reboot, just re-enter this install program, skip this step and go on to step 2." 18 70
542         cfdisk $DISC
543     done
544     S_PART=1
545 }
546
547 mountpoints() {
548     if [ "$S_MKFSAUTO" = "1" ]; then
549         DIALOG --msgbox "You have already prepared your filesystems with Auto-prepare" 0 0
550         return 0
551     fi
552     while [ "$PARTFINISH" != "DONE" ]; do
553         : >/tmp/.fstab
554         : >/tmp/.parts
555
556         # Determine which filesystems are available
557         FSOPTS="ext2 ext2 ext3 ext3 ext4 ext4"
558         [ "$(which mkreiserfs 2>/dev/null)" ] && FSOPTS="$FSOPTS reiserfs Reiser3"
559         [ "$(which mkfs.xfs 2>/dev/null)" ]   && FSOPTS="$FSOPTS xfs XFS"
560         [ "$(which mkfs.jfs 2>/dev/null)" ]   && FSOPTS="$FSOPTS jfs JFS"
561         [ "$(which mkfs.vfat 2>/dev/null)" ]  && FSOPTS="$FSOPTS vfat VFAT"
562
563         # Select mountpoints
564         DIALOG --msgbox "Available Disks:\n\n$(_getavaildisks)\n" 0 0
565         PARTS=$(findpartitions _)
566         DIALOG --menu "Select the partition to use as swap" 21 50 13 NONE - $PARTS 2>$ANSWER || return 1
567         PART=$(cat $ANSWER)
568         PARTS="$(echo $PARTS | sed -e "s#${PART}\ _##g")"
569         if [ "$PART" != "NONE" ]; then
570             DOMKFS="no"
571             DIALOG --yesno "Would you like to create a filesystem on $PART?\n\n(This will overwrite existing data!)" 0 0 && DOMKFS="yes"
572             echo "$PART:swap:swap:$DOMKFS" >>/tmp/.parts
573         fi
574
575         DIALOG --menu "Select the partition to mount as /" 21 50 13 $PARTS 2>$ANSWER || return 1
576         PART=$(cat $ANSWER)
577         PARTS="$(echo $PARTS | sed -e "s#${PART}\ _##g")"
578         PART_ROOT=$PART
579         # Select root filesystem type
580         DIALOG --menu "Select a filesystem for $PART" 13 45 6 $FSOPTS 2>$ANSWER || return 1
581         FSTYPE=$(cat $ANSWER)
582         DOMKFS="no"
583         DIALOG --yesno "Would you like to create a filesystem on $PART?\n\n(This will overwrite existing data!)" 0 0 && DOMKFS="yes"
584         echo "$PART:$FSTYPE:/:$DOMKFS" >>/tmp/.parts
585
586         #
587         # Additional partitions
588         #
589         DIALOG --menu "Select any additional partitions to mount under your new root (select DONE when finished)" 21 50 13 $PARTS DONE _ 2>$ANSWER || return 1
590         PART=$(cat $ANSWER)
591         while [ "$PART" != "DONE" ]; do
592             PARTS="$(echo $PARTS | sed -e "s#${PART}\ _##g")"
593             # Select a filesystem type
594             DIALOG --menu "Select a filesystem for $PART" 13 45 6 $FSOPTS 2>$ANSWER || return 1
595             FSTYPE=$(cat $ANSWER)
596             MP=""
597             while [ "${MP}" = "" ]; do
598                 DIALOG --inputbox "Enter the mountpoint for $PART" 8 65 "/boot" 2>$ANSWER || return 1
599                 MP=$(cat $ANSWER)
600                 if grep ":$MP:" /tmp/.parts; then
601                     DIALOG --msgbox "ERROR: You have defined 2 identical mountpoints! Please select another mountpoint." 8 65
602                     MP=""
603                 fi
604             done
605             DOMKFS="no"
606             DIALOG --yesno "Would you like to create a filesystem on $PART?\n\n(This will overwrite existing data!)" 0 0 && DOMKFS="yes"
607             echo "$PART:$FSTYPE:$MP:$DOMKFS" >>/tmp/.parts
608             DIALOG --menu "Select any additional partitions to mount under your new root" 21 50 13 $PARTS DONE _ 2>$ANSWER || return 1
609             PART=$(cat $ANSWER)
610         done
611         DIALOG --yesno "Would you like to create and mount the filesytems like this?\n\nSyntax\n------\nDEVICE:TYPE:MOUNTPOINT:FORMAT\n\n$(for i in $(cat /tmp/.parts); do echo "$i\n";done)" 18 0 && PARTFINISH="DONE"
612     done
613
614     _umountall
615
616     for line in $(cat /tmp/.parts); do
617         PART=$(echo $line | cut -d: -f 1)
618         FSTYPE=$(echo $line | cut -d: -f 2)
619         MP=$(echo $line | cut -d: -f 3)
620         DOMKFS=$(echo $line | cut -d: -f 4)
621         umount ${DESTDIR}${MP}
622         if [ "$DOMKFS" = "yes" ]; then
623             if [ "$FSTYPE" = "swap" ]; then
624                 DIALOG --infobox "Creating and activating swapspace on $PART" 0 0
625             else
626                 DIALOG --infobox "Creating $FSTYPE on $PART, mounting to ${DESTDIR}${MP}" 0 0
627             fi
628             _mkfs yes $PART $FSTYPE $DESTDIR $MP || return 1
629         else
630             if [ "$FSTYPE" = "swap" ]; then
631                 DIALOG --infobox "Activating swapspace on $PART" 0 0
632             else
633                 DIALOG --infobox "Mounting $PART to ${DESTDIR}${MP}" 0 0
634             fi
635             _mkfs no $PART $FSTYPE $DESTDIR $MP || return 1
636         fi
637         sleep 1
638     done
639
640     DIALOG --msgbox "Partitions were successfully mounted." 0 0
641     S_MKFS=1
642 }
643
644 # do_rsync()
645 # does the rsync
646 #
647 # params: none
648 # returns: 1 on error
649 do_rsync() {
650     DIALOG --infobox "Copy in progress. This may take a while - you can watch the output in the progress window." 6 45
651
652     rsync -av /mnt/livecd/* ${DESTDIR} 2>&1 >$LOG
653     rsync -av /etc/* ${DESTDIR}/etc/ 2>&1 >>$LOG
654     rsync -av /root/* ${DESTDIR}/root/ 2>&1 >>$LOG
655     rsync -av /usr/portage/ ${DESTDIR}/usr/ >>$LOG
656     if [ $? -ne 0 ]; then
657         DIALOG --msgbox "Rsync failed (maybe you're out of disk space?). See the log output for more information"
658         return 1
659     fi
660
661     mknod -m666 ${DESTDIR}/dev/zero c 1 5
662     mknod -m666 ${DESTDIR}/dev/null c 1 3
663     mknod -m600 ${DESTDIR}/dev/console c 5 1
664     mkdir -m755 ${DESTDIR}/media/{cd,dvd,fl}
665
666     S_SELECT=1
667 }
668
669 # auto_fstab()
670 # preprocess fstab file
671 # comments out old fields and inserts new ones
672 # according to partitioning/formatting stage
673 #
674 auto_fstab()
675 {
676     if [ "$S_MKFS" = "1" -o "$S_MKFSAUTO" = "1" ]; then
677         if [ -f /tmp/.fstab ]; then
678             # comment out stray /dev entries
679             sed -i 's/^\/dev/#\/dev/g' $DESTDIR/etc/fstab
680             # append entries from new configuration
681             sort /tmp/.fstab >>$DESTDIR/etc/fstab
682         fi
683     fi
684 }
685
686 dogrub() {
687     get_grub_map
688     local grubmenu="$DESTDIR/boot/grub/menu.lst"
689     if [ ! -f $grubmenu ]; then
690         DIALOG --msgbox "Error: Couldn't find $grubmenu.  Is GRUB installed?" 0 0
691         return 1
692     fi
693     # try to auto-configure GRUB...
694     if [ "$PART_ROOT" != "" -a "$S_GRUB" != "1" ]; then
695         grubdev=$(mapdev $PART_ROOT)
696         local _rootpart="${PART_ROOT}"
697         # look for a separately-mounted /boot partition
698         bootdev=$(mount | grep $DESTDIR/boot | cut -d' ' -f 1)
699         if [ "$grubdev" != "" -o "$bootdev" != "" ]; then
700             subdir=
701             if [ "$bootdev" != "" ]; then
702                 grubdev=$(mapdev $bootdev)
703             else
704                 subdir="/boot"
705             fi
706             # keep the file from being completely bogus
707             if [ "$grubdev" = "DEVICE NOT FOUND" ]; then
708                 DIALOG --msgbox "Your root boot device could not be autodetected by setup.  Ensure you adjust the 'root (hd0,0)' line in your GRUB config accordingly." 0 0
709                 grubdev="(hd0,0)"
710             fi
711             # remove default entries by truncating file at our little tag (#-*)
712             sed -i -e '/#-\*/q' $grubmenu
713             # parse kernel cmdline (only video mode for now)
714             for _var in $(cat /proc/cmdline)
715             do
716                         case $_var in
717                                 video=*)
718                                 eval $(echo $_var)
719                                 ;;
720                         esac
721                 done
722             # get kernel version
723             local _kernver=$(ls $DESTDIR/boot/kernel-genkernel-* |sed -e "s|kernel-genkernel||g" -e "s|$DESTDIR/boot/||")
724             cat >>$grubmenu <<EOF
725
726 # (0) Pentoo
727 title  Pentoo
728 root   $grubdev
729 kernel $subdir/kernel-genkernel${_kernver} root=/dev/ram0 real_root=${_rootpart} ${_cmdline} video=${video} console=tty1 ro
730 initrd $subdir/initramfs-genkernel${_kernver}
731
732 # (2) Windows
733 #title Windows
734 #rootnoverify (hd0,0)
735 #makeactive
736 #chainloader +1
737 EOF
738         fi
739     fi
740
741     DIALOG --msgbox "Before installing GRUB, you must review the configuration file.  You will now be put into the editor.  After you save your changes and exit the editor, you can install GRUB." 0 0
742     [ "$EDITOR" ] || geteditor
743     $EDITOR $grubmenu
744
745     DEVS=$(finddisks _)
746     DEVS="$DEVS $(findpartitions _)"
747     if [ "$DEVS" = "" ]; then
748         DIALOG --msgbox "No hard drives were found" 0 0
749         return 1
750     fi
751     DIALOG --menu "Select the boot device where the GRUB bootloader will be installed (usually the MBR and not a partition)." 14 55 7 $DEVS 2>$ANSWER || return 1
752     ROOTDEV=$(cat $ANSWER)
753     DIALOG --infobox "Installing the GRUB bootloader..." 0 0
754     cp -a $DESTDIR/usr/lib/grub/i386-pc/* $DESTDIR/boot/grub/
755     sync
756     # freeze xfs filesystems to enable grub installation on xfs filesystems
757     if [ -x /usr/sbin/xfs_freeze ]; then
758         /usr/sbin/xfs_freeze -f $DESTDIR/boot > /dev/null 2>&1
759         /usr/sbin/xfs_freeze -f $DESTDIR/ > /dev/null 2>&1
760     fi
761     # look for a separately-mounted /boot partition
762     bootpart=$(mount | grep $DESTDIR/boot | cut -d' ' -f 1)
763     if [ "$bootpart" = "" ]; then
764         if [ "$PART_ROOT" = "" ]; then
765             DIALOG --inputbox "Enter the full path to your root device" 8 65 "/dev/sda3" 2>$ANSWER || return 1
766             bootpart=$(cat $ANSWER)
767         else
768             bootpart=$PART_ROOT
769         fi
770     fi
771     DIALOG --defaultno --yesno "Do you have your system installed on software raid?\nAnswer 'YES' to install grub to another hard disk." 0 0
772     if [ $? -eq 0 ]; then
773         DIALOG --menu "Please select the boot partition device, this cannot be autodetected!\nPlease redo grub installation for all partitions you need it!" 14 55 7 $DEVS 2>$ANSWER || return 1
774         bootpart=$(cat $ANSWER)
775     fi
776     bootpart=$(mapdev $bootpart)
777     bootdev=$(mapdev $ROOTDEV)
778     if [ "$bootpart" = "" ]; then
779         DIALOG --msgbox "Error: Missing/Invalid root device: $bootpart" 0 0
780         return 1
781     fi
782     if [ "$bootpart" = "DEVICE NOT FOUND" -o "$bootdev" = "DEVICE NOT FOUND" ]; then
783         DIALOG --msgbox "GRUB root and setup devices could not be auto-located.  You will need to manually run the GRUB shell to install a bootloader." 0 0
784         return 1
785     fi
786     /sbin/grub-install --no-floppy --recheck --grub-shell=$DESTDIR/sbin/grub --root-directory=$DESTDIR $ROOTDEV >/tmp/grub.log 2>&1
787     cat /tmp/grub.log >$LOG
788     # unfreeze xfs filesystems
789     if [ -x /usr/sbin/xfs_freeze ]; then
790         /usr/sbin/xfs_freeze -u $DESTDIR/boot > /dev/null 2>&1
791         /usr/sbin/xfs_freeze -u $DESTDIR/ > /dev/null 2>&1
792     fi
793
794     if grep "Error [0-9]*: " /tmp/grub.log >/dev/null; then
795         DIALOG --msgbox "Error installing GRUB. (see $LOG for output)" 0 0
796         return 1
797     fi
798     DIALOG --msgbox "GRUB was successfully installed." 0 0
799     S_GRUB=1
800 }
801
802 # set_clock()
803 # prompts user to set hardware clock and timezone
804 #
805 # params: none
806 # returns: 1 on failure
807 set_clock()
808 {
809     # utc or local?
810     DIALOG --menu "Is your hardware clock in UTC or local time?" 10 50 2 \
811         "UTC" " " \
812         "local" " " \
813         2>$ANSWER || return 1
814     HARDWARECLOCK=$(cat $ANSWER)
815
816     # timezone?
817     tzselect > $ANSWER || return 1
818     TIMEZONE=$(cat $ANSWER)
819
820     # set system clock from hwclock - stolen from rc.sysinit
821     local HWCLOCK_PARAMS=""
822     if [ "$HARDWARECLOCK" = "UTC" ]; then
823         HWCLOCK_PARAMS="$HWCLOCK_PARAMS --utc"
824     else
825         HWCLOCK_PARAMS="$HWCLOCK_PARAMS --localtime"
826     fi
827     if [ "$TIMEZONE" != "" -a -e "/usr/share/zoneinfo/$TIMEZONE" ]; then
828         /bin/rm -f /etc/localtime
829         /bin/cp "/usr/share/zoneinfo/$TIMEZONE" /etc/localtime
830     fi
831     /sbin/hwclock --hctosys $HWCLOCK_PARAMS --noadjfile
832
833     # display and ask to set date/time
834     dialog --calendar "Set the date.\nUse <TAB> to navigate and arrow keys to change values." 0 0 0 0 0 2> $ANSWER || return 1
835     local _date="$(cat $ANSWER)"
836     dialog --timebox "Set the time.\nUse <TAB> to navigate and up/down to change values." 0 0 2> $ANSWER || return 1
837     local _time="$(cat $ANSWER)"
838     echo "date: $_date time: $_time" >$LOG
839
840     # save the time
841     # DD/MM/YYYY hh:mm:ss -> YYYY-MM-DD hh:mm:ss
842     local _datetime="$(echo "$_date" "$_time" | sed 's#\(..\)/\(..\)/\(....\) \(..\):\(..\):\(..\)#\3-\2-\1 \4:\5:\6#g')"
843     echo "setting date to: $_datetime" >$LOG
844     date -s "$_datetime" 2>&1 >$LOG
845     /sbin/hwclock --systohc $HWCLOCK_PARAMS --noadjfile
846
847     S_CLOCK=1
848 }
849
850 prepare_harddrive()
851 {
852     S_MKFSAUTO=0
853     S_MKFS=0
854     DONE=0
855     local CURRENT_SELECTION=""
856     while [ "$DONE" = "0" ]; do
857         if [ -n "$CURRENT_SELECTION" ]; then
858             DEFAULT="--default-item $CURRENT_SELECTION"
859         else
860             DEFAULT=""
861         fi
862         DIALOG $DEFAULT --menu "Prepare Hard Drive" 12 60 5 \
863             "1" "Auto-Prepare (erases the ENTIRE hard drive)" \
864             "2" "Partition Hard Drives" \
865             "3" "Set Filesystem Mountpoints" \
866             "4" "Return to Main Menu" 2>$ANSWER
867         CURRENT_SELECTION="$(cat $ANSWER)"
868         case $(cat $ANSWER) in
869             "1")
870                 autoprepare ;;
871             "2")
872                 partition ;;
873             "3")
874                 PARTFINISH=""
875                 mountpoints ;;
876             *)
877                 DONE=1 ;;
878         esac
879     done
880 }
881
882 configure_system()
883 {
884     # must mount chroot so pre/post installs don't fail out
885     chroot_mount
886     chroot $DESTDIR /bin/bash <<EOF
887 rc-update del autoconfig default
888 rc-update add keymaps default
889 mv /etc/inittab.old /etc/inittab
890 mv /etc/init.d/halt.sh.orig /etc/init.d/halt.sh
891 EOF
892     # don't need chroot anymore
893     chroot_umount
894
895     # ensure the disk is synced
896     sync
897
898     # automagic time!
899     # any automatic configuration should go here
900     DIALOG --infobox "Writing base configuration..." 6 40
901     auto_fstab
902
903     [ "$EDITOR" ] || geteditor
904
905     local CURRENT_SELECTION=""
906     while true; do
907         if [ -n "$CURRENT_SELECTION" ]; then
908             DEFAULT="--default-item $CURRENT_SELECTION"
909         else
910             DEFAULT=""
911         fi
912         DIALOG $DEFAULT --menu "Configuration" 17 70 10 \
913             "/etc/conf.d/keymaps"        "Keymap" \
914             "/etc/fstab"                "Filesystem Mountpoints" \
915             "/etc/resolv.conf"          "DNS Servers" \
916             "/etc/hosts"                "Network Hosts" \
917             "/etc/locale.gen"           "Glibc Locales" \
918             "Root-Password"             "Set the root password" \
919             "Return"        "Return to Main Menu" 2>$ANSWER || CURRENT_SELECTION="Return"
920         CURRENT_SELECTION="$(cat $ANSWER)"
921
922         if [ "$CURRENT_SELECTION" = "Return" -o -z "$CURRENT_SELECTION" ]; then       # exit
923             break
924         elif [ "$CURRENT_SELECTION" = "Root-Password" ]; then            # non-file
925             while true; do
926                 chroot ${DESTDIR} passwd root && break
927             done
928         else                                                #regular file
929             $EDITOR ${DESTDIR}${CURRENT_SELECTION}
930         fi
931     done
932
933     ## POSTPROCESSING ##
934
935     # /etc/locale.gen
936     #
937     chroot ${DESTDIR} locale-gen
938
939     # /etc/localtime
940     cp /etc/localtime ${DESDIR}/etc/localtime
941
942     ## END POSTPROCESSING ##
943
944     S_CONFIG=1
945 }
946
947 install_bootloader()
948 {
949     DIALOG --colors --menu "Which bootloader would you like to use?  Grub is the Pentoo default.\n\n" \
950         10 65 2 \
951         "GRUB" "Use the GRUB bootloader (default)" \
952         "None" "\Zb\Z1Warning\Z0\ZB: you must install your own bootloader!" 2>$ANSWER
953     case $(cat $ANSWER) in
954         "GRUB") dogrub ;;
955     esac
956 }
957
958 mainmenu()
959 {
960     if [ -n "$CURRENT_SELECTION" ]; then
961         DEFAULT="--default-item $CURRENT_SELECTION"
962     else
963         DEFAULT=""
964     fi
965     DIALOG $DEFAULT --title " MAIN MENU " \
966         --menu "Use the UP and DOWN arrows to navigate menus.  Use TAB to switch between buttons and ENTER to select." 16 55 8 \
967         "0" "Set Clock" \
968         "1" "Prepare Hard Drive" \
969         "2" "Copy the Distribution" \
970         "3" "Configure System" \
971         "4" "Install Bootloader" \
972         "5" "Exit Install" 2>$ANSWER
973     CURRENT_SELECTION="$(cat $ANSWER)"
974     case $(cat $ANSWER) in
975         "0")
976             set_clock ;;
977         "1")
978             prepare_harddrive ;;
979         "2")
980             do_rsync ;;
981         "3")
982             configure_system ;;
983         "4")
984             install_bootloader ;;
985         "5")
986             echo ""
987             echo "If the install finished successfully, you can now type 'reboot'"
988             echo "to restart the system."
989             echo ""
990             exit 0 ;;
991         *)
992             DIALOG --yesno "Abort Installation?" 6 40 && exit 0
993             ;;
994     esac
995 }
996
997 #####################
998 ## begin execution ##
999
1000 DIALOG --msgbox "Welcome to the Pentoo Installation program. The install \
1001 process is fairly straightforward, and you should run through the options in \
1002 the order they are presented. If you are unfamiliar with partitioning/making \
1003 filesystems, you may want to consult some documentation before continuing. \
1004 You can view all output from commands by viewing your VC8 console (ALT-F8). \
1005 ALT-F1 will bring you back here." 14 65
1006
1007 while true; do
1008     mainmenu
1009 done
1010
1011 exit 0
1012
1013 # vim: set ts=4 sw=4 et: