#! /bin/bash ESC=$'\e' col_red="${ESC}[1;31m" col_green_bold="${ESC}[1;32m" col_green="${ESC}[32m" col_yellow="${ESC}[1;33m" #col_cyan="${ESC}[1;36m" col_reset="${ESC}[0m" opt_destdir=/srv/musiikki opt_adminpwfile=${opt_destdir}/htpasswd opt_verbose=1 opt_uid= opt_gid= opt_apt= opt_hostname= opt_essid= opt_wpakey= opt_subnet= # default name of Raspian default_hostname=raspberrypi echo_ok() { echo "${col_green}$*${col_reset}" } echo_ok_bold() { echo "${col_green_bold}$*${col_reset}" } echo_error() { echo "${col_red}$*${col_reset}" } echo_verbose() { test $opt_verbose -eq 1 || return echo -n "$*" } echo_newline_verbose() { test $opt_verbose -eq 1 || return echo "" } # ------------------------------------------------------------ assert_system_uidgid() { test -z "$opt_uid" || return if [ -d ${opt_destdir} ] then opt_uid=$(stat --format=%u ${opt_destdir}) opt_gid=$(stat --format=%g ${opt_destdir}) else echo -n "${col_yellow}Set file owner to${col_reset}: " read opt_uid echo -n "${col_yellow}Set file group to${col_reset}: " read opt_gid fi } assert_system_hostname() { test -z "$opt_hostname" || return echo -n "${col_yellow}Set hostname to${col_reset}: " read opt_hostname } assert_system_essid() { test -z "$opt_essid" || return if [ -f /etc/musiikki.conf ] then opt_essid=$(grep '^title=' /etc/musiikki.conf) opt_essid=${opt_essid#title=} else if [ -f /etc/hostapd/hostapd.conf ] then opt_essid=$(grep '^ssid=' /etc/hostapd/hostapd.conf) opt_essid=${opt_essid#ssid=} else echo -n "${col_yellow}Set Wireless ESSID to${col_reset}: " read opt_essid fi fi } assert_system_wpakey() { test -z "$opt_wpakey" || return if [ -f /etc/hostapd/hostapd.conf ] then opt_wpakey=$(grep '^wpa_passphrase=' /etc/hostapd/hostapd.conf) opt_wpakey=${opt_wpakey#wpa_passphrase=} else echo -n "${col_yellow}Set Wireless WPA key to${col_reset}: " read opt_wpakey fi } assert_system_subnet() { test -z "$opt_subnet" || return if grep -q '^server\.bind' /etc/lighttpd/lighttpd.conf then opt_subnet=$(grep '^server\.bind\s' /etc/lighttpd/lighttpd.conf) opt_subnet=${opt_subnet#*\"} opt_subnet=${opt_subnet%.1\"*} else echo -n "${col_yellow}Set subnet (3 octets only) to${col_reset}: " read opt_subnet fi } # ------------------------------------------------------------ welcome() { echo echo_ok_bold "Installing Infodrom MediaServer" echo } assert_root() { if [ "$(/usr/bin/whoami)" != "root" ] then echo_error "The installation needs to be done as root" return 1 fi return 0 } assert_directory() { if [ ! -x install-system ] then echo_error "Current directory lacks executable install-system" return 1 fi if [ ! -d bin ] then echo_error "Current directory lacks bin directory" return 1 fi if [ ! -d config-templates ] then echo_error "Current directory lacks config-templates directory" return 1 fi if [ "$(pwd)" != "${opt_destdir}" -a -x /usr/bin/rsync ] then assert_system_uidgid # Relocate ourself rsync -arH ./ ${opt_destdir}/ chown -R ${opt_uid}.${opt_gid} ${opt_destdir} fi return 0 } assert_hostname() { if [ "$(cat /etc/hostname)" = "$default_hostname" ] then echo_verbose "Default hostname found"; echo_newline_verbose assert_system_hostname echo $opt_hostname > /etc/hostname printf "192.168.1.1\t%s\n" "$opt_hostname" >> /etc/hosts fi } assert_programs() { echo_verbose "Looking for programs: " echo_verbose "sed... " if [ ! -x /bin/sed ] then echo_newline_verbose echo_error "Program sed missing" return 1 fi echo_verbose "dpkg... " if [ ! -x /usr/bin/dpkg ] then echo_newline_verbose echo_error "Program dpkg missing" return 1 fi echo_verbose "apt-get... " if [ -x /usr/bin/apt-get ] then opt_apt=/usr/bin/apt-get else echo_verbose "apt... " if [ -x /usr/bin/apt ] then opt_apt=/usr/bin/apt else echo_verbose "aptitude... " if [ -x /usr/bin/aptitude ] then opt_apt=/usr/bin/aptitude else echo_newline_verbose echo_error "High-level package manager missing (apt-get/apt/aptitude)" return 1 fi fi fi echo_newline_verbose return 0 } assert_no_recommends() { if ! grep -q 'APT::Install-Recommends False;' /etc/apt/apt.conf.d/* then echo_ok "Configure APT not to install recommended packages" echo 'APT::Install-Recommends False;' > /etc/apt/apt.conf.d/40recommends fi } install_packages() { if [ -z "$opt_apt" ] then echo_error "No high-level package manager available" return 1 fi set -e $opt_apt update $opt_apt install -y $* set +e return 0 } remove_packages() { if [ -z "$opt_apt" ] then echo_error "No high-level package manager available" return 1 fi set -e $opt_apt purge -y $* set +e return 0 } package_exists() { local pkg=$1 if [ -f "/var/lib/dpkg/info/${pkg}.list" ] then return 0 else return 1 fi } assert_packages() { missing= echo_verbose "Looking for installed packages: " for pkg in sudo super rsync hostapd isc-dhcp-server minidlna lighttpd samba php7.0-cgi php7.0-json do echo_verbose "${pkg}... " if ! package_exists ${pkg} then missing="$missing $pkg" fi done echo_newline_verbose if [ -n "$missing" ] then echo_ok "Installing$missing" install_packages $missing || return 1 echo_ok "Successfully installed$missing" fi toomuch= echo_verbose "Looking for installed packages: " for pkg in triggerhappy avahi-daemon do echo_verbose "${pkg}... " if package_exists ${pkg} then toomuch="$toomuch $pkg" fi done echo_newline_verbose if [ -n "$toomuch" ] then echo_ok "Removing$toomuch" remove_packages $toomuch || return 1 echo_ok "Successfully removed$toomuch" fi } assert_musiikki() { if [ ! -f /etc/musiikki.conf ] then assert_system_essid echo_ok "Installing main configuration" sed "s/{essid}/${opt_essid}/g;s!{basedir}!${opt_destdir}!g;s!{htpasswd}!${opt_adminpwfile}!g" config-templates/musiikki.conf.template > /root/.template install -o root -g root -m 644 /root/.template /etc/musiikki.conf rm -f /root/.template fi } assert_hostapd() { if [ ! -f /etc/hostapd/hostapd.conf ] then assert_system_essid assert_system_wpakey echo_ok "Create hostapd configuration" sed "s/{essid}/${opt_essid}/g;s/{wpakey}/${opt_wpakey}/g" config-templates/hostapd.conf.template > /root/.template install -o root -g root -m 644 /root/.template /etc/hostapd/hostapd.conf rm -f /root/.template fi if grep -q '#DAEMON_CONF=""' /etc/default/hostapd then echo_ok "Activate hostapd" sed -i 's!#DAEMON_CONF=""!DAEMON_CONF="/etc/hostapd/hostapd.conf"!' /etc/default/hostapd fi } assert_dhcpd() { assert_system_subnet if ! grep -q "^subnet ${opt_subnet}.0 " /etc/dhcp/dhcpd.conf then echo_ok "Add DHCP configuration" sed "s/{subnet}/${opt_subnet}/g" config-templates/dhcpd.conf.template >> /etc/dhcp/dhcpd.conf fi if grep -q 'INTERFACESv4=""' /etc/default/isc-dhcp-server then echo_ok "Add WLAN interface to DCHP config" sed -i 's/INTERFACESv4=".*"/INTERFACESv4="wlan0"/' /etc/default/isc-dhcp-server fi } assert_super() { echo_verbose "Asserting permissions " for prg in $(cd bin && echo *) do test $prg != musiikki-rescan || continue echo_verbose "${prg}... " if ! grep -q "^${prg}" /etc/super.tab then printf "%s\t%s/bin/%s www-data u+g=root password=n\n" ${prg} ${opt_destdir} ${prg} >> /etc/super.tab fi done echo_newline_verbose } assert_minidlna() { assert_system_essid assert_system_subnet if ! grep -q "^friendly_name=${opt_essid}" /etc/minidlna.conf then sed -i "s!#friendly_name=!friendly_name=${opt_essid}!;s!^media_dir=.*!!" /etc/minidlna.conf sed -i "s!#listening_ip=!listening_ip=${opt_subnet}.1!" /etc/minidlna.conf sed -i "s!#db_dir=.*!db_dir=/media/music/cache!" /etc/minidlna.conf echo "" >> /etc/minidlna.conf echo "model_name=${opt_essid}" >> /etc/minidlna.conf echo "media_dir=A,/media/music/music" >> /etc/minidlna.conf echo "media_dir=P,/media/music/pictures" >> /etc/minidlna.conf echo "media_dir=V,/media/music/video" >> /etc/minidlna.conf fi chmod o+rx /var/cache/minidlna } assert_lighttpd() { echo_verbose "Asserting lighttpd modules " echo_verbose "05-auth... " if [ ! -f /etc/lighttpd/conf-enabled/05-auth.conf ] then assert_system_essid cat < /etc/lighttpd/conf-enabled/05-auth.conf # /usr/share/doc/lighttpd/authentication.txt.gz server.modules += ( "mod_auth" ) auth.backend = "plain" auth.backend.plain.userfile = "${opt_adminpwfile}" # auth.backend.plain.groupfile = "lighttpd.group" auth.require = ( "/admin/" => ( "method" => "basic", "realm" => "${opt_essid}", "require" => "user=admin", ) ) EOT fi for name in 10-fastcgi 15-fastcgi-php do echo_verbose "${name}... " if [ ! -f /etc/lighttpd/conf-enabled/${name}.conf ] then ln -s ../conf-available/${name}.conf /etc/lighttpd/conf-enabled/${name}.conf fi done echo_newline_verbose if [ ! -f ${opt_adminpwfile} ] then echo -n "${col_yellow}Set web admin password to${col_reset}: " read admin_pw echo "admin:${admin_pw}" > ${opt_adminpwfile} fi chown www-data.www-data ${opt_adminpwfile} if ! grep -q '^server.tag' /etc/lighttpd/lighttpd.conf then assert_system_essid assert_system_subnet sed -i "s!^server.document-root\\s*=\\s*\".*\"!server.document-root = \"${opt_destdir}/html\"!" /etc/lighttpd/lighttpd.conf echo "server.tag = \"${opt_essid}\"" >> /etc/lighttpd/lighttpd.conf echo "server.bind = \"${opt_subnet}.1\"" >> /etc/lighttpd/lighttpd.conf fi } assert_samba() { if ! grep -q '^\[musicread\]$' /etc/samba/smb.conf then echo_ok "Add shares to Samba" sed "s/{essid}/${opt_essid}/g" config-templates/smb.conf.template >> /etc/samba/smb.conf fi if ! grep -q '^musicread:' /etc/passwd then assert_system_essid echo_ok "Create read/only Samba account" adduser --quiet --disabled-password --system --group --no-create-home --home /var/lib/misc --gecos "${opt_essid} read/only account" musicread fi if ! grep -q '^musicwrite:' /etc/passwd then assert_system_essid echo_ok "Create read/write Samba account" adduser --quiet --disabled-password --system --group --no-create-home --home /var/lib/misc --gecos "${opt_essid} read/write account" musicwrite fi } assert_cron() { if [ ! -f /etc/cron.d/musiikki ] then echo_ok "Install crontab" cp config-templates/cron.d.template /etc/cron.d/musiikki fi if [ ! -d /var/local/musiikki ] then install -d -o minidlna -g minidlna -m 755 /var/local/musiikki fi if [ ! -d /var/local/musiikki/rescan ] then install -d -o minidlna -g minidlna -m 777 /var/local/musiikki/rescan fi } welcome assert_root || exit 2 assert_directory || exit 2 assert_hostname || exit 2 assert_programs || exit 2 assert_no_recommends || exit 2 assert_packages || exit 2 assert_musiikki assert_hostapd assert_dhcpd assert_super assert_minidlna assert_lighttpd assert_samba assert_cron