summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorDieter Plaetinck <dieter@plaetinck.be>2009-03-29 18:16:42 +0200
committerDieter Plaetinck <dieter@plaetinck.be>2009-03-29 18:16:42 +0200
commitef2290b0e31c285267bba9dde3634b628df0ebf0 (patch)
treede627bb47c87f535ad7eea5d7b3da9bc2cbef3c7 /src/core
parent71f5510aaaa20ae5ae9c773dca12028bd96aafdf (diff)
parentff1bc0cd6060d0a23911f1ef25633f706a9af619 (diff)
Merge branch 'experimental'2009.03.29
Diffstat (limited to 'src/core')
-rw-r--r--src/core/libs/lib-blockdevices-filesystems.sh155
-rwxr-xr-xsrc/core/libs/lib-flowcontrol.sh216
-rw-r--r--src/core/libs/lib-misc.sh86
-rw-r--r--src/core/libs/lib-network.sh2
-rw-r--r--src/core/libs/lib-pacman.sh29
-rw-r--r--src/core/libs/lib-software.sh29
-rw-r--r--src/core/libs/lib-ui-interactive.sh293
-rw-r--r--src/core/libs/lib-ui.sh300
-rw-r--r--src/core/procedures/automatic116
-rw-r--r--src/core/procedures/base40
-rw-r--r--src/core/procedures/interactive14
-rw-r--r--src/core/procedures/partial-keymap7
-rw-r--r--src/core/procedures/quickinst140
13 files changed, 880 insertions, 547 deletions
diff --git a/src/core/libs/lib-blockdevices-filesystems.sh b/src/core/libs/lib-blockdevices-filesystems.sh
index 3b43541..c1316f0 100644
--- a/src/core/libs/lib-blockdevices-filesystems.sh
+++ b/src/core/libs/lib-blockdevices-filesystems.sh
@@ -3,33 +3,37 @@
# FORMAT DEFINITIONS:
-# MAIN FORMAT FOR $TMP_BLOCKDEVICES (format used to interface with this library): one line per blockdevice, multiple fs'es in 1 'fs-string'
-# $TMP_BLOCKDEVICES entry.
-# <blockdevice> type label/no_label <FS-string>/no_fs
-# FS-string:
-# type;recreate(yes/no);mountpoint;mount?(target,runtime,no);opts;label;params[|FS-string|...] where opts/params have _'s instead of whitespace if needed
-# NOTE: the 'mount?' for now just matters for the location (if 'target', the target path gets prepended and mounted in the runtime system)
-# NOTE: filesystems that span multiple underlying filesystems/devices (eg lvm VG) should specify those in params, separated by colons. \
-# the <blockdevice> in the beginning doesn't matter much, it can be pretty much any device, or not existent, i think. But it's probably best to make it one of the devices listed in params
-# no '+' characters allowed for devices in $fs_params (eg use the real names)
-
-
-# ADDITIONAL INTERNAL FORMAT FOR $TMP_FILESYSTEMS: each filesystem on a separate line, so block devices can appear multiple times be on multiple lines (eg LVM volumegroups with more lvm LV's)
+# -- formats used to interface with this library --
+# $TMP_PARTITIONS
+# one line per partition, blockdevice + partioning string for sfdisk. See docs for function partition for more info.
+# $TMP_BLOCKDEVICES
+# one line per blockdevice, multiple fs'es in 1 'fs-string'
+# $TMP_BLOCKDEVICES entry.
+# <blockdevice> type label/no_label <FS-string>/no_fs
+# FS-string:
+# type;recreate(yes/no);mountpoint;mount?(target,runtime,no);opts;label;params[|FS-string|...] where opts/params have _'s instead of whitespace if needed
+# NOTE: the 'mount?' for now just matters for the location (if 'target', the target path gets prepended and mounted in the runtime system)
+# NOTE: filesystems that span multiple underlying filesystems/devices (eg lvm VG) should specify those in params, separated by colons. \
+# the <blockdevice> in the beginning doesn't matter much, it can be pretty much any device, or not existent, i think. But it's probably best to make it one of the devices listed in params
+# no '+' characters allowed for devices in $fs_params (eg use the real names)
+
+
+# -- ADDITIONAL INTERNAL FORMATS --
+# $TMP_FILESYSTEMS: each filesystem on a separate line, so block devices can appear multiple times be on multiple lines (eg LVM volumegroups with more lvm LV's)
# part part_type part_label fs_type fs_create fs_mountpoint fs_mount fs_opts fs_label fs_params
-#TODO: this should be fixed on the installcd.
-modprobe dm-crypt || show_warning modprobe 'Could not modprobe dm-crypt. no support for disk encryption'
-modprobe aes-i586 || show_warning modprobe 'Could not modprobe aes-i586. no support for disk encryption'
+modprobe -q dm-crypt || show_warning modprobe 'Could not modprobe dm-crypt. no support for disk encryption'
+modprobe -q aes-i586 || modprobe -q aes-x86-64 || show_warning modprobe 'Could not modprobe aes-i586 or aes-x86-64. no support for disk encryption'
-TMP_DEV_MAP=$RUNTIME_DIR/dev.map
-TMP_FSTAB=$RUNTIME_DIR/.fstab
-TMP_PARTITIONS=$RUNTIME_DIR/.partitions
-TMP_FILESYSTEMS=$RUNTIME_DIR/.filesystems # Only used internally by this library. Do not even think about using this as interface to this library. it won't work
-TMP_BLOCKDEVICES=$RUNTIME_DIR/.blockdata
+TMP_DEV_MAP=$RUNTIME_DIR/aif-dev.map
+TMP_FSTAB=$RUNTIME_DIR/aif-fstab
+TMP_PARTITIONS=$RUNTIME_DIR/aif-partitions
+TMP_FILESYSTEMS=$RUNTIME_DIR/aif-filesystems # Only used internally by this library. Do not even think about using this as interface to this library. it won't work
+TMP_BLOCKDEVICES=$RUNTIME_DIR/aif-blockdata
@@ -271,10 +275,10 @@ target_configure_fstab()
# partitions a disk. heavily altered
# $1 device to partition
-# $2 a string of the form: <partsize>:<fstype>[:+] (the + is bootable flag)
+# $2 a string of the form: <partsize in MiB>:<fstype>[:+] (the + is bootable flag)
partition()
{
- debug "Partition called like: partition '$1' '$2'"
+ debug 'FS' "Partition called like: partition '$1' '$2'"
[ -z "$1" ] && die_error "partition() requires a device file and a partition string"
[ -z "$2" ] && die_error "partition() requires a partition string"
@@ -313,7 +317,7 @@ partition()
sfdisk_input=$(printf "$sfdisk_input") # convert \n to newlines
# invoke sfdisk
- debug "Partition calls: sfdisk $DEVICE -uM >$LOG 2>&1 <<< $sfdisk_input"
+ debug 'FS' "Partition calls: sfdisk $DEVICE -uM >$LOG 2>&1 <<< $sfdisk_input"
printk off
sfdisk $DEVICE -uM >$LOG 2>&1 <<EOF
$sfdisk_input
@@ -329,10 +333,6 @@ EOF
}
-# file layout:
-#TMP_PARTITIONS
-# disk partition-scheme
-
# go over each disk in $TMP_PARTITIONS and partition it
process_disks ()
{
@@ -349,6 +349,19 @@ process_disk ()
partition $1 "$2"
}
+# $1 fs_string
+parse_filesystem_string ()
+{
+ fs="$1"
+ fs_type=` cut -d ';' -f 1 <<< $fs`
+ fs_create=` cut -d ';' -f 2 <<< $fs`
+ fs_mountpoint=` cut -d ';' -f 3 <<< $fs`
+ fs_mount=` cut -d ';' -f 4 <<< $fs`
+ fs_opts=` cut -d ';' -f 5 <<< $fs`
+ fs_label=` cut -d ';' -f 6 <<< $fs`
+ fs_params=` cut -d ';' -f 7 <<< $fs`
+}
+
generate_filesystem_list ()
{
@@ -359,13 +372,7 @@ generate_filesystem_list ()
then
for fs in `sed 's/|/ /g' <<< $fs_string` # this splits multiple fs'es up, or just takes the one if there is only one (lvm vg's can have more then one lv)
do
- fs_type=` cut -d ';' -f 1 <<< $fs`
- fs_create=` cut -d ';' -f 2 <<< $fs`
- fs_mountpoint=` cut -d ';' -f 3 <<< $fs`
- fs_mount=` cut -d ';' -f 4 <<< $fs`
- fs_opts=` cut -d ';' -f 5 <<< $fs`
- fs_label=` cut -d ';' -f 6 <<< $fs`
- fs_params=` cut -d ';' -f 7 <<< $fs`
+ parse_filesystem_string "$fs"
echo "$part $part_type $part_label $fs_type $fs_create $fs_mountpoint $fs_mount $fs_opts $fs_label $fs_params" >> $TMP_FILESYSTEMS
done
fi
@@ -377,7 +384,7 @@ generate_filesystem_list ()
# process all entries in $TMP_BLOCKDEVICES, create all blockdevices and filesystems and mount them correctly
process_filesystems ()
{
- debug "process_filesystems Called. checking all entries in $TMP_BLOCKDEVICES"
+ debug 'FS' "process_filesystems Called. checking all entries in $TMP_BLOCKDEVICES"
rm -f $TMP_FSTAB
generate_filesystem_list
returncode=0
@@ -397,26 +404,26 @@ process_filesystems ()
then
if check_is_in "$fs_id" "${done_filesystems[@]}"
then
- debug "$fs_id ->Already done"
+ debug 'FS' "$fs_id ->Already done"
else
# We can't always do -b on the lvm VG. because the devicefile sometimes doesn't exist for a VG. vgdisplay to the rescue!
if [ "$part_type" = lvm-vg ] && vgdisplay $part | grep -q 'VG Name' # $part is a lvm VG and it exists. note that vgdisplay exists 0 when the requested vg doesn't exist.
then
- debug "$fs_id ->Still need to do it: Making the filesystem on a vg volume"
+ debug 'FS' "$fs_id ->Still need to do it: Making the filesystem on a vg volume"
infofy "Making $fs_type filesystem on $part" disks
process_filesystem $part $fs_type $fs_create $fs_mountpoint no_mount $fs_opts $fs_label $fs_params && done_filesystems+=("$fs_id") || returncode=1
elif [ "$part_type" != lvm-pv -a -b "$part" ] # $part is not a lvm PV and it exists
then
- debug "$fs_id ->Still need to do it: Making the filesystem on a non-pv volume"
+ debug 'FS' "$fs_id ->Still need to do it: Making the filesystem on a non-pv volume"
infofy "Making $fs_type filesystem on $part" disks
process_filesystem $part $fs_type $fs_create $fs_mountpoint no_mount $fs_opts $fs_label $fs_params && done_filesystems+=("$fs_id") || returncode=1
elif [ "$part_type" = lvm-pv ] && pvdisplay ${fs_params//:/ } >/dev/null # $part is a lvm PV. all needed lvm pv's exist. note that pvdisplay exits 5 as long as one of the args doesn't exist
then
- debug "$fs_id ->Still need to do it: Making the filesystem on a pv volume"
+ debug 'FS' "$fs_id ->Still need to do it: Making the filesystem on a pv volume"
infofy "Making $fs_type filesystem on $part" disks
process_filesystem ${part/+/} $fs_type $fs_create $fs_mountpoint no_mount $fs_opts $fs_label $fs_params && done_filesystems+=("$fs_id") || returncode=1
else
- debug "$fs_id ->Cannot do right now..."
+ debug 'FS' "$fs_id ->Cannot do right now..."
open_items=1
fi
fi
@@ -431,7 +438,7 @@ process_filesystems ()
# phase 2: mount all filesystems in the vfs in the correct order. (also swapon where appropriate)
infofy "Phase 2: Mounting filesystems" disks
- sort -t \ -k 6 $TMP_FILESYSTEMS | while read part part_type part_label fs_type fs_create fs_mountpoint fs_mount fs_opts fs_label fs_params
+ while read part part_type part_label fs_type fs_create fs_mountpoint fs_mount fs_opts fs_label fs_params
do
if [ "$fs_mountpoint" != no_mountpoint ]
then
@@ -442,7 +449,7 @@ process_filesystems ()
infofy "Swaponning $part" disks
process_filesystem $part $fs_type no $fs_mountpoint $fs_mount $fs_opts $fs_label $fs_params || returncode=1
fi
- done
+ done < <(sort -t \ -k 6 $TMP_FILESYSTEMS)
BLOCK_ROLLBACK_USELESS=0
[ $returncode -eq 0 ] && infofy "Done processing filesystems/blockdevices" disks 1 && return 0
@@ -463,7 +470,7 @@ rollback_filesystems ()
infofy "Phase 1: Umounting all specified mountpoints" disks
done_umounts= # We translate some devices back to their original (eg /dev/sda3+ -> /dev/sda3 for lvm PV's). No need to bother user twice for such devices.
- sort -t \ -k 6 $TMP_FILESYSTEMS | tac | while read part part_type part_label fs_type fs_create fs_mountpoint fs_mount fs_opts fs_label fs_params
+ while read part part_type part_label fs_type fs_create fs_mountpoint fs_mount fs_opts fs_label fs_params
do
if [ "$fs_type" = swap ]
then
@@ -487,7 +494,7 @@ rollback_filesystems ()
fi
fi
fi
- done
+ done < <(sort -t \ -k 6 $TMP_FILESYSTEMS | tac)
# phase 2: destruct blockdevices listed in $BLOCK_DATA if they would exist already, in the correct order (first lvm LV, then VG, then PV etc)
@@ -512,7 +519,7 @@ rollback_filesystems ()
then
if pvdisplay $real_part &>/dev/null
then
- debug "$part ->Cannot do right now..."
+ debug 'FS' "$part ->Cannot do right now..."
open_items=1
else
infofy "Attempting destruction of device $part (type $part_type)" disks
@@ -523,7 +530,7 @@ rollback_filesystems ()
fi
fi
else
- debug "Skipping destruction of device $part (type $part_type) because it doesn't exist"
+ debug 'FS' "Skipping destruction of device $part (type $part_type) because it doesn't exist"
fi
elif [ "$part_type" = lvm-pv ] # Can be in use for: lvm-vg
then
@@ -531,7 +538,7 @@ rollback_filesystems ()
then
if vgdisplay -v 2>/dev/null | grep -q $real_part # check if it's in use
then
- debug "$part ->Cannot do right now..."
+ debug 'FS' "$part ->Cannot do right now..."
open_items=1
else
infofy "Attempting destruction of device $part (type $part_type)" disks
@@ -542,7 +549,7 @@ rollback_filesystems ()
fi
fi
else
- debug "Skipping destruction of device $part (type $part_type) because it doesn't exist"
+ debug 'FS' "Skipping destruction of device $part (type $part_type) because it doesn't exist"
fi
elif [ "$part_type" = lvm-vg ] #Can be in use for: lvm-lv
then
@@ -551,7 +558,7 @@ rollback_filesystems ()
open_lv=`vgdisplay -c $part 2>/dev/null | cut -d ':' -f6`
if [ $open_lv -gt 0 ]
then
- debug "$part ->Cannot do right now..."
+ debug 'FS' "$part ->Cannot do right now..."
open_items=1
else
infofy "Attempting destruction of device $part (type $part_type)" disks
@@ -562,7 +569,7 @@ rollback_filesystems ()
fi
fi
else
- debug "Skipping destruction of device $part (type $part_type) because it doesn't exist"
+ debug 'FS' "Skipping destruction of device $part (type $part_type) because it doesn't exist"
fi
elif [ "$part_type" = lvm-lv ] #Can be in use for: dm_crypt or raw. we don't need to care about raw (it will be unmounted so it can be destroyed)
then
@@ -570,7 +577,7 @@ rollback_filesystems ()
then
if cryptsetup isLuks $part &>/dev/null
then
- debug "$part ->Cannot do right now..."
+ debug 'FS' "$part ->Cannot do right now..."
open_items=1
else
infofy "Attempting destruction of device $part (type $part_type)" disks
@@ -581,7 +588,7 @@ rollback_filesystems ()
fi
fi
else
- debug "Skipping destruction of device $part (type $part_type) because it doesn't exist"
+ debug 'FS' "Skipping destruction of device $part (type $part_type) because it doesn't exist"
fi
else
die_error "Unrecognised partition type $part_type for partition $part. This should never happen. please report this"
@@ -597,6 +604,7 @@ rollback_filesystems ()
fi
[ -n "$warnings" ] && infofy "Rollback failed" disks 1 && show_warning "Rollback problems" "Some problems occurred while rolling back: $warnings.\n Thisk needs to be fixed before retrying disk/filesystem creation or restarting the installer" && return 1
infofy "Rollback succeeded" disks 1
+ done_filesystems=
BLOCK_ROLLBACK_USELESS=1
return 0
}
@@ -616,7 +624,7 @@ process_filesystem ()
{
[ "$2" != lvm-lv ] && [ -z "$1" -o ! -b "$1" ] && die_error "process_filesystem needs a partition as \$1" # Don't do this for lv's. It's a hack to workaround non-existence of VG device files.
[ -z "$2" ] && die_error "process_filesystem needs a filesystem type as \$2"
- debug "process_filesystem $@"
+ debug 'FS' "process_filesystem $@"
part=$1
fs_type=$2
fs_create=${3:-yes}
@@ -674,16 +682,17 @@ process_filesystem ()
BLOCK_ROLLBACK_USELESS=0
if [ "$fs_type" = swap ]
then
- debug "swaponning $part"
+ debug 'FS' "swaponning $part"
swapon $part >$LOG 2>&1 || ( show_warning 'Swapon' "Error activating swap: swapon $part" ; return 1 )
else
[ "$fs_mount" = runtime ] && dst=$fs_mountpoint
[ "$fs_mount" = target ] && dst=$var_TARGET_DIR$fs_mountpoint
- debug "mounting $part on $dst"
+ debug 'FS' "mounting $part on $dst"
mkdir -p $dst &>/dev/null # directories may or may not already exist
mount -t $fs_type $part $dst >$LOG 2>&1 || ( show_warning 'Mount' "Error mounting $part on $dst" ; return 1 )
if [ "$fs_mount" = target -a $fs_mountpoint = '/' ]
then
+ debug FS "setting \$PART_ROOT to $part"
PART_ROOT=$part
fi
fi
@@ -736,24 +745,30 @@ get_filesystem_program ()
# $1 blockdevice
-# $2 standard SI for 1000*n, IEC for 1024*n (optional. defaults to SI)
-# --> Note that if you do SI on a partition, you get the size of the entire disk, so for now you need IEC for single partitions
-# output will be in $BLOCKDEVICE_SIZE in MB/MiB
-# WARNING: hdparm works - by design - only for ide/sata. not scsi et al
-# TODO: clean up all disk size related stuff. see http://bugs.archlinux.org/task/12949
+# $2 unit: B, KiB, kB, MiB, MB, GiB or GB. defaults to B (we follow IEEE 1541-2002 )
+# output will be in $BLOCKDEVICE_SIZE
get_blockdevice_size ()
{
[ -b "$1" ] || die_error "get_blockdevice_size needs a blockdevice as \$1 ($1 given)"
- standard=${2:-SI}
-
- if [ "$standard" = SI ]
+ unit=${2:-B}
+ allowed_units=(B KiB kB MiB MB GiB GB)
+ if ! check_is_in $unit "${allowed_units[@]}"
then
- BLOCKDEVICE_SIZE=$(hdparm -I $1 | grep -F '1000*1000' | sed "s/^.*:[ \t]*\([0-9]*\) MBytes.*$/\1/")
- elif [ "$standard" = IEC ]
- then
- #NOTE: unreliable method: on some interwebs they say 1 block = 512B, on other internets they say 1 block = 1kiB. 1kiB seems to work for me. don't sue me if it doesn't for you
- #blocks=`fdisk -s $1` || show_warning "Fdisk problem" "Something failed when trying to do fdisk -s $1"
- #BLOCKDEVICE_SIZE=$(($blocks/1024))
- BLOCKDEVICE_SIZE=$((`fdisk -l $1 | sed -n '2p' | cut -d' ' -f5`/1024))
+ die_error "Unrecognized unit $unit!"
fi
+
+ # NOTES about older, deprecated methods:
+ # - BLOCKDEVICE_SIZE=$(hdparm -I $1 | grep -F '1000*1000' | sed "s/^.*:[ \t]*\([0-9]*\) MBytes.*$/\1/") # if you do this on a partition, you get the size of the entire disk ! + hdparm only supports sata and ide. not scsi.
+ # - unreliable method: on some interwebs they say 1 block = 512B, on other internets they say 1 block = 1kiB. 1kiB seemed to work for me.
+ # blocks=`fdisk -s $1` || show_warning "Fdisk problem" "Something failed when trying to do fdisk -s $1"
+ # BLOCKDEVICE_SIZE=$(($blocks/1024))
+
+ bytes=$((`fdisk -l $1 2>/dev/null | sed -n '2p' | cut -d' ' -f5`))
+ [ $unit = B ] && BLOCKDEVICE_SIZE=$bytes
+ [ $unit = KiB ] && BLOCKDEVICE_SIZE=$((bytes/2**10)) # /1024
+ [ $unit = kB ] && BLOCKDEVICE_SIZE=$((bytes/10**3)) # /1000
+ [ $unit = MiB ] && BLOCKDEVICE_SIZE=$((bytes/2**20)) # ...
+ [ $unit = MB ] && BLOCKDEVICE_SIZE=$((bytes/10**6))
+ [ $unit = GiB ] && BLOCKDEVICE_SIZE=$((bytes/2**30))
+ [ $unit = GB ] && BLOCKDEVICE_SIZE=$((bytes/10**9))
}
diff --git a/src/core/libs/lib-flowcontrol.sh b/src/core/libs/lib-flowcontrol.sh
new file mode 100755
index 0000000..8106310
--- /dev/null
+++ b/src/core/libs/lib-flowcontrol.sh
@@ -0,0 +1,216 @@
+#!/bin/bash
+
+usage ()
+{
+ msg="aif -p <procedurename> Select a procedure # If given, this *must* be the first option
+ -i <dia/cli> Override interface type (optional)
+ -d Explicitly enable debugging (optional)
+ -l Explicitly enable logging to file (optional)
+ -h Help: show usage (optional)\n
+If the procedurename starts with 'http://' it will be wget'ed. Otherwise it's assumed to be a procedure in the VFS tree
+If the procedurename is prefixed with '<modulename>/' it will be loaded from user module <modulename>.\n
+For more info, see the README which you can find in /usr/share/aif/docs\n
+Available procedures:
+==core==
+`find $LIB_CORE/procedures -type f | sed \"s#$LIB_CORE/procedures/##\" | sort`
+==user==
+`find $LIB_USER/*/procedures -type f 2>/dev/null | sed \"s#$LIB_USER/\(.*\)/procedures/#\1/#\" | sort`"
+ [ -n "$procedure" ] && msg="$msg\nProcedure ($procedure) specific options:\n$var_ARGS_USAGE"
+
+ echo -e "$msg"
+}
+
+
+# $1 module name
+load_module ()
+{
+ [ -z "$1" ] && die_error "load_module needs a module argument"
+ log "Loading module $1 ..."
+ path=$LIB_USER/"$1"
+ [ "$1" = core ] && path=$LIB_CORE
+
+ for submodule in lib #procedure don't load procedures automatically!
+ do
+ if [ ! -d "$path/${submodule}s" ]
+ then
+ # ignore this problem for not-core modules
+ [ "$1" = core ] && die_error "$path/${submodule}s does not exist. something is horribly wrong with this installation"
+ else
+ shopt -s nullglob
+ for i in "$path/${submodule}s"/*
+ do
+ # I have the habit of editing files while testing, don't source my backup files!
+ [[ "$i" == *~ ]] && continue
+
+ load_${submodule} "$1" "`basename "$i"`"
+ done
+ fi
+ done
+
+}
+
+
+# $1 module name
+# $2 procedure name
+load_procedure()
+{
+ [ -z "$1" ] && die_error "load_procedure needs a module as \$1 and procedure as \$2"
+ [ -z "$2" ] && die_error "load_procedure needs a procedure as \$2"
+ if [ "$1" = 'http:' ]
+ then
+ log "Loading procedure $2 ..."
+ procedure=$RUNTIME_DIR/aif-procedure-downloaded-`basename $2`
+ wget "$2" -q -O $procedure >/dev/null || die_error "Could not download procedure $2"
+ else
+ log "Loading procedure $1/procedures/$2 ..."
+ procedure=$LIB_USER/"$1"/procedures/"$2"
+ [ "$1" = core ] && procedure=$LIB_CORE/procedures/"$2"
+ fi
+ [ -f "$procedure" ] && source "$procedure" || die_error "Something went wrong while sourcing procedure $procedure"
+}
+
+
+# $1 module name
+# $2 library name
+load_lib ()
+{
+ [ -z "$1" ] && die_error "load_library needs a module als \$1 and library as \$2"
+ [ -z "$2" ] && die_error "load_library needs a library as \$2"
+ log "Loading library $1/libs/$2 ..."
+ lib=$LIB_USER/"$1"/libs/"$2"
+ [ "$1" = core ] && lib=$LIB_CORE/libs/"$2"
+ source $lib || die_error "Something went wrong while sourcing library $lib"
+}
+
+
+# $1 phase/worker
+# $2 phase/worker name
+# $3... extra args for phase/worker (optional)
+execute ()
+{
+ [ -z "$1" -o -z "$2" ] && debug 'MAIN' "execute $@" && die_error "Use the execute function like this: execute <type> <name> with type=phase/worker"
+ [ "$1" != phase -a "$1" != worker ] && debug 'MAIN' "execute $@" && die_error "execute's first argument must be a valid type (phase/worker)"
+ PWD_BACKUP=`pwd`
+ object=$1_$2
+
+ if [ "$1" = worker ]
+ then
+ log "*** Executing worker $2"
+ if type -t $object | grep -q function
+ then
+ shift 2
+ $object "$@"
+ ret=$?
+ exit_var=exit_$object
+ read $exit_var <<< $ret # maintain exit status of each worker
+ else
+ die_error "$object is not defined!"
+ fi
+ elif [ "$1" = phase ]
+ then
+ log "******* Executing phase $2"
+ exit_var=exit_$object
+ read $exit_var <<< 0
+ # TODO: for some reason the hack below does not work (tested in virtualbox), even though it really should. Someday I must get indirect array variables working and clean this up...
+ # debug 'MAIN' "\$1: $1, \$2: $2, \$object: $object, \$exit_$object: $exit_object"
+ # debug 'MAIN' "declare: `declare | grep -e "^${object}=" | cut -d"=" -f 2-`"
+ # props to jedinerd at #bash for this hack.
+ # eval phase=$(declare | grep -e "^${object}=" | cut -d"=" -f 2-)
+ #debug 'MAIN' "\$phase: $phase - ${phase[@]}"
+ unset phase
+ [ "$2" = preparation ] && phase=( "${phase_preparation[@]}" )
+ [ "$2" = basics ] && phase=( "${phase_basics[@]}" )
+ [ "$2" = system ] && phase=( "${phase_system[@]}" )
+ [ "$2" = finish ] && phase=( "${phase_finish[@]}" )
+ # worker_str contains the name of the worker and optionally any arguments
+ for worker_str in "${phase[@]}"
+ do
+ debug 'MAIN' "Loop iteration. \$worker_str: $worker_str"
+ execute worker $worker_str || read $exit_var <<< $? # assign last failing exit code to exit_phase_<phasename>, if any.
+ done
+ ret=${!exit_var}
+ fi
+
+ debug 'MAIN' "Execute(): $object exit state was $ret"
+ cd $PWD_BACKUP
+ return $ret
+}
+
+
+# check if a phase/worker executed sucessfully
+# returns 0 if ok, the phase/workers' exit state otherwise (and returns 1 if not executed yet)
+# $1 phase/worker
+# $2 phase/worker name
+ended_ok ()
+{
+ [ -z "$1" -o -z "$2" ] && die_error "Use the ended_ok function like this: ended_ok <type> <name> with type=phase/worker"
+ [ "$1" != phase -a "$1" != worker ] && die_error "ended_ok's first argument must be a valid type (phase/worker)"
+ object=$1_$2
+ exit_var=exit_$object
+ debug 'MAIN' "Ended_ok? -> Exit state of $object was: ${!exit_var} (if empty. it's not executed yet)"
+ [ "${!exit_var}" = '0' ] && return 0
+ [ "${!exit_var}" = '' ] && return 1
+ return ${!exit_var}
+}
+
+
+depend_module ()
+{
+ load_module "$1"
+}
+
+
+depend_procedure ()
+{
+ load_procedure "$1" "$2"
+}
+
+
+start_process ()
+{
+ execute phase preparation
+ execute phase basics
+ execute phase system
+ execute phase finish
+}
+
+
+show_report () #TODO: abstract UI method (cli/dia)
+{
+ echo "Execution Report:"
+ echo "-----------------"
+ for phase in preparation basics system finish
+ do
+ object=phase_$phase
+ exit_var=exit_$object
+ ret=${!exit_var}
+ echo -n "Phase $phase: "
+ [ "$ret" = "0" ] && echo "Success" || echo "Failed"
+ eval phase_array=$(declare | grep -e "^${object}=" | cut -d"=" -f 2-)
+ for worker_str in "${phase_array[@]}"
+ do
+ worker=${worker_str%% *}
+ exit_var=exit_worker_$worker
+ ret=${!exit_var}
+ echo -n " > Worker $worker: "
+ [ "$ret" = "0" ] && echo "Success" || echo "Failed"
+ done
+ done
+}
+
+
+start_installer ()
+{
+ log "################## START OF INSTALLATION ##################"
+ cleanup_runtime
+}
+
+
+# use this function to stop the installation procedure.
+# $1 exit code (optional)
+stop_installer ()
+{
+ log "-------------- STOPPING INSTALLATION ----------"
+ cleanup_runtime
+ exit $1
+}
diff --git a/src/core/libs/lib-misc.sh b/src/core/libs/lib-misc.sh
index 01c291f..1acebac 100644
--- a/src/core/libs/lib-misc.sh
+++ b/src/core/libs/lib-misc.sh
@@ -1,9 +1,38 @@
#!/bin/bash
+# runs a process and makes sure the output is shown to the user. sets the exit state of the executed program ($<identifier>_exitcode) so the caller can show a concluding message.
+# when in dia mode, we will run the program and a dialog instance in the background (cause that's just how it works with dia)
+# when in cli mode, the program will just run in the foreground. technically it can be run backgrounded but then we need tail -f (cli_follow_progress), and we miss the beginning of the output if it goes too fast, not to mention because of the sleep in run_background
+# $1 identifier
+# $2 command (will be eval'ed)
+# $3 logfile
+# $4 title to show while process is running
+run_controlled ()
+{
+ [ -z "$1" ] && die_error "run_controlled: please specify an identifier to keep track of the command!"
+ [ -z "$2" ] && die_error "run_controlled needs a command to execute!"
+ [ -z "$3" ] && die_error "run_controlled needs a logfile to redirect output to!"
+ [ -z "$4" ] && die_error "run_controlled needs a title to show while your process is running!"
+
+ if [ "$var_UI_TYPE" = dia ]
+ then
+ run_background $1 "$2" $3
+ follow_progress " $4 " $3 $BACKGROUND_PID # dia mode ignores the pid. cli uses it to know how long it must do tail -f
+ wait_for $1 $FOLLOW_PID
+ else
+ notify "$4"
+ var_exit=${1}_exitcode
+ eval "$2" >>$3 2>&1
+ read $var_exit <<< $?
+ fi
+}
+
+
# run a process in the background, and log it's stdout and stderr to a specific logfile
# returncode is stored in $<identifier>_exitcode
-# $1 identifier
+# pid of the backgrounded wrapper process is stored in BACKGROUND_PID (this is _not_ the pid of $2)
+# $1 identifier -> WARNING: do never ever use -'s or other fancy characters here. only numbers, letters and _ please. (because $<identifier>_exitcode must be a valid bash variable!)
# $2 command (will be eval'ed)
# $3 logfile
run_background ()
@@ -12,47 +41,50 @@ run_background ()
[ -z "$2" ] && die_error "run_background needs a command to execute!"
[ -z "$3" ] && die_error "run_background needs a logfile to redirect output to!"
- debug "run_background called. identifier: $1, command: $2, logfile: $3"
+ debug 'MISC' "run_background called. identifier: $1, command: $2, logfile: $3"
( \
- touch $RUNTIME_DIR/.$1-running
- debug "run_background starting $1: $2 >>$3 2>&1"
+ touch $RUNTIME_DIR/aif-$1-running
+ debug 'MISC' "run_background starting $1: $2 >>$3 2>&1"
[ -f $3 ] && echo -e "\n\n\n" >>$3
echo "STARTING $1 . Executing $2 >>$3 2>&1\n" >> $3;
var_exit=${1}_exitcode
eval "$2" >>$3 2>&1
- read $var_exit <<< $? #TODO: bash complains about 'not a valid identifier'
- debug "run_background done with $1: exitcode (\$$1_exitcode): "${!var_exit}" .Logfile $3" #TODO ${!var_exit} doesn't show anything --> maybe fixed now
+ read $var_exit <<< $?
+ debug 'MISC' "run_background done with $1: exitcode (\$$1_exitcode): ${!var_exit} .Logfile $3"
echo >> $3
- rm -f $RUNTIME_DIR/.$1-running
+ rm -f $RUNTIME_DIR/aif-$1-running
) &
+ BACKGROUND_PID=$!
sleep 2
}
# wait until a process is done
-# $1 identifier
+# $1 identifier. WARNING! see above
+# $2 pid of a process to kill when done (optional). useful for dialog --no-kill --tailboxbg's pid.
wait_for ()
{
[ -z "$1" ] && die_error "wait_for needs an identifier to known on which command to wait!"
- while [ -f $RUNTIME_DIR/.$1-running ]
+ while [ -f $RUNTIME_DIR/aif-$1-running ]
do
- #TODO: follow_progress dialog mode = nonblocking (so check and sleep is good), cli mode (tail -f )= blocking? (so check is probably not needed as it will be done)
sleep 1
done
- kill $(cat $ANSWER) #TODO: this may not work when mode = cli
+ [ -n "$2" ] && kill $2
}
-# $1 set (array) haystack
-# $2 needle
+# $1 needle
+# $2 set (array) haystack
check_is_in ()
{
- [ -z "$1" ] && debug "check_is_in $1 $2" && die_error "check_is_in needs a non-empty needle as \$2 and a haystack as \$1!" # haystack can be empty though
+ [ -z "$1" ] && die_error "check_is_in needs a non-empty needle as \$1 and a haystack as \$2!(got: check_is_in '$1' '$2'" # haystack can be empty though
+ NEEDLE=$1
+ HAYSTACK=$2
- local pattern="$1" element
+ local pattern="$NEEDLE" element
shift
for element
do
@@ -66,5 +98,27 @@ check_is_in ()
cleanup_runtime ()
{
mkdir -p $RUNTIME_DIR || die_error "Cannot create $RUNTIME_DIR"
- rm -rf $RUNTIME_DIR/.dia* &>/dev/null
+ rm -rf $RUNTIME_DIR/aif-dia* &>/dev/null
+}
+
+
+dohwclock() {
+ infofy "Syncing hardwareclock to systemclock ..."
+ if [ "$HARDWARECLOCK" = "UTC" ]; then
+ HWCLOCK_PARAMS="$HWCLOCK_PARAMS --utc"
+ else
+ HWCLOCK_PARAMS="$HWCLOCK_PARAMS --localtime"
+ fi
+
+ [ ! -d /var/lib/hwclock ] && mkdir -p /var/lib/hwclock
+ if [ ! -f /var/lib/hwclock/adjtime ]; then
+ echo "0.0 0 0.0" > /var/lib/hwclock/adjtime # what the hell is this for???
+ fi
+ hwclock $HWCLOCK_PARAMS #tpowa does it without, but i would add --noadjtime here
}
+
+target_configure_initial_keymap_font ()
+{
+ [ -n "$var_KEYMAP" ] && sed -i "s/^KEYMAP=.*/KEYMAP=\"$var_KEYMAP\"/" ${var_TARGET_DIR}/etc/rc.conf
+ [ -n "$var_CONSOLEFONT" ] && sed -i "s/^CONSOLEFONT=.*/CONSOLEFONT=\"$var_CONSOLEFONT\"/" ${var_TARGET_DIR}/etc/rc.conf
+} \ No newline at end of file
diff --git a/src/core/libs/lib-network.sh b/src/core/libs/lib-network.sh
index 9ed96b2..85e597c 100644
--- a/src/core/libs/lib-network.sh
+++ b/src/core/libs/lib-network.sh
@@ -17,7 +17,6 @@ target_configure_network()
sed -i "s#$INTERFACE 192.168.0.2#$INTERFACE $IPADDR#g" ${var_TARGET_DIR}/etc/rc.conf
sed -i "s#netmask 255.255.255.0#netmask $SUBNET#g" ${var_TARGET_DIR}/etc/rc.conf
sed -i "s#broadcast 192.168.0.255#broadcast $BROADCAST#g" ${var_TARGET_DIR}/etc/rc.conf
- sed -i "s#INTERFACES=(eth0)#INTERFACES=($INTERFACE)#g" ${var_TARGET_DIR}/etc/rc.conf
if [ "$GW" != "" ]; then
sed -i "s#gw 192.168.0.1#gw $GW#g" ${var_TARGET_DIR}/etc/rc.conf
sed -i "s#!gateway#gateway#g" ${var_TARGET_DIR}/etc/rc.conf
@@ -26,6 +25,7 @@ target_configure_network()
else
sed -i "s#eth0=\"eth0.*#$INTERFACE=\"dhcp\"#g" ${var_TARGET_DIR}/etc/rc.conf
fi
+ sed -i "s#INTERFACES=(eth0)#INTERFACES=($INTERFACE)#g" ${var_TARGET_DIR}/etc/rc.conf
if [ "$PROXY_HTTP" != "" ]; then
echo "export http_proxy=$PROXY_HTTP" >> ${var_TARGET_DIR}/etc/profile.d/proxy.sh;
diff --git a/src/core/libs/lib-pacman.sh b/src/core/libs/lib-pacman.sh
index 4497074..a104cee 100644
--- a/src/core/libs/lib-pacman.sh
+++ b/src/core/libs/lib-pacman.sh
@@ -78,7 +78,7 @@ do
then
add_pacman_repo target ${repo} "Include = $var_MIRRORLIST"
else
- add_pacman_repo target ${repo} "Server = ${serverurl/\/\$repo\//\/$repo\/}" # replace literal '/$repo/' in the serverurl string by "/$repo/" where $repo is our variable.
+ add_pacman_repo target ${repo} "Server = ${serverurl/\$repo/$repo}" # replace literal '$repo' in the serverurl string by "$repo" where $repo is our variable.
fi
done
# Set up the necessary directories for pacman use
@@ -132,3 +132,30 @@ pacman_what_is_this_for ()
! [ -d /var/lib/pacman ] && mkdir -p /var/lib/pacman
}
+list_package_groups ()
+{
+ $PACMAN_TARGET -Sg
+}
+
+
+# List the packages in one or more repos or groups. output is one or more lines, each line being like this:
+# <repo/group name> packagename [version, if $1=repo]
+# $1 repo or group
+# $2 one or more repo or group names
+# TODO: check the validity of the specified names in $2
+list_packages ()
+{
+ [ "$1" = repo -o "$1" = group ] || die_error "list_packages \$1 must be repo or group. not $1!"
+ [ "$1" = repo ] && $PACMAN_TARGET -Sl $2
+ [ "$1" = group ] && $PACMAN_TARGET -Sg $2
+}
+
+# find out the group to which one or more packages belong
+# $1 packages separated by spaces
+# output format: multiple lines, each line like:
+# <pkgname> <group>
+# TODO: check $1
+which_group ()
+{
+ PACKAGE_GROUPS=`$PACMAN_TARGET -Si $1| awk '/^Name/{ printf("%s ",$3) } /^Group/{ print $3 }'`
+}
diff --git a/src/core/libs/lib-software.sh b/src/core/libs/lib-software.sh
index 726d20f..384cab4 100644
--- a/src/core/libs/lib-software.sh
+++ b/src/core/libs/lib-software.sh
@@ -1,7 +1,7 @@
#!/bin/bash
-TMP_MKINITCPIO_LOG=$RUNTIME_DIR/mkinitcpio.log
-TMP_PACMAN_LOG=$RUNTIME_DIR/pacman.log
+TMP_MKINITCPIO_LOG=$LOG_DIR/mkinitcpio.log
+TMP_PACMAN_LOG=$LOG_DIR/pacman.log
# run_mkinitcpio() taken from setup. adapted a lot
# runs mkinitcpio on the target system, displays output
@@ -9,9 +9,7 @@ run_mkinitcpio()
{
target_special_fs on
- run_background mkinitcpio "chroot $var_TARGET_DIR /sbin/mkinitcpio -p kernel26" $TMP_MKINITCPIO_LOG
- follow_progress "Rebuilding initcpio images ..." $TMP_MKINITCPIO_LOG
- wait_for mkinitcpio
+ run_controlled mkinitcpio "chroot $var_TARGET_DIR /sbin/mkinitcpio -p kernel26" $TMP_MKINITCPIO_LOG "Rebuilding initcpio images ..."
target_special_fs off
@@ -24,16 +22,20 @@ run_mkinitcpio()
# installpkg(). taken from setup. modified bigtime
# performs package installation to the target system
installpkg() {
- notify "Package installation will begin now. You can watch the output in the progress window. Please be patient."
+ ALL_PACKAGES=$var_TARGET_PACKAGES
+ [ -n "$TARGET_GROUPS" ] && ALL_PACKAGES="$ALL_PACKAGES "`list_packages group "$TARGET_GROUPS" | awk '{print $2}'`
+ ALL_PACKAGES=`echo $ALL_PACKAGES`
+ [ -z "$ALL_PACKAGES" ] && die_error "No packages/groups specified to install"
+
target_special_fs on
- run_background pacman-installpkg "$PACMAN_TARGET --noconfirm -S $TARGET_PACKAGES" $TMP_PACMAN_LOG #TODO: There may be something wrong here. See http://projects.archlinux.org/?p=installer.git;a=commitdiff;h=f504e9ecfb9ecf1952bd8dcce7efe941e74db946 ASKDEV (Simo)
- follow_progress " Installing... Please Wait " $TMP_PACMAN_LOG
- wait_for pacman-installpkg
-
+ notify "Package installation will begin now. You can watch the output in the progress window. Please be patient."
+
+ #TODO: There may be something wrong here. See http://projects.archlinux.org/?p=installer.git;a=commitdiff;h=f504e9ecfb9ecf1952bd8dcce7efe941e74db946 ASKDEV (Simo)
+ run_controlled pacman_installpkg "$PACMAN_TARGET --noconfirm -S $ALL_PACKAGES" $TMP_PACMAN_LOG "Installing... Please Wait"
local _result=''
- if [ ${pacman-installpkg_exitcode} -ne 0 ]; then
+ if [ ${pacman_installpkg_exitcode} -ne 0 ]; then
_result="Installation Failed (see errors below)"
echo -e "\nPackage Installation FAILED." >>$TMP_PACMAN_LOG
else
@@ -46,14 +48,13 @@ installpkg() {
target_special_fs off
sync
- #return ${pacman-installpkg_exitcode} TODO: fix this. there is something wrong here
- return 0
+ return ${pacman_installpkg_exitcode}
}
# auto_locale(). taken from setup
# enable glibc locales from rc.conf and build initial locale DB
-target_configure_inital_locale()
+target_configure_initial_locale()
{
for i in $(grep "^LOCALE" ${var_TARGET_DIR}/etc/rc.conf | sed -e 's/.*="//g' -e's/\..*//g'); do
sed -i -e "s/^#$i/$i/g" ${var_TARGET_DIR}/etc/locale.gen
diff --git a/src/core/libs/lib-ui-interactive.sh b/src/core/libs/lib-ui-interactive.sh
index 8fdc5dc..cb80c11 100644
--- a/src/core/libs/lib-ui-interactive.sh
+++ b/src/core/libs/lib-ui-interactive.sh
@@ -26,9 +26,9 @@ interactive_configure_system()
while true; do
DEFAULT=no
[ -n "$FILE" ] && DEFAULT="$FILE"
- helptext=
- grep -q '^/dev/mapper' $TMP_FSTAB && helptext="Don't forget to add the appropriate modules for your /dev/mapper devices to mkinitcpio.conf" #TODO: we can improve this a bit
- ask_option $DEFAULT "Configuration" "$helptext" \
+ helptext="Note that if you want to change any file not listed here (unlikely) you can go to another tty and update ${var_TARGET_DIR}/etc/<filename> yourself"
+ grep -q '^/dev/mapper' $TMP_FSTAB && helptext="$helptext\nDon't forget to add the appropriate modules for your /dev/mapper devices to mkinitcpio.conf" #TODO: we can improve this a bit
+ ask_option $DEFAULT "Configuration" "$helptext" required \
"/etc/rc.conf" "System Config" \
"/etc/fstab" "Filesystem Mountpoints" \
"/etc/mkinitcpio.conf" "Initramfs Config" \
@@ -38,12 +38,13 @@ interactive_configure_system()
"/etc/hosts.deny" "Denied Network Services" \
"/etc/hosts.allow" "Allowed Network Services" \
"/etc/locale.gen" "Glibc Locales" \
+ "/etc/pacman.conf" "Pacman.conf" \
"$var_MIRRORLIST" "Pacman Mirror List" \
"Root-Password" "Set the root password" \
- "Return" "Return to Main Menu" || FILE="Return"
+ "Done" "Return to Main Menu" || return 1
FILE=$ANSWER_OPTION
- if [ "$FILE" = "Return" -o -z "$FILE" ]; then # exit
+ if [ "$FILE" = "Done" ]; then # exit
break
elif [ "$FILE" = "Root-Password" ]; then # non-file
while true; do
@@ -52,60 +53,78 @@ interactive_configure_system()
else #regular file
$EDITOR ${var_TARGET_DIR}${FILE}
fi
+
+ # if user edited /etc/rc.conf, add the hostname to /etc/hosts if it's not already there.
+ # note that if the user edits rc.conf several times to change the hostname more then once, we will add them all to /etc/hosts. this is not perfect, but to avoid this, too much code would be required (feel free to prove me wrong :))
+ if [ "$FILE" = "/etc/rc.conf" ]
+ then
+ HOSTNAME=`sed -n '/^HOSTNAME/s/HOSTNAME=//p' ${var_TARGET_DIR}${FILE} | sed 's/"//g'`
+ if ! grep '127\.0\.0\.1' ${var_TARGET_DIR}/etc/hosts | grep -q "$HOSTNAME"
+ then
+ sed -i "s/127\.0\.0\.1.*/& $HOSTNAME/" ${var_TARGET_DIR}/etc/hosts
+ fi
+ fi
done
+ # temporary backup files are not useful anymore past this point.
+ find "${var_TARGET_DIR}/etc/" -name '*~' -delete &>/dev/null
+ return 0
}
-# set_clock()
-# prompts user to set hardware clock and timezone
-#
-# params: none
-# returns: 1 on failure
-interactive_set_clock()
-{
- # utc or local?
- ask_option no "Clock configuration" "Is your hardware clock in UTC or local time?" "UTC" " " "local" " " || return 1
- HARDWARECLOCK=$ANSWER_OPTION
-
- # timezone?
+interactive_timezone () {
ask_timezone || return 1
- TIMEZONE=$ANSWER_TIMEZONE
+ TIMEZONE=$ANSWER_TIMEZONE
+ infofy "Setting Timezone to $TIMEZONE"
+ [ -e /etc/localtime ] && rm -f /etc/localtime #why do we do this?? tpowa?
+ dohwclock
+}
+
+
+
+interactive_time () {
+ # utc or localtime?
+ ask_option no "Clock configuration" "Is your hardware clock in UTC or local time?" required "UTC" " " "localtime" " " || return 1
+ HARDWARECLOCK=$ANSWER_OPTION
+
+ dohwclock
+
+ if which ntpdate >/dev/null && ask_yesno "'ntpdate' was detected on your system.\n\nDo you want to use 'ntpdate' for syncing your clock,\nby using the internet clock pool?\n(You need a working internet connection for doing this!)" yes #TODO: only propose if network ok.
+ then
+ if ntpdate pool.ntp.org >/dev/null
+ then
+ notify "Synced clock with internet pool successfully.\n\nYour current time is now:\n$(date)"
+ else
+ show_warning 'Ntp failure' "An error has occured, time was not changed!"
+ fi
+ fi
+
+ # display and ask to set date/time
+ ask_datetime
- # set system clock from hwclock - stolen from rc.sysinit
- local HWCLOCK_PARAMS=""
- if [ "$HARDWARECLOCK" = "UTC" ]
- then
- HWCLOCK_PARAMS="$HWCLOCK_PARAMS --utc"
- else
- HWCLOCK_PARAMS="$HWCLOCK_PARAMS --localtime"
- fi
if [ "$TIMEZONE" != "" -a -e "/usr/share/zoneinfo/$TIMEZONE" ]
then
/bin/rm -f /etc/localtime
/bin/cp "/usr/share/zoneinfo/$TIMEZONE" /etc/localtime
fi
- /sbin/hwclock --hctosys $HWCLOCK_PARAMS --noadjfile
-
- # display and ask to set date/time
- ask_datetime
# save the time
date -s "$ANSWER_DATETIME" || show_warning "Date/time setting failed" "Something went wrong when doing date -s $ANSWER_DATETIME"
- /sbin/hwclock --systohc $HWCLOCK_PARAMS --noadjfile
-
- return 0
+ dohwclock
}
+
+
+
interactive_autoprepare()
{
DISCS=$(finddisks)
if [ $(echo $DISCS | wc -w) -gt 1 ]
then
notify "Available Disks:\n\n$(_getavaildisks)\n"
- ask_option no 'Harddrive selection' "Select the hard drive to use" $(finddisks 1 _) || return 1
+ ask_option no 'Harddrive selection' "Select the hard drive to use" required $(finddisks 1 _) || return 1
DISC=$ANSWER_OPTION
else
DISC=$DISCS
@@ -113,7 +132,7 @@ interactive_autoprepare()
DISC=${DISC// /} # strip all whitespace. we need this for some reason.TODO: find out why
- get_blockdevice_size $DISC SI
+ get_blockdevice_size $DISC MiB
FSOPTS=
which `get_filesystem_program ext2` &>/dev/null && FSOPTS="$FSOPTS ext2 Ext2"
which `get_filesystem_program ext3` &>/dev/null && FSOPTS="$FSOPTS ext3 Ext3"
@@ -123,12 +142,12 @@ interactive_autoprepare()
which `get_filesystem_program jfs` &>/dev/null && FSOPTS="$FSOPTS jfs JFS"
which `get_filesystem_program vfat` &>/dev/null && FSOPTS="$FSOPTS vfat VFAT"
- ask_number "Enter the size (MB) of your /boot partition. Recommended size: 100MB\n\nDisk space left: $BLOCKDEVICE_SIZE MB" 16 $BLOCKDEVICE_SIZE || return 1
+ ask_number "Enter the size (MiB) of your /boot partition. Recommended size: 100MiB\n\nDisk space left: $BLOCKDEVICE_SIZE MiB" 16 $BLOCKDEVICE_SIZE 100 || return 1
BOOT_PART_SIZE=$ANSWER_NUMBER
BLOCKDEVICE_SIZE=$(($BLOCKDEVICE_SIZE-$BOOT_PART_SIZE))
- ask_number "Enter the size (MB) of your swap partition. Recommended size: 256MB\n\nDisk space left: $BLOCKDEVICE_SIZE MB" 1 $BLOCKDEVICE_SIZE || return 1
+ ask_number "Enter the size (MiB) of your swap partition. Recommended size: 256MiB\n\nDisk space left: $BLOCKDEVICE_SIZE MiB" 1 $BLOCKDEVICE_SIZE 256 || return 1
SWAP_PART_SIZE=$ANSWER_NUMBER
BLOCKDEVICE_SIZE=$(($BLOCKDEVICE_SIZE-$SWAP_PART_SIZE))
@@ -136,15 +155,15 @@ interactive_autoprepare()
ROOT_PART_SET=""
while [ "$ROOT_PART_SET" = "" ]
do
- ask_number "Enter the size (MB) of your / partition. Recommended size:7500. The /home partition will use the remaining space.\n\nDisk space left: $BLOCKDEVICE_SIZE MB" 1 $BLOCKDEVICE_SIZE || return 1
+ ask_number "Enter the size (MiB) of your / partition. Recommended size:7500. The /home partition will use the remaining space.\n\nDisk space left: $BLOCKDEVICE_SIZE MiB" 1 $BLOCKDEVICE_SIZE 7500 || return 1
ROOT_PART_SIZE=$ANSWER_NUMBER
- ask_yesno "$(($BLOCKDEVICE_SIZE-$ROOT_PART_SIZE)) MB will be used for your /home partition. Is this OK?" yes && ROOT_PART_SET=1 #TODO: when doing yes, cli mode prints option JFS all the time, dia mode goes back to disks menu
+ ask_yesno "$(($BLOCKDEVICE_SIZE-$ROOT_PART_SIZE)) MiB will be used for your /home partition. Is this OK?" yes && ROOT_PART_SET=1 #TODO: when doing yes, cli mode prints option JFS all the time, dia mode goes back to disks menu
done
CHOSEN_FS=""
while [ "$CHOSEN_FS" = "" ]
do
- ask_option no 'Filesystem selection' "Select a filesystem for / and /home:" $FSOPTS || return 1
+ ask_option no 'Filesystem selection' "Select a filesystem for / and /home:" required $FSOPTS || return 1
FSTYPE=$ANSWER_OPTION
ask_yesno "$FSTYPE will be used for / and /home. Is this OK?" yes && CHOSEN_FS=1
done
@@ -152,9 +171,6 @@ interactive_autoprepare()
ask_yesno "$DISC will be COMPLETELY ERASED! Are you absolutely sure?" || return 1
- # we assume a /dev/hdX format (or /dev/sdX)
- PART_ROOT="${DISC}3"
-
echo "$DISC $BOOT_PART_SIZE:ext2:+ $SWAP_PART_SIZE:swap $ROOT_PART_SIZE:$FSTYPE *:$FSTYPE" > $TMP_PARTITIONS
echo "${DISC}1 raw no_label ext2;yes;/boot;target;no_opts;no_label;no_params" > $TMP_BLOCKDEVICES
@@ -191,7 +207,7 @@ interactive_partition() {
DISC=""
while true; do
# Prompt the user with a list of known disks
- ask_option no 'Disc selection' "Select the disk you want to partition (select DONE when finished)" $DISCS || return 1
+ ask_option no 'Disc selection' "Select the disk you want to partition (select DONE when finished)" required $DISCS || return 1
DISC=$ANSWER_OPTION
if [ "$DISC" = "OTHER" ]; then
ask_string "Enter the full path to the device you wish to partition" "/dev/sda" || return 1
@@ -249,7 +265,7 @@ interactive_filesystem ()
local old_fs_params=$fs_params
ask_option edit "Alter this $fs_type filesystem on $part ?" \
- "Alter $fs_type filesystem (label:$fs_label, mountpoint:$fs_mountpoint) on $part (type:$part_type, label:$part_label) ?" \
+ "Alter $fs_type filesystem (label:$fs_label, mountpoint:$fs_mountpoint) on $part (type:$part_type, label:$part_label) ?" required \
edit EDIT delete DELETE #TODO: nicer display if label is empty etc
# Don't alter, and return if user cancels
@@ -302,7 +318,7 @@ interactive_filesystem ()
else
default=
[ -n "$fs_type" ] && default="--default-item $fs_type"
- ask_option no "Select filesystem" "Select a filesystem for $part:" $FSOPTS || return 1
+ ask_option no "Select filesystem" "Select a filesystem for $part:" required $FSOPTS || return 1
fs_type=$ANSWER_OPTION
fi
@@ -351,10 +367,11 @@ interactive_filesystem ()
fi
if [ "$fs_type" = lvm-lv ]
then
- [ -z "$fs_params" ] && default='5G'
+ [ -z "$fs_params" ] && default='5000'
[ -n "$fs_params" ] && default="$fs_params"
- ask_string "Enter the size for this $fs_type on $part (suffix K,M,G,T,P,E. default is M)" "$default" || return 1
- fs_params=$ANSWER_STRING
+ ask_number "Enter the size for this $fs_type on $part in MiB" 1 0 "$default" || return 1 #TODO: can we get the upperlimit from somewhere?
+ # Lvm tools use binary units but have their own suffixes ( K,M,G,T,P,E, but they mean KiB, MiB etc)
+ fs_params="${ANSWER_NUMBER}M"
fi
if [ "$fs_type" = dm_crypt ]
then
@@ -412,7 +429,7 @@ remove_blockdevice ()
declare target_escaped=${target//\//\\/} # note: apparently no need to escape the '+' sign for sed.
declare target_escawk=${target_escaped/+/\\+} # ...but that doesn't count for awk
fs_string=`awk "/^$target_escawk / { print \$4}" $TMP_BLOCKDEVICES` #TODO: fs_string is the entire line, incl part?
- debug "Cleaning up partition $part (type $part_type, label $part_label). It has the following FS's on it: $fs_string"
+ debug 'UI-INTERACTIVE' "Cleaning up partition $part (type $part_type, label $part_label). It has the following FS's on it: $fs_string"
sed -i "/$target_escaped/d" $TMP_BLOCKDEVICES || show_warning "blockdevice removal" "Could not remove partition $part (type $part_type, label $part_label). This is a bug. please report it"
for fs in `sed 's/|/ /g' <<< $fs_string`
do
@@ -435,7 +452,7 @@ interactive_filesystems() {
ALLOK=0
while [ "$ALLOK" = 0 ]
do
- # Let the user make filesystems and mountpoints
+ # Let the user make filesystems and mountpoints. USERHAPPY becomes 1 when the user hits DONE.
USERHAPPY=0
while [ "$USERHAPPY" = 0 ]
@@ -449,16 +466,16 @@ interactive_filesystems() {
fs_display=${fs//;target/}
[ "$label" != no_label ] && label_display="($label)"
[ "$label" = no_label ] && label_display=
- if [ -b "${part/+/}" ] && get_blockdevice_size ${part/+/} IEC # test -b <-- exit's 0, test -b '' exits >0.
+ if [ -b "${part/+/}" ] && get_blockdevice_size ${part/+/} MiB # test -b <-- exit's 0, test -b '' exits >0.
then
- infostring="${type},${BLOCKDEVICE_SIZE}MB${label_display}->$fs_display" # add size in MB for existing blockdevices (eg not for mapper devices that are not yet created yet) #TODO: ${BLOCKDEVICE_SIZE} is empty sometimes?
+ infostring="${type},${BLOCKDEVICE_SIZE}MiB${label_display}->$fs_display" # add size in MiB for existing blockdevices (eg not for mapper devices that are not yet created yet)
else
infostring="${type}${label_display}->$fs_display"
fi
menu_list="$menu_list $part $infostring" #don't add extra spaces, dialog doesn't like that.
done < $TMP_BLOCKDEVICES
- ask_option no "Manage filesystems" "Here you can manage your filesystems, block devices and virtual devices (device mapper). Note that you don't *need* to specify opts, labels or extra params if you're not using lvm, dm_crypt, etc." $menu_list DONE _
+ ask_option no "Manage filesystems" "Here you can manage your filesystems, block devices and virtual devices (device mapper). Note that you don't *need* to specify opts, labels or extra params if you're not using lvm, dm_crypt, etc." required $menu_list DONE _
[ $? -gt 0 ] && USERHAPPY=1 && break
[ "$ANSWER_OPTION" == DONE ] && USERHAPPY=1 && break
@@ -479,53 +496,52 @@ interactive_filesystems() {
then
for lv in `sed 's/|/ /g' <<< $fs`
do
- label=$( cut -d ';' -f 6 <<< $lv)
- size=$(cut -d ';' -f 7 <<< $lv)
+ label=$(cut -d ';' -f 6 <<< $lv)
+ size=$( cut -d ';' -f 7 <<< $lv)
list="$list $label $size"
done
- else
- list="XXX no-LV's-defined-yet-make-a-new-one"
fi
list="$list empty NEW"
- ask_option empty "Manage LV's on this VG" "Edit/create new LV's on this VG:" $list
- EDIT_VG=$ANSWER_OPTION
- if [ "$ANSWER_OPTION" = XXX -o "$ANSWER_OPTION" = empty ]
- then
- # a new LV must be created on this VG
- if interactive_filesystem $part $part_type $part_label ''
+ ask_option empty "Manage LV's on this VG" "Edit/create new LV's on this VG:" required $list && {
+ EDIT_VG=$ANSWER_OPTION
+ if [ "$ANSWER_OPTION" = empty ]
then
- if [ "$NEW_FILESYSTEM" != no_fs ]
+ # a new LV must be created on this VG
+ if interactive_filesystem $part $part_type $part_label ''
then
- [ -n "$fs" ] && fs="$fs|$NEW_FILESYSTEM"
- [ -z "$fs" ] && fs=$NEW_FILESYSTEM
+ if [ "$NEW_FILESYSTEM" != no_fs ]
+ then
+ [ -n "$fs" ] && fs="$fs|$NEW_FILESYSTEM"
+ [ -z "$fs" ] && fs=$NEW_FILESYSTEM
+ fi
fi
+ else
+ # an existing LV will be edited and it's settings updated
+ for lv in `sed 's/|/ /g' <<< $fs`
+ do
+ label=$(cut -d ';' -f 6 <<< $lv)
+ [ "$label" = "$EDIT_VG" ] && found_lv="$lv"
+ done
+ interactive_filesystem $part $part_type $part_label "$found_lv"
+ newfs=
+ for lv in `sed 's/|/ /g' <<< $fs`
+ do
+ label=$(cut -d ';' -f 6 <<< $lv)
+ if [ "$label" != "$EDIT_VG" ]
+ then
+ add=$lv
+ elif [ $NEW_FILESYSTEM != no_fs ]
+ then
+ add=$NEW_FILESYSTEM
+ else
+ add=
+ fi
+ [ -n "$add" -a -n "$newfs" ] && newfs="$newfs|$add"
+ [ -n "$add" -a -z "$newfs" ] && newfs=$add
+ done
+ fs=$newfs
fi
- else
- # an existing LV will be edited and it's settings updated
- for lv in `sed 's/|/ /g' <<< $fs`
- do
- label=$(cut -d ';' -f 6 <<< $lv)
- [ "$label" = "$EDIT_VG" ] && found_lv="$lv"
- done
- interactive_filesystem $part $part_type $part_label "$found_lv"
- newfs=
- for lv in `sed 's/|/ /g' <<< $fs`
- do
- label=$(cut -d ';' -f 6 <<< $lv)
- if [ "$label" != "$EDIT_VG" ]
- then
- add=$lv
- elif [ $NEW_FILESYSTEM != no_fs ]
- then
- add=$NEW_FILESYSTEM
- else
- add=
- fi
- [ -n "$add" -a -n "$newfs" ] && newfs="$newfs|$add"
- [ -n "$add" -a -z "$newfs" ] && newfs=$add
- done
- fs=$newfs
- fi
+ }
else
interactive_filesystem $part $part_type "$part_label" "$fs"
[ $? -eq 0 ] && fs=$NEW_FILESYSTEM
@@ -550,7 +566,14 @@ interactive_filesystems() {
str="The following issues have been detected:\n"
[ -n "$errors" ] && str="$str\n - Errors: $errors"
[ -n "$warnings" ] && str="$str\n - Warnings: $warnings"
- ask_yesno "$str\n Do you want to back to fix (one of) these issues?" || ALLOK=1 # TODO: we should ask the user if he wants to continue, return or abort.
+ [ -n "$errors" ] && str="$str\nIt is highly recommended you go back to fix at least the errors."
+ str="$str\nIf you hit cancel, we will abort here and go back to the menu"
+ if ask_option back "Issues detected. what do you want to do?" "$str" required back "go back to fix the issues" ignore "continue, ignoring the issues"
+ then
+ [ "$ANSWER_OPTION" == ignore ] && ALLOK=1
+ else
+ return 1
+ fi
else
ALLOK=1
fi
@@ -571,42 +594,43 @@ interactive_filesystems() {
# returns: 1 on error
interactive_select_packages() {
- notify "Package selection is split into two stages. First you will select package categories that contain packages you may be interested in. Then you will be presented with a full list of packages for each category, allowing you to fine-tune.\n\n"
+ # set up our install location if necessary and sync up so we can get package lists
+ target_prepare_pacman || ( show_warning 'Pacman preparation failure' "Pacman preparation failed! Check $LOG for errors." && return 1 )
- # set up our install location if necessary and sync up
- # so we can get package lists
- target_prepare_pacman || ( show_warning 'Pacman preparation failure' "Pacman preparation failed! Check $LOG for errors." && return 1 )
+ repos=`list_pacman_repos target`
+ notify "Package selection is split into two stages. First you will select package groups that contain packages you may be interested in. Then you will be presented with a full list of packages for each group, allowing you to fine-tune.\n\n
+Note that right now the packages (and groups) selection is limited to the repos available at this time ($repos). One you have your Arch system up and running, you have access to more repositories and packages."
# show group listing for group selection, base is ON by default, all others are OFF
- local _catlist="base ^ ON"
- for i in $($PACMAN_TARGET -Sg | sed "s/^base$/ /g"); do
- _catlist="${_catlist} ${i} - OFF"
+ local _grouplist="base ^ ON"
+ for i in $(list_package_groups | sed "s/^base$/ /g"); do
+ _grouplist="${_grouplist} ${i} - OFF"
done
- ask_checklist "Select Package Categories\nDO NOT deselect BASE unless you know what you're doing!" $_catlist || return 1
- _catlist=$ANSWER_CHECKLIST # _catlist now contains all categories (the tags from the dialog checklist)
+ ask_checklist "Select Package groups\nDO NOT deselect BASE unless you know what you're doing!" $_grouplist || return 1
+ _grouplist=$ANSWER_CHECKLIST # _grouplist now contains all groups (the tags from the dialog checklist)
# assemble a list of packages with groups, marking pre-selected ones
# <package> <group> <selected>
- local _pkgtmp="$($PACMAN_TARGET -Sl core | awk '{print $2}')" # all packages in core repository
+ local _pkgtmp="$(list_packages repo core | awk '{print $2}')" # all packages in core repository
local _pkglist=''
- $PACMAN_TARGET -Si $_pkgtmp | awk '/^Name/{ printf("%s ",$3) } /^Group/{ print $3 }' > $ANSWER
- while read pkgname pkgcat; do
+ which_group "$_pkgtmp"
+ while read pkgname pkggroup; do
# check if this package is in a selected group
# slightly ugly but sorting later requires newlines in the variable
- if [ "${_catlist/"\"$pkgcat\""/XXXX}" != "${_catlist}" ]; then
- _pkglist="$(echo -e "${_pkglist}\n${pkgname} ${pkgcat} ON")"
+ if [ "${_grouplist/"\"$pkggroup\""/XXXX}" != "${_grouplist}" ]; then
+ _pkglist="$(echo -e "${_pkglist}\n${pkgname} ${pkggroup} ON")"
else
- _pkglist="$(echo -e "${_pkglist}\n${pkgname} ${pkgcat} OFF")"
+ _pkglist="$(echo -e "${_pkglist}\n${pkgname} ${pkggroup} OFF")"
fi
- done < $ANSWER
+ done <<< "$PACKAGE_GROUPS"
- # sort by category
+ # sort by group
_pkglist="$(echo "$_pkglist" | sort -f -k 2)"
ask_checklist "Select Packages To Install." $_pkglist || return 1
- TARGET_PACKAGES=$ANSWER_CHECKLIST # contains now all package names
+ var_TARGET_PACKAGES=$ANSWER_CHECKLIST # contains now all package names
return 0
}
@@ -626,23 +650,23 @@ interactive_runtime_network() {
return 1
fi
- ask_option no "Interface selection" "Select a network interface" $ifaces || return 1 #TODO: code used originaly --nocancel here. what's the use? + make ok button 'select'
+ ask_option no "Interface selection" "Select a network interface" required $ifaces || return 1 #TODO: code used originaly --nocancel here. what's the use? + make ok button 'select'
INTERFACE=$ANSWER_OPTION
- ask_yesno "Do you want to use DHCP?"
- if [ $? -eq 0 ]; then
+ if ask_yesno "Do you want to use DHCP?"
+ then
infofy "Please wait. Polling for DHCP server on $INTERFACE..."
- killall dhcpd
- killall -9 dhcpd
- sleep 1
- dhcpcd $INTERFACE >$LOG 2>&1
- if [ $? -ne 0 ]; then
- notify "Failed to run dhcpcd. See $LOG for details."
+ dhcpcd -k $INTERFACE >$LOG 2>&1
+ if ! dhcpcd $INTERFACE >$LOG 2>&1
+ then
+ show_warning "Dhcpcd problem" "Failed to run dhcpcd. See $LOG for details."
return 1
fi
- if [ ! $(ifconfig $INTERFACE | grep 'inet addr:') ]; then
- notify "DHCP request failed." || return 1
+ if ! ifconfig $INTERFACE | grep -q 'inet addr:'
+ then
+ show_warning "Dhcpcd problem" "DHCP request failed. dhcpcd returned 0 but no ip configured for $INTERFACE"
+ return 1
fi
S_DHCP=1
else
@@ -669,16 +693,20 @@ interactive_runtime_network() {
esac
done
echo "running: ifconfig $INTERFACE $IPADDR netmask $SUBNET broadcast $BROADCAST up" >$LOG
- ifconfig $INTERFACE $IPADDR netmask $SUBNET broadcast $BROADCAST up >$LOG 2>&1 || notify "Failed to setup $INTERFACE interface." || return 1
- if [ "$GW" != "" ]; then
+ if ! ifconfig $INTERFACE $IPADDR netmask $SUBNET broadcast $BROADCAST up >$LOG 2>&1
+ then
+ show_warning "Ifconfig problem" "Failed to setup interface $INTERFACE"
+ return 1
+ fi
+ if [ -n "$GW" ]; then
route add default gw $GW >$LOG 2>&1 || notify "Failed to setup your gateway." || return 1
fi
- if [ "$PROXY_HTTP" = "" ]; then
+ if [ -z "$PROXY_HTTP" ]; then
unset http_proxy
else
export http_proxy=$PROXY_HTTP
fi
- if [ "$PROXY_FTP" = "" ]; then
+ if [ -z "$PROXY_FTP" ]; then
unset ftp_proxy
else
export ftp_proxy=$PROXY_FTP
@@ -696,6 +724,7 @@ interactive_install_grub() {
[ ! -f $grubmenu ] && show_warning "No grub?" "Error: Couldn't find $grubmenu. Is GRUB installed?" && return 1
# try to auto-configure GRUB...
+ debug 'UI-INTERACTIVE' "install_grub \$PART_ROOT $PART_ROOT \$GRUB_OK $GRUB_OK"
if [ -n "$PART_ROOT" -a "$GRUB_OK" != '1' ] ; then
GRUB_OK=0
grubdev=$(mapdev $PART_ROOT)
@@ -758,7 +787,7 @@ EOF
notify "No hard drives were found"
return 1
fi
- ask_option no "Boot device selection" "Select the boot device where the GRUB bootloader will be installed (usually the MBR and not a partition)." $DEVS || return 1
+ ask_option no "Boot device selection" "Select the boot device where the GRUB bootloader will be installed (usually the MBR and not a partition)." required $DEVS || return 1
ROOTDEV=$ANSWER_OPTION
infofy "Installing the GRUB bootloader..."
cp -a $var_TARGET_DIR/usr/lib/grub/i386-pc/* $var_TARGET_DIR/boot/grub/
@@ -780,7 +809,7 @@ EOF
fi
ask_yesno "Do you have your system installed on software raid?\nAnswer 'YES' to install grub to another hard disk." no
if [ $? -eq 0 ]; then
- ask_option no "Boot partition device selection" "Please select the boot partition device, this cannot be autodetected!\nPlease redo grub installation for all partitions you need it!" $DEVS || return 1
+ ask_option no "Boot partition device selection" "Please select the boot partition device, this cannot be autodetected!\nPlease redo grub installation for all partitions you need it!" required $DEVS || return 1
bootpart=$ANSWER_OPTION
fi
bootpart=$(mapdev $bootpart)
@@ -827,7 +856,7 @@ interactive_select_source()
var_FILE_URL="file:///src/core/pkg"
var_SYNC_URL=
- ask_option no "Source selection" "Please select an installation source" \
+ ask_option no "Source selection" "Please select an installation source" required \
"1" "CD-ROM or OTHER SOURCE" \
"2" "FTP/HTTP" || return 1
@@ -861,7 +890,7 @@ interactive_select_mirror() {
notify "Keep in mind ftp.archlinux.org is throttled.\nPlease select another mirror to get full download speed."
# FIXME: this regex doesn't honor commenting
MIRRORS=$(egrep -o '((ftp)|(http))://[^/]*' "${var_MIRRORLIST}" | sed 's|$| _|g')
- ask_option no "Mirror selection" "Select an FTP/HTTP mirror" $MIRRORS "Custom" "_" || return 1
+ ask_option no "Mirror selection" "Select an FTP/HTTP mirror" required $MIRRORS "Custom" "_" || return 1
local _server=$ANSWER_OPTION
if [ "${_server}" = "Custom" ]; then
ask_string "Enter the full URL to core repo." "ftp://ftp.archlinux.org/core/os/$var_ARCH" || return 1
@@ -884,7 +913,7 @@ interactive_get_editor() {
which nano &>/dev/null && EDITOR_OPTS+=("nano" "nano (easier)")
which joe &>/dev/null && EDITOR_OPTS+=("joe" "joe's editor")
which vi &>/dev/null && EDITOR_OPTS+=("vi" "vi (advanced)")
- ask_option no "Text editor selection" "Select a Text Editor to Use" "${EDITOR_OPTS[@]}"
+ ask_option no "Text editor selection" "Select a Text Editor to Use" required "${EDITOR_OPTS[@]}"
#TODO: this code could be a little bit cleaner.
case $ANSWER_OPTION in
"nano") EDITOR="nano" ;;
diff --git a/src/core/libs/lib-ui.sh b/src/core/libs/lib-ui.sh
index 2315394..50d087a 100644
--- a/src/core/libs/lib-ui.sh
+++ b/src/core/libs/lib-ui.sh
@@ -1,24 +1,38 @@
#!/bin/bash
+# Note that $var_UI_TYPE may not be set here. especially if being loaded in the "early bootstrap" phase
+
# TODO: implement 'retry until user does it correctly' everywhere
# TODO: at some places we should check if $1 etc is only 1 word because we often depend on that
# TODO: standardize. eg everything $1= question/title, $2=default
# TODO: figure out something to make dia windows always big enough, yet fit nicely in the terminal
-# Taken from setup. we store dialog output in a file. TODO: can't we do this with variables? ASKDEV
-ANSWER=$RUNTIME_DIR/.dialog-answer
+# Taken from setup. we store dialog output in a file. TODO: a variable would be cleaner
+ANSWER=$RUNTIME_DIR/aif-dialog-answer
DIA_MENU_TEXT="Use the UP and DOWN arrows to navigate menus. Use TAB to switch between buttons and ENTER to select."
-DIA_SUCCESSIVE_ITEMS=$RUNTIME_DIR/.dia-successive-items
+DIA_SUCCESSIVE_ITEMS=$RUNTIME_DIR/aif-dia-successive-items
+
+
+# get keymap/font (maybe configured by aif allready in another process or even in another shell)
+# otherwise, take default keymap and consolefont as configured in /etc/rc.conf. can be overridden
+# Note that the vars in /etc/rc.conf can also be empty!
+[ -e $RUNTIME_DIR/aif-keymap ] && var_KEYMAP=` cat $RUNTIME_DIR/aif-keymap`
+[ -e $RUNTIME_DIR/aif-consolefont ] && var_CONSOLEFONT=`cat $RUNTIME_DIR/aif-consolefont`
+[ -z "$var_KEYMAP" ] && source /etc/rc.conf && var_KEYMAP=$KEYMAP
+[ -z "$var_CONSOLEFONT" ] && source /etc/rc.conf && var_CONSOLEFONT=$CONSOLEFONT
+
+
### Functions that your code can use. Cli/dialog mode is fully transparant. This library takes care of it ###
+
# display error message and die
+# Do not call other functions like debug, notify, .. here because that might cause loops!
die_error ()
{
- debug "die_error: ERROR: $@"
- notify "ERROR: $@"
- exit 2
+ echo "ERROR: $@" >&2
+ exit 2
}
@@ -28,32 +42,32 @@ die_error ()
# $3 type of item. msg or text if it's a file. (optional. defaults to msg)
show_warning ()
{
- [ -z "$1" ] && die_error "show_warning needs a title"
- [ -z "$2" ] && die_error "show_warning needs an item to show"
- [ -n "$3" -a "$3" != msg -a "$3" != text ] && die_error "show_warning \$3 must be text or msg"
- type=msg
- [ -n "$3" ] && type=$3
- debug "show_warning '$1': $2 ($type)"
- if [ "$var_UI_TYPE" = dia ]
- then
- _dia_DIALOG --title "$1" --exit-label "Continue" --${type}box "$2" 18 70 || die_error "dialog could not show --${type}box $2. often this means a file does not exist"
- else
- echo "WARNING: $1"
- [ "${type}" = msg ] && echo -e "$2"
- [ "${type}" = text ] && (cat $2 || die_error "Could not cat $2")
- fi
+ [ -z "$1" ] && die_error "show_warning needs a title"
+ [ -z "$2" ] && die_error "show_warning needs an item to show"
+ [ -n "$3" -a "$3" != msg -a "$3" != text ] && die_error "show_warning \$3 must be text or msg"
+ type=msg
+ [ -n "$3" ] && type=$3
+ debug 'UI' "show_warning '$1': $2 ($type)"
+ if [ "$var_UI_TYPE" = dia ]
+ then
+ _dia_DIALOG --title "$1" --exit-label "Continue" --${type}box "$2" 0 0 || die_error "dialog could not show --${type}box $2. often this means a file does not exist"
+ else
+ echo "WARNING: $1"
+ [ "${type}" = msg ] && echo -e "$2"
+ [ "${type}" = text ] && (cat $2 || die_error "Could not cat $2")
+ fi
return 0
}
-
-
+
+
#notify user
notify ()
{
- debug "notify: $@"
+ debug 'UI' "notify: $@"
if [ "$var_UI_TYPE" = dia ]
then
- _dia_DIALOG --msgbox "$@" 20 50
+ _dia_DIALOG --msgbox "$@" 0 0
else
echo -e "$@"
fi
@@ -70,7 +84,7 @@ infofy () #TODO: when using successive things, the screen can become full and yo
{
successive=${2:-0}
succ_last=${3:-0}
- debug "infofy: $1"
+ debug 'UI' "infofy: $1"
if [ "$var_UI_TYPE" = dia ]
then
str="$1"
@@ -80,44 +94,47 @@ infofy () #TODO: when using successive things, the screen can become full and yo
str=`cat $DIA_SUCCESSIVE_ITEMS-$successive`
fi
[ "$succ_last" = 1 ] && rm $DIA_SUCCESSIVE_ITEMS-$successive
- _dia_DIALOG --infobox "$str" 20 50
+ _dia_DIALOG --infobox "$str" 0 0
else
echo -e "$1"
fi
}
-
# logging of stuff
log ()
{
+ mkdir -p $LOG_DIR || die_error "Cannot create log directory"
str="[LOG] `date +"%Y-%m-%d %H:%M:%S"` $@"
- if [ "$var_UI_TYPE" = dia ]
- then
- echo -e "$str" >$LOG
- else
- echo -e "$str" >$LOG
- fi
+ echo -e "$str" > $LOG || die_error "Cannot log $str to $LOG"
- [ "$LOG_TO_FILE" = 1 ] && echo -e "$str" >> $LOGFILE
+ [ "$LOG_TO_FILE" = 1 ] && ( echo -e "$str" >> $LOGFILE || die_error "Cannot log $str to $LOGFILE" )
}
+# $1 = one or more categories (separated by spaces) from: MAIN, PROCEDURE, UI, UI-INTERACTIVE, FS, MISC, NETWORK, PACMAN, SOFTWARE
+# You should always at least specify where you are (main, procedure or the name of the lib) and optionally further specification: eg in a ui function that works with pacman.
+# This is very useful in ui-interactive where we always work with something else.
+# $2 = string to log
debug ()
{
- str="[DEBUG] $@"
+ valid_cats=(MAIN PROCEDURE UI UI-INTERACTIVE FS MISC NETWORK PACMAN SOFTWARE)
+ for cat in $1
+ do
+ check_is_in $cat "${valid_cats[@]}" || die_error "debug \$1 contains a value ($cat) which is not a valid debug category"
+ done
+ [ -n "$2" ] || die_error "debug \$2 cannot be empty"
+
+ mkdir -p $LOG_DIR || die_error "Cannot create log directory"
if [ "$DEBUG" = "1" ]
then
- if [ "$var_UI_TYPE" = dia ]
- then
- echo -e "$str" > $LOG
- else
- echo -e "$str" > $LOG
- fi
- [ "$LOG_TO_FILE" = 1 ] && echo -e "$str" >> $LOGFILE
- fi
+ str="[DEBUG $1 ] $2"
+ echo -e "$str" > $LOG || die_error "Cannot debug $str to $LOG"
+ [ "$LOG_TO_FILE" = 1 ] && ( echo -e "$str" >> $LOGFILE || die_error "Cannot debug $str to $LOGFILE" )
+ fi
}
+
# taken from setup
printk()
{
@@ -129,14 +146,17 @@ printk()
# TODO: pass disks as argument to decouple backend logic
-# Get a list of available disks for use in the "Available disks" dialogs. This
-# will print the disks as follows, getting size info from hdparm:
-# /dev/sda: 640133 MBytes (640 GB)
-# /dev/sdb: 640135 MBytes (640 GB)
+# Get a list of available disks for use in the "Available disks" dialogs.
+# Something like:
+# /dev/sda: 640133 MiB (640 GiB)
+# /dev/sdb: 640135 MiB (640 GiB)
_getavaildisks()
{
- # NOTE: to test as non-root, stick in a 'sudo' before the hdparm call
- for i in $(finddisks); do echo -n "$i: "; hdparm -I $i | grep -F '1000*1000' | sed "s/.*1000:[ \t]*\(.*\)/\1/"; echo "\n"; done
+ for i in $(finddisks)
+ do
+ get_blockdevice_size $i MiB
+ echo "$i: $BLOCKDEVICE_SIZE MiB ($(($BLOCKDEVICE_SIZE/2**10)) GiB)\n"
+ done
}
@@ -147,7 +167,7 @@ _getavaildisks()
ask_checklist ()
{
[ -z "$1" ] && die_error "ask_checklist needs a question!"
- [ -z "$4" ] && debug "ask_checklist args: $@" && die_error "ask_checklist makes only sense if you specify at least 1 thing (tag,item and ON/OFF switch)"
+ [ -z "$4" ] && debug 'UI' "ask_checklist args: $@" && die_error "ask_checklist makes only sense if you specify at least 1 thing (tag,item and ON/OFF switch)"
[ "$var_UI_TYPE" = dia ] && { _dia_ask_checklist "$@" ; return $? ; }
[ "$var_UI_TYPE" = cli ] && { _cli_ask_checklist "$@" ; return $? ; }
}
@@ -163,17 +183,18 @@ ask_datetime ()
# ask for a number.
# $1 question
# $2 lower limit (optional)
-# $3 upper limit (optional)
-# $4 default : TODO implement in cli
-# echo's the number the user said
+# $3 upper limit (optional. set 0 for none)
+# $4 default (optional)
+# sets $ANSWER_NUMBER to the number the user specified
# returns 1 if the user cancelled or did not enter a numeric, 0 otherwise
ask_number ()
{
[ -z "$1" ] && die_error "ask_number needs a question!"
- [ -n "$2" ] && [[ $2 = *[^0-9]* ]] && die_error "ask_number \$2 must be a number! not $2"
- [ -n "$3" ] && [[ $3 = *[^0-9]* ]] && die_error "ask_number \$3 must be a number! not $3"
- [ "$var_UI_TYPE" = dia ] && { _dia_ask_number "$1" "$2" "$3" ; return $? ; }
- [ "$var_UI_TYPE" = cli ] && { _cli_ask_number "$1" "$2" "$3" ; return $? ; }
+ [ -n "$2" ] && [[ "$2" = *[^0-9]* ]] && die_error "ask_number \$2 must be a number! not $2"
+ [ -n "$3" ] && [[ "$3" = *[^0-9]* ]] && die_error "ask_number \$3 must be a number! not $3"
+ [ -n "$4" ] && [[ "$4" = *[^0-9]* ]] && die_error "ask_number \$4 must be a number! not $4"
+ [ "$var_UI_TYPE" = dia ] && { _dia_ask_number "$1" $2 $3 $4; return $? ; }
+ [ "$var_UI_TYPE" = cli ] && { _cli_ask_number "$1" $2 $3 $4; return $? ; }
}
@@ -181,9 +202,11 @@ ask_number ()
# $1 default item (set to 'no' for none)
# $2 title
# $3 additional explanation (default: '')
-# shift;shift; $@ list of options. first tag. then name. (eg tagA itemA "tag B" 'item B' )
-# the response will be echoed to stdout. but also $ANSWER_OPTION will be set. take that because the former method seems to not work.
-# $? if user cancelled. 0 otherwise
+# $4 type (required or optional). '' means required. cancel labels will be 'Cancel' and 'Skip' respectively.
+# shift 4 ; $@ list of options. first tag. then name. (eg tagA itemA "tag B" 'item B' )
+
+# $ANSWER_OPTION : selected answer (if none selected: default (if available), or empty string otherwise). if user hits cancel or skip, this is an empty string.
+# $? : 0 if the user selected anything or skipped (when optional), when user cancelled: 1
ask_option ()
{
[ "$var_UI_TYPE" = dia ] && { _dia_ask_option "$@" ; return $? ; }
@@ -239,12 +262,14 @@ ask_yesno ()
# follow the progress of something by showing it's log, updating real-time
# $1 title
# $2 logfile
+# $3 pid to monitor. if process stopped, stop following (only used in cli mode)
follow_progress ()
{
[ -z "$1" ] && die_error "follow_progress needs a title!"
[ -z "$2" ] && die_error "follow_progress needs a logfile to follow!"
- [ "$var_UI_TYPE" = dia ] && { _dia_follow_progress "$1" "$2" ; return $? ; }
- [ "$var_UI_TYPE" = cli ] && { _cli_follow_progress "$1" "$2" ; return $? ; }
+ FOLLOW_PID=
+ [ "$var_UI_TYPE" = dia ] && { _dia_follow_progress "$@" ; return $? ; }
+ [ "$var_UI_TYPE" = cli ] && { _cli_follow_progress "$@" ; return $? ; }
}
@@ -280,10 +305,10 @@ _dia_ask_checklist ()
list="$list $1 $2 $3"
shift 3
done
- _dia_DIALOG --checklist "$str" 30 60 20 $list 2>$ANSWER
+ _dia_DIALOG --checklist "$str" 0 0 0 $list 2>$ANSWER
ret=$?
ANSWER_CHECKLIST=`cat $ANSWER`
- debug "_dia_ask_checklist: user checked ON: $ANSWER_CHECKLIST"
+ debug 'UI' "_dia_ask_checklist: user checked ON: $ANSWER_CHECKLIST"
return $ret
}
@@ -295,7 +320,7 @@ _dia_ask_datetime ()
local _date="$(cat $ANSWER)" # form like: 07/12/2008
dialog --timebox "Set the time.\nUse <TAB> to navigate and up/down to change values." 0 0 2> $ANSWER || return 1
local _time="$(cat $ANSWER)" # form like: 15:26:46
- debug "Date as specified by user $_date time: $_time"
+ debug 'UI' "Date as specified by user $_date time: $_time"
# DD/MM/YYYY hh:mm:ss -> MMDDhhmmYYYY.ss (date default format, set like date $ANSWER_DATETIME) Not enabled because there is no use for it i think.
# ANSWER_DATETIME=$(echo "$_date" "$_time" | sed 's#\(..\)/\(..\)/\(....\) \(..\):\(..\):\(..\)#\2\1\4\5\3\6#g')
@@ -310,17 +335,17 @@ _dia_ask_number ()
while true
do
str="$1"
- [ -n "$2" ] && str2="min $2"
- [ -n "$3" ] && str2="$str2 max $3"
+ [ -n $2 ] && str2="min $2"
+ [ -n $3 -a $3 != '0' ] && str2="$str2 max $3"
[ -n "$str2" ] && str="$str ( $str2 )"
- _dia_DIALOG --inputbox "$str" 8 65 "$4" 2>$ANSWER
+ _dia_DIALOG --inputbox "$str" 0 0 $4 2>$ANSWER
ret=$?
ANSWER_NUMBER=`cat $ANSWER`
if [[ $ANSWER_NUMBER = *[^0-9]* ]] #TODO: handle exit state
then
show_warning "$ANSWER_NUMBER is not a number! try again."
else
- if [ -n "$3" -a $ANSWER_NUMBER -gt $3 ]
+ if [ -n "$3" -a $3 != '0' -a $ANSWER_NUMBER -gt $3 ]
then
show_warning "$ANSWER_NUMBER is bigger then the maximum,$3! try again."
elif [ -n "$2" -a $ANSWER_NUMBER -lt $2 ]
@@ -331,7 +356,7 @@ _dia_ask_number ()
fi
fi
done
- debug "_dia_ask_number: user entered: $ANSWER_NUMBER"
+ debug 'UI' "_dia_ask_number: user entered: $ANSWER_NUMBER"
[ -z "$ANSWER_NUMBER" ] && return 1
return $ret
}
@@ -343,16 +368,21 @@ _dia_ask_option ()
[ "$1" != 'no' ] && DEFAULT="--default-item $1"
[ -z "$2" ] && die_error "ask_option \$2 must be the title"
# $3 is optional more info
- [ -z "$5" ] && debug "_dia_ask_option args: $@" && die_error "ask_option makes only sense if you specify at least one option (with tag and name)" #nothing wrong with only 1 option. it still shows useful info to the user
+ TYPE=${4:-required}
+ [ "$TYPE" != required -a "$TYPE" != optional ] && debug 'UI' "_dia_ask_option args: $@" && die_error "ask option \$4 must be required or optional or ''. not $TYPE"
+ [ -z "$6" ] && debug 'UI' "_dia_ask_option args: $@" && die_error "ask_option makes only sense if you specify at least one option (with tag and name)" #nothing wrong with only 1 option. it still shows useful info to the user
DIA_MENU_TITLE=$2
EXTRA_INFO=$3
- shift 3
- _dia_DIALOG $DEFAULT --colors --title " $DIA_MENU_TITLE " --menu "$DIA_MENU_TEXT $EXTRA_INFO" 20 80 16 "$@" 2>$ANSWER
+ shift 4
+ CANCEL_LABEL=Cancel
+ [ $TYPE == optional ] && CANCEL_LABEL='Skip'
+ _dia_DIALOG $DEFAULT --cancel-label $CANCEL_LABEL --colors --title " $DIA_MENU_TITLE " --menu "$DIA_MENU_TEXT $EXTRA_INFO" 0 0 0 "$@" 2>$ANSWER
ret=$?
ANSWER_OPTION=`cat $ANSWER`
- debug "dia_ask_option: User choose $ANSWER_OPTION ($DIA_MENU_TITLE)"
- return $ret
+ debug 'UI' "dia_ask_option: ANSWER_OPTION: $ANSWER_OPTION, returncode (skip/cancel): $ret ($DIA_MENU_TITLE)"
+ [ $TYPE == required ] && return $ret
+ return 0 # TODO: check if dialog returned >0 because of an other reason then the user hitting 'cancel/skip'
}
@@ -372,7 +402,7 @@ _dia_ask_password ()
[ -n "$type_u" ] && read ${type_u}_PASSWORD < $ANSWER
[ -z "$type_u" ] && read PASSWORD < $ANSWER
cat $ANSWER
- debug "_dia_ask_password: user entered <<hidden>>"
+ debug 'UI' "_dia_ask_password: user entered <<hidden>>"
return $ret
}
@@ -380,10 +410,10 @@ _dia_ask_password ()
_dia_ask_string ()
{
exitcode=${3:-1}
- _dia_DIALOG --inputbox "$1" 8 65 "$2" 2>$ANSWER
+ _dia_DIALOG --inputbox "$1" 0 0 "$2" 2>$ANSWER
ret=$?
ANSWER_STRING=`cat $ANSWER`
- debug "_dia_ask_string: user entered $ANSWER_STRING"
+ debug 'UI' "_dia_ask_string: user entered $ANSWER_STRING"
[ -z "$ANSWER_STRING" ] && return $exitcode
return $ret
}
@@ -391,7 +421,25 @@ _dia_ask_string ()
_dia_ask_timezone ()
{
- ANSWER_TIMEZONE=`tzselect` #TODO: implement nicer then this
+ REGIONS=""
+ SET_ZONE=""
+ for i in $(grep ^[A-Z] /usr/share/zoneinfo/zone.tab | cut -f 3 | sed -e 's#/.*##g'| sort -u); do
+ REGIONS="$REGIONS $i -"
+ done
+ while [ "$SET_ZONE" != "1" ]; do
+ SET_REGION=""
+ ask_option no "Please select a region" '' required $REGIONS
+ region=ANSWER_OPTION
+ if [ $? -eq 0 ]; then
+ ZONES=""
+ for i in $(grep ^[A-Z] /usr/share/zoneinfo/zone.tab | grep $region/ | cut -f 3 | sed -e "s#$region/##g"| sort -u); do
+ ZONES="$ZONES $i -"
+ done
+ ask_option no "Please select a timezone" '' required $ZONES
+ zone=$ANSWER_OPTION
+ [ $? -gt 0 ] && ANSWER_TIMEZONE="$region/$zone" && return
+ fi
+ done
}
@@ -403,8 +451,8 @@ _dia_ask_yesno ()
[ -n "$2" ] && str="$str (default: $2)"
dialog --yesno "$str" $height 55 # returns 0 for yes, 1 for no
ret=$?
- [ $ret -eq 0 ] && debug "dia_ask_yesno: User picked YES"
- [ $ret -gt 0 ] && debug "dia_ask_yesno: User picked NO"
+ [ $ret -eq 0 ] && debug 'UI' "dia_ask_yesno: User picked YES"
+ [ $ret -gt 0 ] && debug 'UI' "dia_ask_yesno: User picked NO"
return $ret
}
@@ -413,7 +461,7 @@ _dia_follow_progress ()
{
title=$1
logfile=$2
- _dia_DIALOG --title "$1" --no-kill --tailboxbg "$2" 18 70 2>$ANSWER
+ FOLLOW_PID=`_dia_DIALOG --title "$1" --no-kill --tailboxbg "$2" 0 0 2>&1 >/dev/null`
}
@@ -444,7 +492,7 @@ _cli_ask_datetime ()
{
ask_string "Enter date [YYYY-MM-DD hh:mm:ss]"
ANSWER_DATETIME=$ANSWER_STRING
- debug "Date as picked by user: $ANSWER_STRING"
+ debug 'UI' "Date as picked by user: $ANSWER_STRING"
}
@@ -454,8 +502,9 @@ _cli_ask_number ()
while true
do
str="$1"
- [ -n "$2" ] && str2="min $2"
- [ -n "$3" ] && str2="$str2 max $3"
+ [ -n $2 ] && str2="min $2"
+ [ -n $3 -a $3 != '0' ] && str2="$str2 max $3"
+ [ -n $4 ] && str2=" default $4"
[ -n "$str2" ] && str="$str ( $str2 )"
echo "$str"
read ANSWER_NUMBER
@@ -463,10 +512,18 @@ _cli_ask_number ()
then
show_warning "$ANSWER_NUMBER is not a number! try again."
else
- break
+ if [ -n "$3" -a $3 != '0' -a $ANSWER_NUMBER -gt $3 ]
+ then
+ show_warning "$ANSWER_NUMBER is bigger then the maximum,$3! try again."
+ elif [ -n "$2" -a $ANSWER_NUMBER -lt $2 ]
+ then
+ show_warning "$ANSWER_NUMBER is smaller then the minimum,$2! try again."
+ else
+ break
+ fi
fi
done
- debug "cli_ask_number: user entered: $ANSWER_NUMBER"
+ debug 'UI' "cli_ask_number: user entered: $ANSWER_NUMBER"
[ -z "$ANSWER_NUMBER" ] && return 1
return 0
}
@@ -476,15 +533,17 @@ _cli_ask_option ()
{
#TODO: strip out color codes
#TODO: if user entered incorrect choice, ask him again
- DEFAULT=""
+ DEFAULT=
[ "$1" != 'no' ] && DEFAULT=$1 #TODO: if user forgot to specify a default (eg all args are 1 pos to the left, we can end up in an endless loop :s)
[ -z "$2" ] && die_error "ask_option \$2 must be the title"
# $3 is optional more info
- [ -z "$5" ] && debug "_dia_ask_option args: $@" && die_error "ask_option makes only sense if you specify at least one option (with tag and name)" #nothing wrong with only 1 option. it still shows useful info to the user
+ TYPE=${4:-required}
+ [ "$TYPE" != required -a "$TYPE" != optional ] && debug 'UI' "_dia_ask_option args: $@" && die_error "ask option \$4 must be required or optional or ''. not $TYPE"
+ [ -z "$6" ] && debug 'UI' "_dia_ask_option args: $@" && die_error "ask_option makes only sense if you specify at least one option (with tag and name)" #nothing wrong with only 1 option. it still shows useful info to the user
MENU_TITLE=$2
EXTRA_INFO=$3
- shift 3
+ shift 4
echo "$MENU_TITLE"
[ -n "$EXTRA_INFO" ] && echo "$EXTRA_INFO"
@@ -493,14 +552,20 @@ _cli_ask_option ()
echo "$1 ] $2"
shift 2
done
- echo "CANCEL ] CANCEL"
+ CANCEL_LABEL=CANCEL
+ [ $TYPE == optional ] && CANCEL_LABEL=SKIP
+ echo "$CANCEL_LABEL ] $CANCEL_LABEL"
[ -n "$DEFAULT" ] && echo -n " > [ $DEFAULT ] "
[ -z "$DEFAULT" ] && echo -n " > "
read ANSWER_OPTION
+ ret=0
[ -z "$ANSWER_OPTION" -a -n "$DEFAULT" ] && ANSWER_OPTION="$DEFAULT"
- debug "cli_ask_option: User choose $ANSWER_OPTION ($MENU_TITLE)"
- [ "$ANSWER_OPTION" = CANCEL ] && return 1
- return 0
+ [ "$ANSWER_OPTION" == CANCEL ] && ret=1 && ANSWER_OPTION=
+ [ "$ANSWER_OPTION" == SKIP ] && ret=0 && ANSWER_OPTION=
+ [ -z "$ANSWER_OPTION" -a "$TYPE" == required ] && ret=1
+
+ debug 'UI' "cli_ask_option: ANSWER_OPTION: $ANSWER_OPTION, returncode (skip/cancel): $ret ($MENU_TITLE)"
+ return $ret
}
@@ -532,7 +597,7 @@ _cli_ask_string ()
[ -n "$2" ] && echo "(Press enter for default. Default: $2)"
echo -n ">"
read ANSWER_STRING
- debug "cli_ask_string: User entered: $ANSWER_STRING"
+ debug 'UI' "cli_ask_string: User entered: $ANSWER_STRING"
if [ -z "$ANSWER_STRING" ]
then
if [ -n "$2" ]
@@ -562,10 +627,10 @@ _cli_ask_yesno ()
answer=`tr '[:upper:]' '[:lower:]' <<< $answer`
if [ "$answer" = y -o "$answer" = yes ] || [ -z "$answer" -a "$2" = yes ]
then
- debug "cli_ask_yesno: User picked YES"
+ debug 'UI' "cli_ask_yesno: User picked YES"
return 0
else
- debug "cli_ask_yesno: User picked NO"
+ debug 'UI' "cli_ask_yesno: User picked NO"
return 1
fi
}
@@ -576,6 +641,43 @@ _cli_follow_progress ()
title=$1
logfile=$2
echo "Title: $1"
- tail -f $2
- #TODO: don't block anymore when it's done
+ [ -n "$3" ] && tail -f $2 --pid=$3
+ [ -z "$3" ] && tail -f $2
+}
+
+set_keymap ()
+{
+ KBDDIR="/usr/share/kbd"
+
+ KEYMAPS=
+ for i in $(find $KBDDIR/keymaps -name "*.gz" | sort); do
+ KEYMAPS="$KEYMAPS ${i##$KBDDIR/keymaps/} -"
+ done
+ ask_option "${var_KEYMAP:-no}" "Select A Keymap" '' optional $KEYMAPS
+ if [ -n "$ANSWER_OPTION" ]
+ then
+ loadkeys -q $KBDDIR/keymaps/$ANSWER_OPTION
+ var_KEYMAP=$ANSWER_OPTION
+ echo "$var_KEYMAP" > $RUNTIME_DIR/aif-keymap
+ fi
+
+ FONTS=
+ # skip .cp.gz and partialfonts files for now see bug #6112, #6111
+ for i in $(find $KBDDIR/consolefonts -maxdepth 1 ! -name '*.cp.gz' -name "*.gz" | sed 's|^.*/||g' | sort); do
+ FONTS="$FONTS $i -"
+ done
+ ask_option "${var_CONSOLEFONT:-no}" "Select A Console Font" '' optional $FONTS
+ if [ -n "$ANSWER_OPTION" ]
+ then
+ var_CONSOLEFONT=$ANSWER_OPTION
+ for i in 1 2 3 4
+ do
+ if [ -d /dev/vc ]; then
+ setfont $KBDDIR/consolefonts/$var_CONSOLEFONT -C /dev/vc/$i
+ else
+ setfont $KBDDIR/consolefonts/$var_CONSOLEFONT -C /dev/tty$i
+ fi
+ done
+ echo "$var_CONSOLEFONT" > $RUNTIME_DIR/aif-consolefont
+ fi
}
diff --git a/src/core/procedures/automatic b/src/core/procedures/automatic
index 3c93167..b0e327a 100644
--- a/src/core/procedures/automatic
+++ b/src/core/procedures/automatic
@@ -1,24 +1,32 @@
#!/bin/bash
-# This procedure is EARLY in development!!
# This is a procedure for automatic deployment/installation/configuration of systems. # TODO: document! (readme, notes about deployment profiles, examples, ...)
+# check /usr/share/aif/examples for some example config files.
+# This procedure can easily replace the old quickinst script if you look at the "generic install" config file
+# Look at the base procedure to see the phases and which workers they'll execute.
+# It should be:
+# phase_preparation=(configure intro sysprep select_source runtime_network runtime_repositories runtime_packages)
+# phase_basics=(set_clock prepare_disks)
+# phase_system=(package_list install_packages auto_fstab auto_networkTODO auto_locale auto_keymap_font configure_system mkinitcpio locales install_bootloader)
+# phase_finish=(msg_report)
# In theory, the only manual thing should maybe be configuring the runtime network and putting the configfile in place
# TODO: I don't know if you can do non-interactive dm_crypt stuff.. maybe by pulling luks keyfiles from svn/git/..?
+# TODO: for worker_configure_system, we probably want the user to specify hostname, root pass etc.
+# TODO: implement setting hostname, keymap, consolefont, network settings
+# for a list of recognized variables, see examples/generic-install-on-sda
depend_procedure core base
var_OPTS_STRING="c:"
-var_ARGS_USAGE="-c <config>: Specify a configfile (profile) to be used (optional)" #if we need some settings that we're missing, we'll ask for them
-
-phase_preparation+=(runtime_settings)
-phase_preparation+=(msg_automatic) # this can happen probably a bit earlier..
-phase_preparation+=(fetch_configs)
+var_ARGS_USAGE="-c <config>: Specify a configfile (profile) to be used"
+var_AUTOMATIC_PROFILE=""
+# TODO: if the user does aif -p automatic -c, then $1 is ":-" ??? if you do -c <something> then it's ok.
process_args ()
{
if [ "$1" = '-c' ]
then
[ -z "$2" ] && die_error "You must specify a config"
- source $2 || die_error "Could not source config $2"
+ var_AUTOMATIC_PROFILE=$2
else
usage
exit 5
@@ -28,69 +36,51 @@ process_args ()
worker_intro ()
{
- notify "Automatic procedure running..."
+ notify "Automatic procedure running profile $var_AUTOMATIC_PROFILE ..."
}
worker_configure ()
{
var_UI_TYPE=${arg_ui_type:-cli}
+ [ -z "$var_AUTOMATIC_PROFILE" ] && die_error "You must specify a config file to use this procedure"
+ source $var_AUTOMATIC_PROFILE || die_error "Could not source config $var_AUTOMATIC_PROFILE"
+ # Check mandatory options
+ [ -z "$PARTITIONS" ] && die_error "You did not specify a partition scheme"
+ [ -z "$BLOCKDATA" ] && die_error "You did not specify a partition scheme"
+ [ -z "$GRUB_DEVICE" ] && die_error "You did not specify a grub device"
+ # initialize internal variables based on variables set by the user (some of the vars are handled in other workers):
+ var_RUNTIME_REPOSITORIES=$RUNTIME_REPOSITORIES
+ var_RUNTIME_PACKAGES=$RUNTIME_PACKAGES
+ var_GRUB_DEVICE=$GRUB_DEVICE
+ var_PARTITIONS=$PARTITIONS
+ var_BLOCKDATA=$BLOCKDATA
}
-
-# not used
-worker_msg_manual ()
-{
- notify "A few manual things need to happen first..."
-}
-
-
-worker_msg_automatic ()
-{
- notify "**** From now on. everything will be automatic. Enjoy the show!" # not true: you need pass for dm_crypt
-}
-
-
-worker_fetch_configs ()
+worker_select_source ()
{
- true
+ var_PKG_SOURCE_TYPE=${SOURCE:-cd}
+ var_FILE_URL=${FILE_URL:-file:///src/core/pkg}
+ var_SYNC_URL=${SYNC_URL:-}
}
-
worker_runtime_network ()
{
- if ask_yesno "Do you want to (re)-configure your networking?"
- then
- interactive_runtime_network
- else
- infofy "Ok. skipping network config"
- fi
-}
-
-
-# Check if we have all needed settings loaded from the profile
-worker_runtime_settings ()
-{
- if check_is_in $var_RUNTIME_PACKAGES svn
- then
- [ -z "$SVN_USERNAME" ] && ask_string "Please enter your svn username" && SVN_USERNAME=$ANSWER_STRING
- [ -z "$SVN_PASSWORD" ] && ask_password svn #TODO: if user entered incorrect password, the install process will just fail..
- [ -z "$SVN_BASE" ] && ask_string "What's the base path of your svn repo? (no ending /) " && SVN_BASE=$ANSWER_STRING
- [ -z "$DEPLOY_CLASS" ] && ask_string "Which hostclass are you installing? (optional)" '' 0 && DEPLOY_CLASS=$ANSWER_STRING
- SVN="svn --username $SVN_USERNAME --password $SVN_PASSWORD"
- elif check_is_in $var_RUNTIME_PACKAGES moo
- then
- # Maybe more stuff later
- true
- fi
- [ -z "$HOSTNAME" ] && ask_string "Hostname of target system?" && HOSTNAME=$ANSWER_STRING
-
- return 0
+ true # for now. we assume the user has taken care of this himself already. doing this interactively wouldn't be a good default anyway.
+ # maybe check if network works, if not, try dhcp. let user override by using a static config in his config file
+ #if ask_yesno "Do you want to (re)-configure your networking?"
+ #then
+ # interactive_runtime_network
+ #else
+ # infofy "Ok. skipping network config"
+ #fi
}
worker_prepare_disks ()
{
+ echo "$var_PARTITIONS" > $TMP_PARTITIONS
+ echo "$var_BLOCKDATA" > $TMP_BLOCKDEVICES
process_disks || die_error "Could not process_disks"
if ! process_filesystems
then
@@ -105,31 +95,35 @@ worker_prepare_disks ()
true
}
+worker_package_list ()
+{
+ var_TARGET_PACKAGES=$TARGET_PACKAGES
+ var_TARGET_GROUPS=$TARGET_GROUPS
+ [ -z "$var_TARGET_PACKAGES" -a -z "$var_TARGET_GROUPS" ] && var_TARGET_GROUPS=base
+}
+
worker_install_packages ()
{
target_prepare_pacman core extra community #TODO: it would be better if this was a separate worker, i think
- [ -z "$TARGET_PACKAGES" ] && die_error "No packages listed to be installed!"
installpkg
}
worker_set_clock ()
{
- #timezone="Europe/Brussels"
- #Not doing anything. hwclock is set already and configs are coming from svn anyway..
+ #TODO implement this
true
}
-worker_install_bootloader ()
-{
- install-grub /dev/sda
+worker_auto_network () {
+ # temporary override because i need to implement this
+ true
}
-worker_runtime_yaourt ()
+worker_install_bootloader ()
{
- _yaourt_replace_pacman
+ grub-install $var_GRUB_DEVICE --root-directory=/mnt
}
-
diff --git a/src/core/procedures/base b/src/core/procedures/base
index c22a01c..6d99421 100644
--- a/src/core/procedures/base
+++ b/src/core/procedures/base
@@ -5,7 +5,7 @@ var_DEFAULTFS="/boot:32:ext2:+ swap:256:swap /:7500:ext3 /home:*:ext3"
var_TARGET_DIR="/mnt" # When overriding this, do _not_ add a trailing /. It's not needed and maybe you could even break something
var_RUNTIME_REPOSITORIES= # array like this ('name1' 'location of repo 1' ['name2' 'location of repo2',..])
var_RUNTIME_PACKAGES=
-var_PKG_FILE=$RUNTIME_DIR/package-list # not used by default in base/interactive. can be used by custom procedures or profiles for the automatic procedure
+var_PKG_FILE=$RUNTIME_DIR/aif-package-list # not used by default in base/interactive. can be used by custom procedures or profiles for the automatic procedure
var_MIRRORLIST="/etc/pacman.d/mirrorlist"
var_UI_TYPE="cli" # set to cli or dia for dialog
var_ARCH=`uname -m` #i686 or x86_64. NOTE: this assumes you want to install the same arch as the installation environment you're using. maybe we could decouple those someday..
@@ -31,6 +31,7 @@ phase_system=(\
auto_fstab \
auto_network \
auto_locale \
+ auto_keymap_font \
configure_system \
mkinitcpio \
locales \
@@ -101,7 +102,29 @@ worker_runtime_packages ()
worker_set_clock ()
{
- interactive_set_clock
+ while true; do
+ default=no
+ [ -n "$NEXTITEM" ] && default="$NEXTITEM"
+ ask_option $default "Date/time configuration" '' required \
+ "1" "Select region and timezone" \
+ "2" "Set time and date" \
+ "3" "Return to Main Menu"
+ [ "$ANSWER_OPTION" = 1 ] && execute worker interactive_timezone && NEXTITEM=2
+ [ "$ANSWER_OPTION" = 2 ] && check_depend worker interactive_timezone && execute worker interactive_time && NEXTITEM=3
+ [ "$ANSWER_OPTION" = 3 ] && break
+ done
+}
+
+
+worker_interactive_timezone ()
+{
+ interactive_timezone
+}
+
+
+worker_interactive_time ()
+{
+ interactive_time
}
@@ -112,18 +135,16 @@ worker_prepare_disks ()
}
-# Put the list of packages to be installed in $TARGET_PACKAGES
+# Put the list of packages to be installed in $var_TARGET_PACKAGES and $var_TARGET_GROUPS
worker_package_list ()
{
- #TODO: sensible list of packages. maybe just 'base'
- true
+ var_TARGET_GROUPS=base
}
worker_install_packages ()
{
target_prepare_pacman core #TODO: it would be better if this was a separate worker, i think
- [ -z "$TARGET_PACKAGES" ] && die_error "No packages listed to be installed!"
installpkg
}
@@ -143,10 +164,15 @@ worker_auto_network ()
worker_auto_locale ()
{
- target_configure_inital_locale
+ target_configure_initial_locale
}
+worker_auto_keymap_font ()
+{
+ target_configure_initial_keymap_font
+}
+
worker_configure_system ()
{
#TODO: what to do here?
diff --git a/src/core/procedures/interactive b/src/core/procedures/interactive
index 051d187..86e3d63 100644
--- a/src/core/procedures/interactive
+++ b/src/core/procedures/interactive
@@ -53,7 +53,7 @@ mainmenu()
[ -n "$NEXTITEM" ] && default="$NEXTITEM"
#TODO: why does a '2' appear instead of '' ??
- ask_option $default "MAIN MENU" '' \
+ ask_option $default "MAIN MENU" '' required \
"1" "$worker_select_source_title" \
"2" "$worker_set_clock_title" \
"3" "$worker_prepare_disks_title" \
@@ -78,7 +78,8 @@ mainmenu()
check_depend worker package_list && \
check_depend worker select_source && execute worker install_packages && { execute worker auto_fstab ; \
ended_ok worker runtime_network && execute worker auto_network ; \
- execute worker auto_locale ; } && NEXTITEM=6 ;;
+ execute worker auto_locale ; \
+ execute worker auto_keymap_font; } && NEXTITEM=6 ;;
"6")
check_depend worker install_packages && execute worker configure_system && { execute worker mkinitcpio ; \
execute worker locales ;
@@ -96,7 +97,7 @@ mainmenu()
select_source_extras_menu ()
{
while true; do
- ask_option no "FTP Installation" 'Make sure the network is ok before continuing the installer' \
+ ask_option no "FTP Installation" 'Make sure the network is ok before continuing the installer' required \ #TODO: display the "make sure network is okay" in a better way
"1" "$worker_runtime_network_title" \
"2" "$worker_select_mirror_title" \
"3" "Return to Main Menu"
@@ -114,7 +115,7 @@ worker_configure_system()
# /etc/pacman.d/mirrorlist
# add installer-selected mirror to the top of the mirrorlist
if [ "$var_PKG_SOURCE_TYPE" = "ftp" -a "${var_SYNC_URL}" != "" ]; then
- debug "Adding choosen mirror (${var_SYNC_URL}) to ${var_TARGET_DIR}/$var_MIRRORLIST"
+ debug 'PROCEDURE' "Adding choosen mirror (${var_SYNC_URL}) to ${var_TARGET_DIR}/$var_MIRRORLIST"
mirrorlist=`awk "BEGIN { printf(\"# Mirror used during installation\nServer = "${var_SYNC_URL}"\n\n\") } 1 " "${var_TARGET_DIR}/$var_MIRRORLIST"`
echo "$mirrorlist" > "${var_TARGET_DIR}/$var_MIRRORLIST" #TODO: test this, this may not work
fi
@@ -147,7 +148,8 @@ worker_prepare_disks()
default=no
[ -n "$NEXTITEM" ] && default="$NEXTITEM"
- ask_option $default "Prepare Hard Drive" '' \
+ #TODO: inform user (using dialog's --item-help or so) that autoprepare uses 1 disk and uses it in a "fairly regular" (though somewhat customizable) manner.
+ ask_option $default "Prepare Hard Drive" '' required \
"1" "Auto-Prepare (erases the ENTIRE hard drive and sets up partitions and filesystems)" \
"2" "Partition Hard Drives" \
"3" "Configure block devices, filesystems and mountpoints" \
@@ -246,7 +248,7 @@ worker_select_mirror ()
worker_install_bootloader ()
{
- ask_option Grub "Choose bootloader" "Which bootloader would you like to use? Grub is the Arch default." \
+ ask_option Grub "Choose bootloader" "Which bootloader would you like to use? Grub is the Arch default." required \
"Grub" "Use the GRUB bootloader (default)" \
"None" "\Zb\Z1Warning\Z0\ZB: you must install your own bootloader!"
diff --git a/src/core/procedures/partial-keymap b/src/core/procedures/partial-keymap
new file mode 100644
index 0000000..ad81727
--- /dev/null
+++ b/src/core/procedures/partial-keymap
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+start_process ()
+{
+ var_UI_TYPE=dia
+ set_keymap
+}
diff --git a/src/core/procedures/quickinst b/src/core/procedures/quickinst
deleted file mode 100644
index b95bfa4..0000000
--- a/src/core/procedures/quickinst
+++ /dev/null
@@ -1,140 +0,0 @@
-#!/bin/bash
-depend_procedure core base
-
-# This is a port of the original /arch/quickinst script.
-
-# TODO: nowhere rely on /tmp
-
-
-# TODO: find a way to make profilespecific arguments and usage function work (see src/aif.sh)
-usage() {
- echo "quickinst <install_mode> <destdir> <package_directory|server_url>"
- echo
- echo "This script is for users who would rather partition/mkfs/mount their target"
- echo "media manually than go through the routines in the setup script."
- echo
- echo "First make sure you have all your filesystems mounted under <destdir>."
- echo "e.g. mount -t iso9660 /dev/sdc or /dev/sr0 (for new naming sheme) /src "
- echo "Then run this script to install all base packages to <destdir>."
- echo
- if [ -e /usr/bin/wget ]; then
- echo "<install_mode> must be either 'ftp' or 'cd'"
- else
- echo "<install_mode> must be 'cd'"
- fi
- echo
- echo "Examples:"
- if [ -e /usr/bin/wget ]; then
- echo " quickinst ftp /mnt ftp://ftp.archlinux.org/core/os/$var_ARCH"
- fi
-
- echo " quickinst cd /mnt /src/core/pkg"
- echo ""
- exit 0
-}
-
-
-# TODO: implement correctly
-worker_configure ()
-{
-# var_PKG_SOURCE_TYPE
-# var_TARGET_DIR
-# var_FILE_URL or var_SYNC_URL
-}
-
-# TODO: clean up everything below this
-
-PACMAN=
-[ -f /tmp/usr/bin/pacman.static ] && PACMAN=/tmp/usr/bin/pacman.static
-[ -f /usr/bin/pacman.static ] && PACMAN=/usr/bin/pacman.static
-if [ "$PACMAN" = "" ]; then
- cd /tmp
- if [ "$INSTMODE" = "ftp" ]; then
- echo "Downloading pacman..."
- wget $PKGARG/pacman*.pkg.tar.gz
- if [ $? -gt 0 ]; then
- echo "error: Download failed"
- exit 1
- fi
- tar -xzf pacman*.pkg.tar.gz
- elif [ "$INSTMODE" = "cd" ]; then
- echo "Unpacking pacman..."
- tar -xzf $PKGARG/pacman*.pkg.tar.gz
- fi
-fi
-[ -f /tmp/usr/bin/pacman.static ] && PACMAN=/tmp/usr/bin/pacman.static
-if [ "$PACMAN" = "" ]; then
- echo "error: Cannot find the pacman.static binary!"
- exit 1
-fi
-
-if [ "$INSTMODE" = "ftp" ]; then
- echo "[core]" >/tmp/pacman.conf
- echo "Server = $PKGARG" >>/tmp/pacman.conf
- mkdir -p $DESTDIR/var/cache/pacman/pkg /var/cache/pacman >/dev/null 2>&1
- rm -f /var/cache/pacman/pkg >/dev/null 2>&1
- ln -sf $DESTDIR/var/cache/pacman/pkg /var/cache/pacman/pkg >/dev/null 2>&1
-fi
-
-if [ "$INSTMODE" = "cd" ]; then
- echo "[core]" >/tmp/pacman.conf
- echo "Server = file://$PKGARG" >>/tmp/pacman.conf
- mkdir -p $DESTDIR/var/cache/pacman/pkg /var/cache/pacman >/dev/null 2>&1
- rm -f /var/cache/pacman/pkg >/dev/null 2>&1
- ln -sf $PKGARG /var/cache/pacman/pkg >/dev/null 2>&1
-fi
-
-! [ -d $DESTDIR/var/lib/pacman ] && mkdir -p $DESTDIR/var/lib/pacman
-! [ -d /var/lib/pacman ] && mkdir -p /var/lib/pacman
-# mount proc/sysfs first, so mkinitrd can use auto-detection if it wants
-! [ -d $DESTDIR/proc ] && mkdir $DESTDIR/proc
-! [ -d $DESTDIR/sys ] && mkdir $DESTDIR/sys
-! [ -d $DESTDIR/dev ] && mkdir $DESTDIR/dev
-mount -t proc none $DESTDIR/proc
-mount -t sysfs none $DESTDIR/sys
-mount -o bind /dev $DESTDIR/dev
-$PACMAN -r $DESTDIR --config /tmp/pacman.conf -Sy base
-umount $DESTDIR/proc $DESTDIR/sys $DESTDIR/dev
-if [ $? -gt 0 ]; then
- echo
- echo "Package installation FAILED."
- echo
- exit 1
-fi
-
-echo
-echo "Package installation complete."
-echo
-echo "Please install a bootloader. Edit the appropriate config file for"
-echo "your loader, and chroot into your system to install it into the"
-echo "boot sector:"
-echo " # mount -o bind /dev $DESTDIR/dev"
-echo " # mount -t proc none $DESTDIR/proc"
-echo " # mount -t sysfs none $DESTDIR/sys"
-echo " # chroot $DESTDIR /bin/bash"
-echo
-echo "For GRUB:"
-echo " # install-grub /dev/sda /dev/sdaX (replace with your boot partition)"
-echo " (or install manually by invoking the GRUB shell)"
-echo "HINT XFS FILESYSTEM:"
-echo "If you have created xfs filesystems, freeze them before and unfreeze them after"
-echo "installing grub (outside the chroot):"
-echo "- freeze:"
-echo " # xfs_freeze -f $DESTDIR/boot"
-echo " # xfs_freeze -f $DESTDIR/"
-echo "- unfreeze:"
-echo " # xfs_freeze -u $DESTDIR/boot"
-echo " # xfs_freeze -u $DESTDIR/"
-echo
-echo "For LILO:"
-echo " # lilo"
-echo
-echo "Next step, initramfs setup:"
-echo "Edit your /etc/mkinitcpio.conf and /etc/mkinitcpio.d/kernel26-fallback.conf"
-echo "to fit your needs. After that run:"
-echo "# mkinitcpio -p kernel26"
-echo
-echo "Then exit your chroot shell, edit $DESTDIR/etc/fstab and"
-echo "$DESTDIR/etc/rc.conf, and reboot!"
-echo
-exit 0