mirror of
https://github.com/libretro/Lakka-LibreELEC.git
synced 2025-02-01 03:02:31 +00:00
588ee556e2
update to 10.95.001 - LibreELEC 11 beta 1
505 lines
15 KiB
Bash
Executable File
505 lines
15 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
|
|
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
|
|
|
# some DOCs:
|
|
|
|
# list devices:
|
|
# cat /proc/partitions | sed -n "s/\ *[0-9][0-9]*\ *[0-9][0-9]*\ *[0-9][0-9]*\ \([a-z]*\)$/\1/p"
|
|
|
|
# list all partitionnumbers from /dev/sda:
|
|
# parted -m /dev/sda print | grep -v ^/dev | grep -v ^BYT | cut -f1 -d ":"
|
|
|
|
# list device data from /dev/sda:
|
|
# parted -m /dev/sda print | grep /dev/sda
|
|
|
|
# list mounted partitions:
|
|
# mount | grep ^/dev
|
|
|
|
# list modelnumber:
|
|
# parted -m /dev/sda print | grep /dev/sda | cut -f7 -d ":" | sed "s/;//"
|
|
# list size:
|
|
# parted -m /dev/sda print | grep /dev/sda | cut -f2 -d ":"
|
|
|
|
# exclude mounted partitions
|
|
# for i in `cat /proc/mounts | grep ^/dev/ | cut -f1 -d " " | sed "s/[0-9]//"`; do TEST="$TEST `echo "| grep -v $i"`"; done
|
|
|
|
# disable Ctrl+C - can be very dangerous
|
|
trap '' 2
|
|
|
|
[ -f /etc/installer.conf ] && . /etc/installer.conf || exit 0
|
|
|
|
dbglg() {
|
|
# Acts just like echo cmd, with automatic redirection
|
|
|
|
echo "" >> $LOGFILE
|
|
echo "#################################################################" >> $LOGFILE
|
|
echo "# $@" >> $LOGFILE
|
|
echo "#################################################################" >> $LOGFILE
|
|
echo "" >> $LOGFILE
|
|
}
|
|
|
|
log_system_status() {
|
|
echo "# cat /proc/mounts"
|
|
cat /proc/mounts
|
|
echo
|
|
|
|
echo "# df"
|
|
df
|
|
echo
|
|
|
|
echo "# df -h"
|
|
df -h
|
|
echo
|
|
|
|
echo "# parted -s -m -l"
|
|
parted -s -m -l
|
|
echo
|
|
|
|
echo "# blkid"
|
|
blkid
|
|
echo
|
|
|
|
echo "# UEFI (if directory exists)"
|
|
ls -la /sys/firmware/efi
|
|
echo
|
|
|
|
echo "# Disk sizes (bytes)"
|
|
grep . /sys/block/*/size
|
|
echo
|
|
}
|
|
|
|
get_device_unmount() {
|
|
# get all unmounted devices
|
|
# usage: get_devices_unmount
|
|
# uses: -
|
|
# provides: DEVICES
|
|
|
|
DEVICES=""
|
|
DEVICES=$(parted -s -m -l 2>/dev/null | grep -E '^/dev/sd|^/dev/mmcblk|^/dev/nvme' | grep -E -v '^[^:]*rpmb|^[^:]*boot' | cut -f1 -d ":")
|
|
|
|
for i in $(cat /proc/mounts | grep -E '^/dev/sd' | cut -f1 -d " " | sed "s/[0-9].*$//"); do
|
|
DEVICES=$(echo $DEVICES | sed -e "s|$i||")
|
|
done
|
|
|
|
for i in $(cat /proc/mounts | grep -E '^/dev/mmcblk' | cut -f1 -d " " | sed "s/p.*$//"); do
|
|
DEVICES=$(echo $DEVICES | sed -e "s|$i||")
|
|
done
|
|
|
|
for i in $(cat /proc/mounts | grep -E '^/dev/nvme' | cut -f1 -d " " | sed "s/p.*$//"); do
|
|
DEVICES=$(echo $DEVICES | sed -e "s|$i||")
|
|
done
|
|
}
|
|
|
|
get_partition() {
|
|
# get all partitions of a specifed device
|
|
# usage: get_partitions /dev/sda
|
|
# uses: -
|
|
# provides: PARTITIONS
|
|
|
|
PARTITIONS=$(parted -s -m $1 print | grep -v ^/dev | grep -v BYT | cut -f1 -d ":")
|
|
}
|
|
|
|
create_device_list() {
|
|
# creates device list to use in menus
|
|
# usage: create_devices_list
|
|
# uses: get_device_unmount
|
|
# provides: DEVICE_MODEL, DEVICE_SIZE, DEVICE_LIST, DEVICE_NAME,
|
|
# DEVICES (get_device_unmount)
|
|
|
|
DEVICE_MODEL=""
|
|
DEVICE_SIZE=""
|
|
DEVICE_LIST=""
|
|
DEVICE_NAME=""
|
|
|
|
get_device_unmount
|
|
|
|
if [ "$DEVICES" = "" ]; then
|
|
msg_no_device
|
|
return 1
|
|
fi
|
|
|
|
for i in $DEVICES; do
|
|
DEVICE_MODEL=$(parted -s $i -m print | grep ^$i | cut -f7 -d ":" | sed "s/;//")
|
|
DEVICE_SIZE=$(parted -s $i -m print | grep ^$i | cut -f2 -d ":")
|
|
DEVICE_NAME=$(echo $DEVICE_MODEL ${DEVICE_SIZE} | sed 's/ /_/g')
|
|
DEVICE_LIST="$DEVICE_LIST $i $DEVICE_NAME"
|
|
done
|
|
return 0
|
|
}
|
|
|
|
do_install_quick() {
|
|
# show menu
|
|
MSG_TITLE="QUICK INSTALL MENU"
|
|
MSG_MENU="\nUse the up/down arrows to select the device you wish to install to.\n\nPlease select a device:"
|
|
MSG_CANCEL="Back"
|
|
|
|
create_device_list || return
|
|
|
|
whiptail --backtitle "$BACKTITLE" --cancel-button "$MSG_CANCEL" \
|
|
$DIALOG_OPTIONS --title "$MSG_TITLE" --menu "$MSG_MENU" 20 50 5 \
|
|
$DEVICE_LIST 2> $TMPDIR/device_for_install
|
|
[ $? -ne 0 ] && return
|
|
|
|
# now we must do everything
|
|
INSTALL_DEVICE=$(cat "$TMPDIR/device_for_install")
|
|
INSTALL_DEVICE_FULL=$(echo $DEVICE_LIST | sed "s|.*$INSTALL_DEVICE \([^ ]*\).*|$INSTALL_DEVICE \1|")
|
|
|
|
case $INSTALL_DEVICE in
|
|
"/dev/mmcblk"*|"/dev/nvme"*)
|
|
PART1="p1"
|
|
PART2="p2"
|
|
;;
|
|
*)
|
|
PART1="1"
|
|
PART2="2"
|
|
;;
|
|
esac
|
|
|
|
prompt_gpt
|
|
prompt_backup_unpack
|
|
|
|
# check for confirmation (twice!)
|
|
MSG_TITLE="Confirmation before installing"
|
|
MSG_DETAIL="\nIf you continue the contents of the target disk will be wiped out:\n\n$INSTALL_DEVICE_FULL\n\n"
|
|
DIALOG_OPTIONS="--defaultno"
|
|
whiptail --backtitle "$BACKTITLE" --title "$MSG_TITLE" \
|
|
$DIALOG_OPTIONS --yesno "$MSG_DETAIL" 0 0
|
|
[ $? -ne 0 ] && return
|
|
|
|
MSG_TITLE="Confirmation before installing"
|
|
MSG_DETAIL="\nThis is last chance to abort the installation!\n\nIf you continue the target disk will be wiped out:\n\n$INSTALL_DEVICE_FULL\n\n\n"
|
|
DIALOG_OPTIONS="--defaultno"
|
|
whiptail --backtitle "$BACKTITLE" --title "$MSG_TITLE" \
|
|
$DIALOG_OPTIONS --yesno "$MSG_DETAIL" 0 0
|
|
[ $? -ne 0 ] && return
|
|
|
|
# start the progress bar (whiptail --gauge)
|
|
{
|
|
# remove all partitions
|
|
msg_progress_install "1" "Get all partitions $INSTALL_DEVICE"
|
|
get_partition $INSTALL_DEVICE 2>>$LOGFILE
|
|
|
|
msg_progress_install "5" "Wiping disk $INSTALL_DEVICE"
|
|
dd if=/dev/zero of=$INSTALL_DEVICE bs=4096 count=1024 2>>$LOGFILE
|
|
|
|
# create 2 new partitions (first $PARTSIZE_SYSTEM, second rest)
|
|
msg_progress_install "7" "Creating label on $INSTALL_DEVICE"
|
|
if [ "$GPT" = "1" ]; then
|
|
parted -s $INSTALL_DEVICE mklabel gpt >> $LOGFILE 2>&1
|
|
else
|
|
parted -s $INSTALL_DEVICE mklabel msdos >> $LOGFILE 2>&1
|
|
fi
|
|
|
|
msg_progress_install "9" "Writing Master Boot Record on $INSTALL_DEVICE"
|
|
if [ "$GPT" = "1" ]; then
|
|
cat /usr/share/syslinux/gptmbr.bin > $INSTALL_DEVICE
|
|
else
|
|
cat /usr/share/syslinux/mbr.bin > $INSTALL_DEVICE
|
|
fi
|
|
|
|
partsize_system_start=$PARTSIZE_SYSTEM_OFFSET
|
|
partsize_system_end=$(((PARTSIZE_SYSTEM * 1024 * 1024 / 512) + partsize_system_start - 1))
|
|
partsize_storage_start=$((partsize_system_end + 1))
|
|
partsize_storage_end=-1024
|
|
|
|
msg_progress_install "10" "Creating partition on $INSTALL_DEVICE"
|
|
if [ "$GPT" = "1" ]; then
|
|
parted -s $INSTALL_DEVICE unit s mkpart $DISKLABEL_SYSTEM fat16 -- $partsize_system_start $partsize_system_end >> $LOGFILE 2>&1
|
|
else
|
|
parted -s $INSTALL_DEVICE unit s mkpart primary fat16 -- $partsize_system_start $partsize_system_end >> $LOGFILE 2>&1
|
|
fi
|
|
|
|
msg_progress_install "13" "Creating partition on $INSTALL_DEVICE"
|
|
if [ "$GPT" = "1" ]; then
|
|
parted -s $INSTALL_DEVICE unit s mkpart $DISKLABEL_STORAGE ext4 -- $partsize_storage_start $partsize_storage_end >> $LOGFILE 2>&1
|
|
else
|
|
parted -s $INSTALL_DEVICE unit s mkpart primary ext4 -- $partsize_storage_start $partsize_storage_end >> $LOGFILE 2>&1
|
|
fi
|
|
|
|
msg_progress_install "16" "Setup bootflag on partition 1 of $INSTALL_DEVICE"
|
|
parted -s $INSTALL_DEVICE set 1 boot on >> $LOGFILE 2>&1
|
|
if [ "$GPT" = "1" ]; then
|
|
parted -s $INSTALL_DEVICE set 1 legacy_boot on >> $LOGFILE 2>&1
|
|
fi
|
|
|
|
msg_progress_install "20" "Tell the kernel we have a new partition table on $INSTALL_DEVICE"
|
|
partprobe $INSTALL_DEVICE >> $LOGFILE 2>&1
|
|
|
|
# create filesystem
|
|
msg_progress_install "23" "Creating filesystem on ${INSTALL_DEVICE}1"
|
|
mkfs.vfat -F 16 ${INSTALL_DEVICE}${PART1} >> $LOGFILE 2>&1
|
|
|
|
msg_progress_install "25" "Set uuid and disklabel $DISKLABEL_SYSTEM on ${INSTALL_DEVICE}${PART1}"
|
|
dosfslabel ${INSTALL_DEVICE}${PART1} $DISKLABEL_SYSTEM >> $LOGFILE 2>&1
|
|
|
|
msg_progress_install "28" "Creating filesystem on ${INSTALL_DEVICE}${PART2}"
|
|
mke2fs -t ext4 -m 0 ${INSTALL_DEVICE}${PART2} >> $LOGFILE 2>&1
|
|
|
|
msg_progress_install "30" "Set uuid and disklabel $DISKLABEL_STORAGE on ${INSTALL_DEVICE}${PART2}"
|
|
tune2fs -U random -L $DISKLABEL_STORAGE ${INSTALL_DEVICE}${PART2} >> $LOGFILE 2>&1
|
|
|
|
UUID_SYSTEM="$(blkid --output udev ${INSTALL_DEVICE}${PART1} | grep ^ID_FS_UUID= | cut -d= -f2)"
|
|
UUID_STORAGE="$(blkid --output udev ${INSTALL_DEVICE}${PART2} | grep ^ID_FS_UUID= | cut -d= -f2)"
|
|
|
|
echo "" >> $LOGFILE
|
|
echo "UUID_SYSTEM : ${UUID_SYSTEM}" >> $LOGFILE
|
|
echo "UUID_STORAGE: ${UUID_STORAGE}" >> $LOGFILE
|
|
|
|
# mount system partition
|
|
msg_progress_install "35" "Creating $TMPDIR/part1"
|
|
mkdir -p $TMPDIR/part1 >> $LOGFILE 2>&1
|
|
|
|
msg_progress_install "40" "Mounting ${INSTALL_DEVICE}${PART1} to $TMPDIR/part1"
|
|
mount -t vfat ${INSTALL_DEVICE}${PART1} $TMPDIR/part1 >> $LOGFILE 2>&1
|
|
|
|
# installing syslinux
|
|
msg_progress_install "50" "Installing syslinux to $TMPDIR/part1"
|
|
syslinux -i ${INSTALL_DEVICE}${PART1} >> $LOGFILE 2>&1
|
|
|
|
# install system files
|
|
msg_progress_install "60" "Installing Kernel"
|
|
cp "/flash/$IMAGE_KERNEL" $TMPDIR/part1/KERNEL >> $LOGFILE 2>&1
|
|
|
|
msg_progress_install "65" "Installing System"
|
|
cp "/flash/$IMAGE_SYSTEM" $TMPDIR/part1/SYSTEM >> $LOGFILE 2>&1
|
|
sync
|
|
|
|
# configuring bootloader
|
|
msg_progress_install "80" "Setup bootloader with boot label = $DISKLABEL_SYSTEM and disk label = $DISKLABEL_STORAGE"
|
|
mkdir -p $TMPDIR/part1/EFI/BOOT
|
|
cat << EOF > $TMPDIR/part1/syslinux.cfg
|
|
DEFAULT linux
|
|
PROMPT 0
|
|
|
|
LABEL linux
|
|
KERNEL /KERNEL
|
|
APPEND boot=UUID=$UUID_SYSTEM disk=UUID=$UUID_STORAGE $SYSLINUX_PARAMETERS quiet
|
|
EOF
|
|
|
|
cat << EOF > $TMPDIR/part1/EFI/BOOT/grub.cfg
|
|
set timeout="0"
|
|
set default="LibreELEC"
|
|
|
|
menuentry "LibreELEC" {
|
|
search --set -f /KERNEL
|
|
linux /KERNEL boot=UUID=$UUID_SYSTEM disk=UUID=$UUID_STORAGE quiet
|
|
}
|
|
EOF
|
|
|
|
# uefi boot / hybrid mode
|
|
cp /usr/share/grub/bootia32.efi $TMPDIR/part1/EFI/BOOT
|
|
cp /usr/share/grub/bootx64.efi $TMPDIR/part1/EFI/BOOT
|
|
sync
|
|
|
|
# umount system partition, remove mountpoint
|
|
msg_progress_install "85" "Unmount $TMPDIR/part1"
|
|
umount $TMPDIR/part1 >> $LOGFILE 2>&1
|
|
|
|
msg_progress_install "87" "Remove $TMPDIR/part1"
|
|
rmdir $TMPDIR/part1 >> $LOGFILE 2>&1
|
|
|
|
if [ "$BACKUP_UNPACK" = "1" ]; then
|
|
# mount storage partition
|
|
msg_progress_install "89" "Creating $TMPDIR/part2"
|
|
mkdir -p $TMPDIR/part2 >> $LOGFILE 2>&1
|
|
|
|
msg_progress_install "90" "Mounting ${INSTALL_DEVICE}${PART2} to $TMPDIR/part2"
|
|
mount -t ext4 ${INSTALL_DEVICE}${PART2} $TMPDIR/part2 >> $LOGFILE 2>&1
|
|
|
|
msg_progress_install "92" "Restoring backup"
|
|
[ -f /flash/backup.tar.bz2 ] && tar -xjf /flash/backup.tar.bz2 -C $TMPDIR/part2 >> $LOGFILE 2>&1
|
|
[ -f /flash/backup.zip ] && unzip -qq /flash/backup.zip -d $TMPDIR/part2 >> $LOGFILE 2>&1
|
|
sync
|
|
|
|
# umount system partition, remove mountpoint
|
|
msg_progress_install "97" "Unmount $TMPDIR/part2"
|
|
umount $TMPDIR/part2 >> $LOGFILE 2>&1
|
|
|
|
msg_progress_install "100" "Remove $TMPDIR/part2"
|
|
rmdir $TMPDIR/part2 >> $LOGFILE 2>&1
|
|
fi
|
|
} | whiptail --backtitle "$BACKTITLE" --gauge "Please wait while your system is being setup ..." 6 73 0
|
|
|
|
# install complete
|
|
MSG_TITLE="@DISTRONAME@ Install Complete"
|
|
MSG_DETAIL="You may now remove the install media and reboot.\n"
|
|
whiptail --backtitle "$BACKTITLE" --title "$MSG_TITLE" --msgbox "$MSG_DETAIL" 7 52
|
|
}
|
|
|
|
msg_no_device() {
|
|
# show a warning dialog if we dont find not mounted devices for install and return to main menu
|
|
MSG_TITLE="WARNING"
|
|
MSG_INFOBOX=" No devices were found. "
|
|
|
|
whiptail --backtitle "$BACKTITLE" --title "$MSG_TITLE" --msgbox "$MSG_INFOBOX" 9 73
|
|
}
|
|
|
|
msg_progress_install() {
|
|
# update the whiptail gauge window
|
|
|
|
dbglg "$2"
|
|
sleep .3
|
|
echo XXX
|
|
echo $1
|
|
echo "$2 ..."
|
|
echo XXX
|
|
}
|
|
|
|
prompt_gpt() {
|
|
GPT="0"
|
|
UEFI="0"
|
|
# Get size in GB.
|
|
# 2^41 bytes is the DOS limit (2199023255552 bytes, 2.2TB). Use GUID Partition Table.>= 2200GB
|
|
INSTALL_DEVICE_SIZE=$(($(cat /sys/block/${INSTALL_DEVICE#/dev/}/size)*512/1000/1000/1000))
|
|
if [ "$INSTALL_DEVICE_SIZE" -ge 2200 ] 2>/dev/null; then
|
|
GPT="1"
|
|
fi
|
|
# force gpt + uefi in uefi boot mode
|
|
if [ -d /sys/firmware/efi ]; then
|
|
UEFI="1"
|
|
GPT="1"
|
|
fi
|
|
}
|
|
|
|
prompt_backup_unpack() {
|
|
# Prompt for unpacking backup files to /storage
|
|
# usage: prompt_backup_unpack
|
|
# uses:
|
|
# provides: BACKUP_UNPACK
|
|
BACKUP_UNPACK="0"
|
|
if [ -f /flash/backup.tar.bz2 -o -f /flash/backup.zip ]; then
|
|
MSG_TITLE="Restore backup files"
|
|
MSG_DETAIL="Restore backup files to storage partition.\nFile backup.tar.bz2 or/and backup.zip exist on\ninstallation USB stick."
|
|
DIALOG_OPTIONS="--defaultno"
|
|
if whiptail --backtitle "$BACKTITLE" --title "$MSG_TITLE" $DIALOG_OPTIONS --yesno "$MSG_DETAIL" 0 0; then
|
|
BACKUP_UNPACK="1"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
menu_main() {
|
|
# show the mainmenu
|
|
MSG_TITLE="MAIN MENU"
|
|
MSG_MENU="\nWelcome to @DISTRONAME@ installation tool! \
|
|
\n
|
|
This tool is used to copy @DISTRONAME@ from the installation media \
|
|
to your disk or other device. You'll be up and running in no time! \
|
|
Please note that the contents of the disk you choose will be wiped \
|
|
out during the installation. \
|
|
\n\nPlease select:"
|
|
MSG_CANCEL="Close"
|
|
|
|
whiptail --backtitle "$BACKTITLE" --cancel-button "$MSG_CANCEL" \
|
|
--title "$MSG_TITLE" --menu "$MSG_MENU" 18 73 4 \
|
|
1 "Install @DISTRONAME@" \
|
|
2 "View installation log" \
|
|
3 "Save installation log" \
|
|
4 "Reboot" 2> $TMPDIR/mainmenu
|
|
|
|
case $? in
|
|
0)
|
|
ITEM_MAINMENU=$(cat "$TMPDIR/mainmenu")
|
|
case $ITEM_MAINMENU in
|
|
1) do_install_quick;;
|
|
2) logfile_show;;
|
|
3) logfile_save;;
|
|
4) do_reboot;;
|
|
esac
|
|
;;
|
|
1)
|
|
do_reboot
|
|
;;
|
|
255)
|
|
do_poweroff
|
|
;;
|
|
esac
|
|
}
|
|
|
|
logfile_show() {
|
|
whiptail --textbox "$LOGFILE" 20 73 --scrolltext --backtitle "$BACKTITLE"
|
|
}
|
|
|
|
logfile_save() {
|
|
mount -o remount,rw /flash
|
|
|
|
mkdir -p $(dirname $LOGBACKUP)
|
|
cp $LOGFILE $LOGBACKUP
|
|
sync
|
|
|
|
mount -o remount,ro /flash
|
|
|
|
MSG_TITLE="@DISTRONAME@ Log Saved"
|
|
MSG_DETAIL="Log location: ${LOGBACKUP}\n"
|
|
whiptail --backtitle "$BACKTITLE" --title "$MSG_TITLE" --msgbox "$MSG_DETAIL" 7 52
|
|
}
|
|
|
|
do_reboot() {
|
|
# reboot on request
|
|
clear
|
|
sync
|
|
reboot -f
|
|
}
|
|
|
|
do_poweroff() {
|
|
# powerdown on request
|
|
clear
|
|
sync
|
|
poweroff -f
|
|
}
|
|
|
|
# setup needed variables
|
|
OS_VERSION=$(lsb_release)
|
|
BACKTITLE="@DISTRONAME@ Installer - $OS_VERSION"
|
|
|
|
TMPDIR="/tmp/installer"
|
|
LOGFILE="$TMPDIR/install.log"
|
|
LOGBACKUP="/flash/logs/$(date +%Y%m%d%H%M%S).log"
|
|
|
|
export COLORTERM="1"
|
|
export NEWT_COLORS="$WHIPTAIL_COLORS"
|
|
|
|
IMAGE_KERNEL="KERNEL"
|
|
IMAGE_SYSTEM="SYSTEM"
|
|
for arg in $(cat /proc/cmdline); do
|
|
case $arg in
|
|
BOOT_IMAGE=*)
|
|
IMAGE_KERNEL="${arg#*=}"
|
|
[ "${IMAGE_KERNEL:0:1}" = "/" ] && IMAGE_KERNEL="${IMAGE_KERNEL:1}"
|
|
;;
|
|
SYSTEM_IMAGE=*)
|
|
IMAGE_SYSTEM="${arg#*=}"
|
|
[ "${IMAGE_SYSTEM:0:1}" = "/" ] && IMAGE_SYSTEM="${IMAGE_SYSTEM:1}"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# prepare temporary directory
|
|
rm -rf $TMPDIR
|
|
mkdir -p $TMPDIR
|
|
|
|
#create log file
|
|
echo "@DISTRONAME@ Installer - $OS_VERSION started at:" > $LOGFILE
|
|
date >> $LOGFILE
|
|
|
|
dbglg "System status"
|
|
log_system_status >> $LOGFILE 2>&1
|
|
|
|
# generate the en_US.UTF-8 locale to enable line drawing
|
|
mkdir -p $TMPDIR/locale
|
|
localedef -i en_US -f UTF-8 $TMPDIR/locale/en_US.UTF-8
|
|
export LOCPATH=$TMPDIR/locale
|
|
export LC_ALL=en_US.UTF-8
|
|
|
|
# main
|
|
|
|
while true; do
|
|
clear
|
|
menu_main
|
|
done
|
|
|
|
# exit cleanly
|
|
exit 0
|