#!/bin/bash # +--------------------------------------------------------------------------+ # | _____ __ ___ __ _ __ | # | / ___// /___ ______/ (_)___ / / (_)___ / /__ | # | \__ \/ __/ / / / __ / / __ \ / / / / __ \/ //_/ | # | ___/ / /_/ /_/ / /_/ / / /_/ / / /___/ / / / / ,< | # |/____/\__/\__,_/\__,_/_/\____/ /_____/_/_/ /_/_/|_| | # |Copyright Sebastian Reimers 2013 - 2015 studio-link.de | # |License: BSD-2-Clause (see LICENSE File) | # +--------------------------------------------------------------------------+ # Exit on non-zero return codes set -e # VARS pacman="pacman --noconfirm --force --needed" home="/opt/studio" repo="https://github.com/studio-link/webapp.git" pkg_url="https://github.com/studio-link/PKGBUILDs/raw/master" version="15.1.0-beta" update_docroot="/tmp/update" update_status() { echo "nobody ALL=(ALL) NOPASSWD: /usr/bin/journalctl" >> /etc/sudoers mkdir -p $update_docroot/cgi-bin cat > $update_docroot/cgi-bin/logging.sh << EOF #!/bin/bash echo "Content-type: text/html" echo "" sudo journalctl | grep studio-update EOF chmod +x $update_docroot/cgi-bin/logging.sh curl -L https://raw.githubusercontent.com/studio-link/images/devel/update.html | sed "s/STATUS/$1/g" > $update_docroot/index.html_tmp mv $update_docroot/index.html_tmp $update_docroot/index.html } # Root permissions are required to run this script if [ "$(whoami)" != "root" ]; then echo "Error: Studio Link Bootstrap requires root privileges to install. Please re-run this script as root." exit 1 fi update_status 0 # 0% systemctl stop nginx || true sleep 2 cd $update_docroot python2 -m CGIHTTPServer 80 > /dev/null 2>&1 & http_pid=$! # New pacman Version pacman-db-upgrade # Cleanup pacman cache yes | pacman -Scc rm /var/lib/pacman/sync/*.db || true # Remove corrupt systemd journal files find /var/log/journal -name "*.journal~" -exec rm {} \; update_status 10 # 10% # Check disk usage disk_free=`df -m / | awk '{ print $4 }' | tail -1` if [ $disk_free -lt 300 ]; then echo "Not enough free disk space [only ${disk_free} MByte free]" exit 1 fi if [[ "$(uname -m)" =~ armv7.? ]]; then # Update Mirrorlist cat > /etc/pacman.d/mirrorlist << EOF # Studio Link Repo Server = http://repo.studio-link.de/$version/armv7h/\$repo EOF cat > /etc/pacman.conf << EOF [options] HoldPkg = pacman glibc Architecture = armv7h CheckSpace SigLevel = Never [studio] Include = /etc/pacman.d/mirrorlist EOF fi # Remove man-db (rebuild takes too much cpu load and time) $pacman -R man-db man-pages || true # Upgrade packages $pacman -Syu pacman-db-upgrade update_status 50 # 50% # Install packages $pacman -S git vim ntp nginx aiccu python2 python2-distribute avahi wget $pacman -S python2-virtualenv alsa-plugins alsa-utils gcc make redis sudo fake-hwclock $pacman -S python2-numpy ngrep tcpdump lldpd dosfstools # Baresip/Jackd requirements (codecs) $pacman -S spandsp gsm celt # Long polling and baresip redis requirements $pacman -S hiredis libmicrohttpd # Studio PKGBUILDs $pacman -S jack2 opus libre librem baresip aj-snapshot jack_capture # Create User if [ ! -d $home ]; then useradd --password paCam17s4xpyc --home-dir $home studio $pacman -S studio-webapp cd $home/webapp $home/bin/python -c "from app import db; db.create_all();" else if [ -f /etc/systemd/system/studio-webapp.service ]; then systemctl stop studio-webapp systemctl stop studio-celery systemctl stop baresip fi # Check if migration to studio-webapp package already completed if [ "$(pacman -Q studio-webapp)" == "" ]; then cp -a /opt/studio/webapp/app.db /tmp/ cp -a /opt/studio/webapp/htpasswd /tmp/ rm -Rf /opt/studio $pacman -S studio-webapp cp -a /tmp/app.db /opt/studio/webapp/ cp -a /tmp/htpasswd /opt/studio/webapp/ fi fi if [ ! -f $home/webapp/htpasswd ]; then echo 'studio:$apr1$Qq44Nzw6$pRmaAHIi001i4UChgU1jF1' > $home/webapp/htpasswd fi chown -R studio:studio $home gpasswd -a studio audio gpasswd -a studio video mkdir -p $home/logs update_status 90 # 90% # Deploy configs cat > /etc/systemd/system/studio-webapp.service << EOF [Unit] Description=studio-webapp fastcgi After=syslog.target network.target redis.service [Service] Type=simple User=studio Group=studio ExecStart=/opt/studio/bin/gunicorn -w 2 -b 127.0.0.1:5000 --chdir /opt/studio/webapp app:app ExecStartPost=/usr/bin/redis-cli flushall CPUShares=200 [Install] WantedBy=multi-user.target EOF cat > /etc/systemd/system/studio-events.service << EOF [Unit] Description=studio-webapp events After=syslog.target network.target redis.service [Service] Type=simple User=studio Group=studio ExecStart=/opt/studio/webapp/long_polling/server CPUShares=100 [Install] WantedBy=multi-user.target EOF cat > /etc/systemd/system/studio-celery.service << EOF [Unit] Description=studio-celery worker After=syslog.target network.target [Service] Type=simple User=studio Group=studio ExecStart=/opt/studio/bin/celery worker --app=app.tasks -l info --concurrency=1 WorkingDirectory=/opt/studio/webapp CPUShares=100 [Install] WantedBy=multi-user.target EOF cat > /etc/systemd/system/aiccu.service << EOF [Unit] Description=SixXS Automatic IPv6 Connectivity Configuration Utility After=network.target ntpdate.service [Service] Type=forking PIDFile=/var/run/aiccu.pid ExecStart=/usr/bin/aiccu start ExecStop=/usr/bin/aiccu stop Restart=always RestartSec=20 [Install] WantedBy=multi-user.target EOF cat > /etc/nginx/nginx.conf << EOF worker_processes 1; events { worker_connections 20; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; gzip off; server { listen 80; listen [::]:80; server_name localhost; root /opt/studio/webapp/app/templates; access_log off; location /events { proxy_pass http://127.0.0.1:8888; proxy_redirect off; } location /media { root /; } location / { auth_basic "Please Login"; auth_basic_user_file /opt/studio/webapp/htpasswd; try_files \$uri @studioapp; } location @studioapp { proxy_pass http://127.0.0.1:5000; proxy_redirect off; proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } } EOF cat > /usr/share/nginx/html/50x.html << EOF Rebooting/Upgrading

Rebooting/Upgrading...

Please wait and retry a few seconds later.

Bitte warten, die Anwendung wird gerade neu gestartet.

EOF cat > /etc/avahi/services/http.service << EOF %h HTTP _http._tcp 80 EOF cat > /etc/nsswitch.conf << EOF # Begin /etc/nsswitch.conf passwd: files group: files shadow: files publickey: files hosts: files mdns_minimal [NOTFOUND=return] dns myhostname networks: files protocols: files services: files ethers: files rpc: files netgroup: files # End /etc/nsswitch.conf EOF cat > /etc/systemd/system/baresip.service << EOF [Unit] Description=baresip After=syslog.target network.target ntpdate.service [Service] Type=simple User=studio Group=studio LimitRTPRIO=infinity LimitMEMLOCK=infinity ExecStart=/usr/bin/baresip WorkingDirectory=/opt/studio/webapp CPUShares=2048 TimeoutStopSec=10 Restart=always RestartSec=5 [Install] WantedBy=multi-user.target EOF mkdir -p $home/.baresip chown -R studio:studio $home/.baresip # Fix IPv6 avahi sed -i 's/use-ipv6=no/use-ipv6=yes/' /etc/avahi/avahi-daemon.conf cat > /etc/iptables/ip6tables.rules << EOF # Generated by studio-link *filter :INPUT DROP [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -p ipv6-icmp -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT -A INPUT -s fe80::/10 -j ACCEPT COMMIT EOF # Allow ipv4 autoconfiguration (comment noipv4ll) # https://wiki.archlinux.org/index.php/avahi#Obtaining_IPv4LL_IP_address cat > /etc/dhcpcd.conf << EOF hostname clientid #duid option rapid_commit option domain_name_servers, domain_name, domain_search, host_name option classless_static_routes option ntp_servers require dhcp_server_identifier nohook lookup-hostname #noipv4ll EOF cat > /etc/netctl/hooks/dhcpcd-timeout << EOF TimeoutDHCP=40 EOF chmod +x /etc/netctl/hooks/dhcpcd-timeout cat > /etc/systemd/system/studio-update.service << EOF [Unit] Description=studio-update After=syslog.target network.target [Service] Type=oneshot User=root Group=root ExecStart=/opt/studio/bin/studio-update.sh [Install] WantedBy=multi-user.target EOF cat > /opt/studio/bin/studio-update.sh << EOF #!/bin/bash version=\$(/usr/bin/redis-cli get next_release) if [ \$version ]; then curl -L https://raw.githubusercontent.com/studio-link/images/\$version/bootstrap.sh | bash -ex fi EOF chmod +x /opt/studio/bin/studio-update.sh cat > /etc/systemd/system/studio-jackd.service << EOF [Unit] Description=Studio Link JACK DAEMON After=baresip.service studio-webapp.service [Service] LimitRTPRIO=infinity LimitMEMLOCK=infinity User=studio ExecStart=/opt/studio/bin/studio-jackd.sh Restart=always RestartSec=5 [Install] WantedBy=multi-user.target EOF cat > /opt/studio/bin/studio-jackd.sh << EOF #!/bin/bash device=\$(grep audio_player /opt/studio/.baresip/config | awk '{ print \$2 }' | awk -F: '{ print \$2 }') /usr/bin/jackd -R -P89 -dalsa -d hw:\$device -r48000 -p480 -n3 EOF chmod +x /opt/studio/bin/studio-jackd.sh cat > /etc/sysctl.d/99-sysctl.conf << EOF # realtime fix jackd kernel.sched_rt_runtime_us = -1 EOF cat > /opt/studio/.asoundrc << EOF # convert alsa API over jack API # use this as default pcm.!default { type plug slave { pcm "jack" } } ctl.mixer0 { type hw card 1 } # pcm type jack pcm.jack { type jack playback_ports { 0 system:playback_1 1 system:playback_2 } capture_ports { 0 system:capture_1 1 system:capture_2 } } EOF chown studio:studio /opt/studio/.asoundrc # g_audio Kernel Modul cat > /etc/modules-load.d/studio.conf << EOF g_audio EOF cat > /etc/modprobe.d/studio.conf << EOF options g_audio c_srate=48000 p_srate=48000 EOF cat > /opt/studio/routing.xml << EOF EOF chown studio:studio /opt/studio/routing.xml cat > /etc/systemd/system/aj-snapshot.service << EOF [Unit] Description=aj-snapshot After=syslog.target network.target studio-jackd.service [Service] Type=simple User=studio Group=studio LimitMEMLOCK=infinity ExecStart=/usr/bin/aj-snapshot -j -d /opt/studio/routing.xml [Install] WantedBy=multi-user.target EOF cat > /etc/systemd/system/studio-capture.service << EOF [Unit] Description=studio-capture After=syslog.target network.target [Service] Type=simple User=studio Group=studio LimitRTPRIO=infinity LimitMEMLOCK=infinity ExecStart=/opt/studio/bin/studio-capture.sh ExecStop=/usr/bin/killall jack_capture WorkingDirectory=/media [Install] WantedBy=multi-user.target EOF cat > /opt/studio/bin/studio-capture.sh << EOF #!/bin/bash hostname=\$(hostname) date=\$(date +%d%m%y%H%M%S) /usr/bin/jack_capture --daemon -b 16 -c 2 -f flac -dm -mc -B 8 -Rf 864000000 \$hostname-\$date EOF chmod +x /opt/studio/bin/studio-capture.sh cat > /etc/systemd/system/studio-playback.service << EOF [Unit] Description=studio-playback After=syslog.target network.target [Service] Type=simple User=studio Group=studio LimitRTPRIO=infinity LimitMEMLOCK=infinity ExecStart=/opt/studio/bin/studio-playback.sh WorkingDirectory=/media [Install] WantedBy=multi-user.target EOF cat > /opt/studio/bin/studio-playback.sh << EOF #!/bin/bash filename=\$(redis-cli get playback) /usr/bin/flac -d \$filename -c | aplay redis-cli set playback empty EOF chmod +x /opt/studio/bin/studio-playback.sh if [ ! -f /etc/studio-link-community ]; then cat > /opt/studio/bin/studio-vpn-update.sh << EOF #!/bin/bash hostname=\$(ip link show eth0 | grep ether | awk '{ print \$2 }' | sed s/://g | cut -c 7-) private_ip=\$(hostname -i) curl --data "hostname=\$hostname&private_ip=\$private_ip" https://vpn.studio-link.de/update.php EOF chmod +x /opt/studio/bin/studio-vpn-update.sh cat > /etc/systemd/system/studio-vpn-update.service << EOF [Unit] Description=studio-vpn-update After=syslog.target network.target ntpdate.service [Service] Type=oneshot User=root Group=root ExecStart=/opt/studio/bin/studio-vpn-update.sh [Install] WantedBy=multi-user.target EOF fi systemctl daemon-reload # Enable systemd start scripts systemctl enable nginx systemctl enable avahi-daemon systemctl enable redis systemctl enable ntpdate systemctl enable studio-webapp systemctl enable studio-events systemctl enable studio-celery systemctl enable baresip systemctl enable fake-hwclock systemctl enable studio-jackd systemctl enable aj-snapshot systemctl enable lldpd if [ ! -f /etc/studio-link-community ]; then systemctl enable studio-vpn-update fi # Temporary disabling ip6tables until final version systemctl disable ip6tables.service # Disable mandb cache daily cron systemctl stop man-db.timer systemctl disable man-db.timer systemctl mask man-db.timer # sudo privileges cat > /etc/sudoers << EOF root ALL=(ALL) ALL studio ALL=(ALL) NOPASSWD: ALL EOF pacman -Q | grep linux-am33x if [ $? -eq 0 ]; then mkdir -p /media # Only write fstab if no sdcard if [ ! "$(blkid /dev/mmcblk1p2)" ]; then uuid=$(blkid -o value -s UUID /dev/mmcblk0p2) # Mount Options (noatime) cat > /etc/fstab << EOF UUID=$uuid / ext4 defaults,noatime,nodiratime 0 1 /dev/disk/by-path/platform-48060000.mmc-part1 /media auto defaults,uid=1000,x-systemd.automount 0 0 EOF fi fi # Limit systemd journal cat > /etc/systemd/journald.conf << EOF [Journal] SystemMaxUse=20M EOF # Hostname if [[ "$(uname -m)" =~ armv7.? ]]; then post=$(ip link show eth0 | grep ether | awk '{ print $2 }' | sed s/://g | cut -c 7-) else post="dev" fi echo "studio-link-$post" > /etc/hostname # Disable root account passwd -l root # Set timezone if [ ! -f /etc/studio-release ]; then timedatectl set-timezone Europe/Berlin fi # Cleanup yes | pacman -Scc # Logrotate (mostly nginx logs) logrotate -f /etc/logrotate.conf if [[ "$(uname -m)" =~ armv7.? ]]; then pacman -Q | grep linux-am33x if [ $? -eq 0 ]; then yes | pacman --needed -S linux-am33x fi fi # Add Audio files #if [ ! -f /usr/local/share/baresip/ring.wav ]; then # mkdir -p /usr/local/share/baresip # cd /usr/local/share/baresip/ # wget http://mirror.studio-connect.de/music/busy.wav # wget http://mirror.studio-connect.de/music/error.wav # wget http://mirror.studio-connect.de/music/message.wav # wget http://mirror.studio-connect.de/music/ring.wav # wget http://mirror.studio-connect.de/music/ringback.wav #fi if [ -f /usr/local/share/baresip/ring.wav ]; then rm -Rf /usr/local/share/baresip fi # Starting Services systemctl start redis sleep 2 # workaround - redis needs sometimes more time. systemctl start studio-celery systemctl start studio-webapp systemctl start studio-events systemctl start studio-jackd systemctl start baresip systemctl start aj-snapshot if [ ! -f /etc/studio-link-community ]; then # Provisioning hash=$(ip link show eth0 | grep ether | awk '{ print $2 }' | md5sum | awk '{ print $1 }') wget https://server.visr.de/provisioning/$hash.txt -O /tmp/provisioning.txt || true if [ -s /tmp/provisioning.txt ]; then cd /opt/studio/webapp /opt/studio/bin/celery call --app=app.tasks app.tasks.provisioning fi fi update_status 95 # 95% # Flush filesystem buffers echo "Syncing filesystem..." sync; sleep 5; sync kill $http_pid sleep 5 systemctl start nginx # Update Version echo $version > /etc/studio-release echo "*** Bootstrap finished! Please reboot now! ***" /usr/bin/redis-cli set reboot_required true