#!/bin/sh -e
#
# (C) Copyright 2015-2018 Axis Communications AB, LUND, SWEDEN
. /usr/lib/addon-common
. /usr/lib/addon-apache-config
LOG_TAG="addon-setup"
[ $# -le 3 ] && [ "$1" ] && [ "$2" ] || {
echo "This is a setup script for add-on package.
Usage: ${0##*/} <package filename> <signed package 0:1> <optional: first_boot_mode>"
return 1
}
# Declare global variables
OPKGNAME=$(get_package_name $1) || {
syslog_err $LOG_TAG "addon-setup: Failed to get package name from $1"
exit 1
}
# Declare signed package status used to determine if devmode needs to be checked
[ "$2" -eq 1 ] && SIGNED_PACKAGE=1 || SIGNED_PACKAGE=0
if [ $# -eq 3 ]; then
if [ "$3" ]; then
FIRST_BOOT_MODE="$3"
else
syslog_err $LOG_TAG "addon-setup: Failed to get pre-install mode from $3"
exit 1
fi
fi
is_package_name_valid "$OPKGNAME" result ||
fail_errorcode $ERR_INVALID_PKG_NAME "Failed to validate package name: $OPKGNAME"
[ $result -eq $TRUE ] || fail_errorcode $ERR_INVALID_PKG_NAME "Package name $OPKGNAME contains illegal characters only " "[a-z0-9.+-] is allowed"
#Declare variables for folders access rights
# Current addon access rights
#
# <addon dir>: $OPKGNAME:addon 701 (exec required by Apache)
# /usr: $OPKGNAME:addon 701 (exec required by Apache)
# /usr/bin/*: $OPKGNAME:addon 700
# <web folder>: $OPKGNAME:www 750 (exec required by Apache)
# <web folder>/<dirs>: $OPKGNAME:www 750 (exec required by Apache)
# <web folder>/<files>: $OPKGNAME:www 640
# License file: $OPKGNAME:www 640
PERM_EXECDIR=701
PERM_OTHERDIR=700
PERM_BINFILES=700
PERM_WEBDIR=750
PERM_WEBFILES=640
PERM_LICFILE=640
PERM_OTHER=600
# Make sure package is installed
is_package_installed $OPKGNAME result || fail_errorcode $ERR_INSTALL_ERROR "Failed to check if Add-on package $OPKGNAME is installed"
[ $result -eq $TRUE ] || fail_errorcode $ERR_ADDON_NOT_FOUND "Add-on $pkgname is not installed"
OPKGFILES=$($OPKG files $OPKGNAME | tail +2) || {
syslog_err $LOG_TAG "addon-setup: Failed to get list of installed files for $OPKGNAME"
exit 1
}
MANIFESTFILE=$MANIFEST_PATH/${OPKGNAME}_manifest.xml
[ -f "$MANIFESTFILE" ] || {
syslog_err $LOG_TAG "addon-setup: $MANIFESTFILE does not exist"
exit 1
}
revert_and_fail() {
local errorcode
rm -f $SERVICE_PATH/$OPKGNAME.service
rm -f $WEB_ROOT$OPKGNAME
remove_apac_grant $OPKGNAME || :
remove_addon_configuration $OPKGNAME || :
# If an error code was specified used it, otherwise default to install error
if [ $# -gt 1 ]; then
errorcode=$1
shift
else
errorcode=$ERR_INSTALL_ERROR
fi
fail_errorcode $errorcode "$@"
}
get_schema_location() {
# Check which version of the schema is requested
# Validate that this version is available.
# $1 - The manifest containing the version
# $2 - Output parameter indicating the schema to use
local manifest_chk schema_location
# Schema install path
local SCHEMAPATH="usr/share/addon/schema"
manifest_chk="$1"
major=$(xmllint --xpath "string(//Manifest/@Major)" $manifest_chk) ||
revert_and_fail $ERR_INSTALL_ERROR "Internal Error when parsing manifest version"
minor=$(xmllint --xpath "string(//Manifest/@Minor)" $manifest_chk) ||
revert_and_fail $ERR_INSTALL_ERROR "Internal Error when parsing manifest version"
[ "$major" ] && [ "$minor" ] || revert_and_fail $ERR_INSTALL_ERROR "Schema version: Major or Minor is missing"
[ -d $SDKTARGETSYSROOT/$SCHEMAPATH/$major/$minor ] || {
revert_and_fail $ERR_INSTALL_ERROR "Requested schema version not available"
}
schema_location=$SDKTARGETSYSROOT/$SCHEMAPATH/$major/$minor/unrestricted_manifest.xsd
eval $2=\$schema_location
}
get_schema_location $MANIFESTFILE SCHEMAFILE
[ -f "$SCHEMAFILE" ] || {
syslog_err $LOG_TAG "addon-setup: $SCHEMAFILE does not exist"
exit 1
}
WEB_FOLDER=
FCGI_SOCK=
LINUX_CAPS=
ADDON_CB_BUSNAME=
[ -d $SERVICE_PATH ] || {
syslog_err $LOG_TAG "addon-setup: $SERVICE_PATH does not exist"
exit 1
}
# Prints the opkg path that ends with $1
# Return error if not found
get_path() {
local f
for f in $OPKGFILES; do
case $f in
*$1)
echo $f
return 0
;
esac
done
return 1
}
INSTALL_DIR=$(get_path /$OPKGNAME/) || {
syslog_err $LOG_TAG "addon-setup: Failed to get install dir for $OPKGNAME"
exit 1
}
[ -d "$INSTALL_DIR" ] || {
syslog_err $LOG_TAG "addon-setup: No install directory found for $OPKGNAME"
exit 1
}
# Strip trailing '/'
INSTALL_DIR=${INSTALL_DIR%/}
get_manifest_xpath() {
[ ${#MANIFEST} -ne 0 ] || return 1
[ $1 ] || return 1
echo $MANIFEST | xmllint --xpath "$1" -
}
extract_manifest_basic_data() {
# Validate the xml format according to the DTD (currently part of the xml
# file) should be added as a system file in both the product and the sdk.
# alternatively a schema could be added to do validaton against.
MANIFEST=$(xmllint --schema $SCHEMAFILE $MANIFESTFILE) > /dev/null 2>&1 ||
revert_and_fail $ERR_MANIFEST "Invalid manifest"
# Check if license exists
license=$(get_manifest_xpath 'string(//License)') ||
revert_and_fail $ERR_MANIFEST "Internal error when trying to: get license"
[ -n "$license" ] || revert_and_fail $ERR_NO_LICENSE "No license in manifest"
}
generate_dbus_access_file() {
local busname tmp_busname count_iface m type i=0 m=0
# Clear old APAC grants if available
syslog_notice $LOG_TAG "Remove grants for user $OPKGNAME "
remove_apac_grant $OPKGNAME
count_iface=$(get_manifest_xpath 'count(//DbusInterface)') ||
revert_and_fail $ERR_MANIFEST 'Fail to extract required data from manifest'
if [ "$count_iface" -le 0 ]; then
return 0;
fi
# Grant user access required APIs
while [ $i -lt $count_iface ]; do
i=$(($i + 1))
busname=$(get_manifest_xpath "string(//DbusInterface[$i]/@Name)") ||
revert_and_fail $ERR_MANIFEST 'Fail to extract requirement name from manifest'
# Count number of methods the interface has and handle them.
count_method=$(get_manifest_xpath "count(//DbusInterface[$i]/Method)") ||
revert_and_fail $ERR_MANIFEST 'Fail to extract required data from manifest'
while [ $m -lt $count_method ]; do
m=$(($m + 1))
method=$(get_manifest_xpath "string(//DbusInterface[$i]/Method[$m])") ||
revert_and_fail $ERR_MANIFEST 'Fail to extract requirement name from manifest'
tmp_busname="$busname.$method"
# Convert the Dbus interface and method name to a APAC
# action id. If not possible, fail.
syslog_notice $LOG_TAG "Grant access for user $OPKGNAME, $tmp_busname"
apac-update grant $OPKGNAME "$tmp_busname" > /dev/null 2>&1 ||
revert_and_fail $ERR_API_GRANT_FAILED "Cannot grant access to $tmp_busname"
# If the API supports CB then we need to add symlinks to the
# configurations.
enable_dbus_conf_for_cb $OPKGNAME
done
m=0
done
}
get_secondary_groups() {
local count groups type name i=0
count=$(get_manifest_xpath 'count(//Uses/Requires/LinuxGroup)') ||
fail 'Fail to extract data from manifest'
while [ $i -lt $count ]; do
i=$(($i + 1))
name=$(get_manifest_xpath "string(//Uses/Requires/LinuxGroup[$i])") ||
fail 'Fail to extract requirement busname from manifest'
[ -e /usr/share/addon/group/$name ] ||
revert_and_fail $ERR_INVALID_REQUIREMENT "$name is not a valid addon group"
if [ "$groups" ]; then
groups="$groups, '$name'"
else
groups="'$name'"
fi
done
echo "$groups"
}
verify_dbus_dependencies() {
local count type busname user ownablebusname devmode_allowed_apis i=0
count=$(get_manifest_xpath 'count(//DbusInterface)') ||
revert_and_fail $ERR_MANIFEST 'Fail to extract requirement data from manifest'
devmode_allowed_apis=$(get_devmode_allowed_apis)
while [ $i -lt $count ]; do
i=$(($i + 1))
busname=$(get_manifest_xpath "string(//DbusInterface[$i]/@Name)") ||
revert_and_fail $ERR_MANIFEST 'Fail to extract requirement busname from manifest'
minor_version=$(get_manifest_xpath "string(//DbusInterface[$i]/@Minor)") ||
revert_and_fail $ERR_MANIFEST 'Fail to extract minor version from DbusInterface'
# Method name not included so we only use the interface since the
# API check is only done on interface level
# Check if the API exist
is_api_available $busname $minor_version result user > /dev/null 2>&1 ||
revert_and_fail $ERR_INSTALL_ERROR "Failed to check API $busname" "$minor_version is available"
# The addon is not signed and we're in devmode but not in 'allow all' mode.
# Check if we're allowed to use it
if [ $SIGNED_PACKAGE -eq 0 ] && [ "$devmode_allowed_apis" ]; then
is_api_allowed $devmode_allowed_apis "$DEVMODE_ALLOW_ALL_VALUE" ||
is_api_allowed $devmode_allowed_apis $busname ||
revert_and_fail $ERR_INSTALL_ERROR "API $busname is not allowed in developer mode"
fi
if [ $result -eq $TRUE ]; then
[ -z $user ] || {
# Check whether a user was returned.
# This means that the API supports cb and that
# a .conf file needs to be generated.
ownablebusname=$(echo "$OPKGNAME" | sed "s/-/_/g")
generate_dbus_conf_for_cb $OPKGNAME $user $busname
ADDON_CB_BUSNAME="com.axis.callbacks.$ownablebusname"
}
else
revert_and_fail $ERR_INVALID_REQUIREMENT "D-Bus name $busname ver $minor_version not available"
fi
done
}
configure_linux_cap() {
# Read LinuxCapability tags from manifest and create a string
# that is suitable for use in systemd service file.
local count linux_cap temp_caps i=0
local cap_xpath=//Uses/Requires/LinuxCapability
count=$(get_manifest_xpath "count($cap_xpath)") ||
revert_and_fail $ERR_MANIFEST "Invalid manifest"
while [ $i -lt $count ]; do
i=$(($i + 1))
linux_cap=$(get_manifest_xpath "string($cap_xpath[$i])") ||
revert_and_fail $ERR_MANIFEST "Invalid manifest"
temp_caps="$temp_caps $linux_cap"
done
LINUX_CAPS="CapabilityBoundingSet=$temp_caps
AmbientCapabilities=$temp_caps"
}
extract_systemd_service_options()
{
# Extract systemD service field options from the manifest
# and use them in the creation of the systemd service file.
local optionvalue optioncount temp optioncommand i=0
local option_xpath=//Configuration/SystemdServiceFileOption
# $1 - The service file being generated
local servicefile="$1"
addon_path="$OPKG_DEST/$OPKGNAME"
addon_bin_path="$addon_path/usr/bin"
optioncount=$(get_manifest_xpath "count($option_xpath)") ||
revert_and_fail $ERR_INSTALL_ERROR "Internal error"
while [ $i -lt $optioncount ]; do
i=$(($i + 1))
temp=$(get_manifest_xpath "string($option_xpath[$i])") ||
revert_and_fail $ERR_MANIFEST "Invalid manifest"
[ -n "$temp" ] ||
revert_and_fail $ERR_MANIFEST "Empty SystemdServiceFileOption"
optionvalue=${temp##*=}
optioncommand=${temp%=*}
optionvalue=$(echo $optionvalue | sed "s#\%ADDON_HOME\%#$addon_path#g")
optionvalue=$(echo $optionvalue | sed "s#\%ADDON_BIN\%#$addon_bin_path#g")
echo "$optioncommand=$optionvalue" >> $servicefile
done
}
generate_services_file() {
local servicefile tmp_file
local start_execfile full_start_exec_path start_exec_option start_args
local stop_execfile full_stop_exec_path stop_exec_option stop_args
local remain_value remain_option
local fcgis_count
local env_option
local cb_busname_option
# Set the environment variable for passing the Add-ons FCGI socket if it
# manifests to use FCGI
fcgis_count=$(get_manifest_xpath 'count(//Fcgis)') ||
revert_and_fail $ERR_MANIFEST "Failed to get Fcgis"
if [ $fcgis_count -eq 1 ]; then
env_option="Environment=FCGI_SOCKET_NAME=$FCGI_SOCK"
fi
if [ -n "$ADDON_CB_BUSNAME" ]; then
cb_busname_option="Environment=ADDON_CB_BUSNAME=$ADDON_CB_BUSNAME"
fi
servicefile=$SERVICE_PATH/"$OPKGNAME".service
tmp_file=$servicefile.tmp
rm -f $tmp_file
if [ -f $servicefile ]; then
# The service file is being re-generated, the saved state should
# reflect the state in the previous service file.
# Therefore it is correct to directly call systemctl stop.
systemctl stop $OPKGNAME > /dev/null 2>&1 ||
syslog_err $LOG_TAG "generate_services_file: Failed to stop service $OPKGNAME"
remove_service $OPKGNAME
fi
echo "[Unit]
Description=Addon $OPKGNAME
[Service]
$LINUX_CAPS
User=$OPKGNAME
RuntimeDirectory=$OPKGNAME
WorkingDirectory=$OPKG_DEST/$OPKGNAME
Restart=on-failure
RuntimeDirectoryMode=0700
Slice=extension-addon.slice" >$tmp_file || revert_and_fail $ERR_FILE_SYSTEM "Failed to create service for $OPKGNAME"
extract_systemd_service_options $tmp_file
echo "
$env_option
$cb_busname_option
[Install]
WantedBy=multi-user.target" >>$tmp_file || revert_and_fail $ERR_FILE_SYSTEM "Failed to create service for $OPKGNAME"
chmod 644 $tmp_file
fsynced_write_or_cleanup $tmp_file $servicefile
}
configure_addon_access() {
# Sets all files in the addon to be owned by the addon user and to be apart
# of the addon group.
# Initially only the owner can access to addon files. If files needs other
# permissions they should be set explicitly e.g. WEB_FOLDER, /usr/bin and
# etc
chown $OPKGNAME:addon -R $INSTALL_DIR ||
revert_and_fail $ERR_FILE_SYSTEM "Failed to change owner of the addon to $OPKGNAME"
chmod -R $PERM_OTHERDIR $INSTALL_DIR ||
revert_and_fail $ERR_FILE_SYSTEM "Failed to set file permission for addon directory and its content"
for addon_sub_dir in $(find -H $INSTALL_DIR -type f); do
chmod $PERM_OTHER $addon_sub_dir
done
# Apache needs executable permissions for all directories in the full
# path to $WEB_FOLDER and the $WEB_FOLDER subdirectories
chmod $PERM_EXECDIR $INSTALL_DIR ||
revert_and_fail $ERR_FILE_SYSTEM "Failed to set executable permission for $INSTALL_DIR"
chmod $PERM_EXECDIR $INSTALL_DIR/usr ||
revert_and_fail $ERR_FILE_SYSTEM "Failed to set executable permission for $INSTALL_DIR/usr"
# Systemd will execute the addon service as the addon user, so only the
# addon user should have permission to execute the addon binaries
chmod -R $PERM_BINFILES $INSTALL_DIR/usr/bin/* ||
revert_and_fail $ERR_FILE_SYSTEM "Failed to set file permission for addon binaries"
}
configure_layered_addon_access() {
# Sets all files in the addon to be owned by the addon user and to be apart
# of the addon group.
# Initially only the owner can access to addon files. If files needs other
# permissions they should be set explicitly e.g. WEB_FOLDER, /usr/bin and
# etc
local addon_sub_file addon_sub_file
chown $OPKGNAME:addon $INSTALL_DIR ||
revert_and_fail $ERR_FILE_SYSTEM "Failed to change owner of the addon to $OPKGNAME"
for addon_sub_file in $(find -H $INSTALL_DIR -type f); do
addon_sub_dir=${addon_sub_file%/*}
if [ $addon_sub_dir != $INSTALL_DIR/usr/lib ];then
chown $OPKGNAME:addon $addon_sub_file
chown $OPKGNAME:addon $addon_sub_dir
chmod $PERM_OTHER $addon_sub_file
fi
done
# Apache needs executable permissions for all directories in the full
# path to $WEB_FOLDER and the $WEB_FOLDER subdirectories
chmod $PERM_EXECDIR $INSTALL_DIR ||
revert_and_fail $ERR_FILE_SYSTEM "Failed to set executable permission for $INSTALL_DIR"
chmod $PERM_EXECDIR $INSTALL_DIR/usr ||
revert_and_fail $ERR_FILE_SYSTEM "Failed to set executable permission for $INSTALL_DIR/usr"
# Systemd will execute the addon service as the addon user, so only the
# addon user should have permission to execute the addon binaries
chmod -R $PERM_BINFILES $INSTALL_DIR/usr/bin/* ||
revert_and_fail $ERR_FILE_SYSTEM "Failed to set file permission for addon binaries"
}
configure_web_folder() {
# Expose folder http to web server
# Create it if user addon do not supply it
WEB_FOLDER=$INSTALL_DIR/usr/http
mkdir -p $WEB_FOLDER || revert_and_fail "Could not create dir: $WEB_FOLDER"
# Create web_folder configuration dir
HTTP_CONF_DIR=$INSTALL_DIR/usr/conf
mkdir -p $HTTP_CONF_DIR || revert_and_fail "Could not create dir: $HTTP_CONF_DIR"
ln -sfn $WEB_FOLDER $WEB_ROOT$OPKGNAME > /dev/null 2>&1 ||
revert_and_fail $ERR_FILE_SYSTEM "Failed to configure web server for $OPKGNAME"
}
configure_license() {
local lic_file urls_list
[ $# -eq 1 ] || revert_and_fail $ERR_FILE_SYSTEM 'Missing url list while configuring license'
urls_list=$1
# Expose the LICENSE file to web server
lic_file=$(get_path /$OPKGNAME/LICENSE) || revert_and_fail 'No license file'
# The license file should be owned by the addon user but be part of the
# www group so Apache can read it
chown $OPKGNAME:www $lic_file ||
revert_and_fail $ERR_FILE_SYSTEM 'Failed to set ownership of the license file'
# Set permission 640 for license file so Apache can read it from the www
# group
chmod $PERM_LICFILE $lic_file ||
revert_and_fail $ERR_FILE_SYSTEM 'Failed to file permissions for the license file'
ln -sf $lic_file $WEB_FOLDER/LICENSE > /dev/null 2>&1 ||
revert_and_fail $ERR_FILE_SYSTEM 'Failed to expose license'
urls_list=$(append_addon_url_configuration LICENSE viewer "$urls_list")
echo "$urls_list"
}
create_rewrite_webroot_conf_file() {
# Will take create conf file that contain rewrite rule
# to make mainPage as webRoot.
#
# $1 MainPage file
#
local rewrite_file=$HTTP_CONF_DIR/$ADDON_MAIN_REWRITE_FILE
local tmp_file=$rewrite_file.tmp
rm -f $tmp_file
echo "RewriteCond \"%{REQUEST_URI}\" !^/admin/?
RewriteRule \"^/$\" \"/local/$OPKGNAME/$1\" [L]" >$tmp_file ||
revert_and_fail $ERR_FILE_SYSTEM "Could not create file: $ADDON_MAIN_REWRITE_FILE"
fsynced_write_or_cleanup $tmp_file $rewrite_file
}
create_rewrite_alt_root_conf_file() {
# Will create second configuration file
# which contains alternative webroots. Meaning
# other URLs will point to the main addon webroot and addon server-root.
#
local alternative_webroot=//Supplies/WebContent/AlternativeRoot i=0
local main_webpage=//MainPage count=0 url_to_redirect main_webpage_file
local alt_webroot_conf_file=$HTTP_CONF_DIR/40_addon_webroot_alt_$OPKGNAME.conf
local tmp_file=$alt_webroot_conf_file.tmp
main_webpage_file=$(get_manifest_xpath "string($main_webpage)") ||
revert_and_fail 'Fail to extract main webpage file from manifest'
main_webpage_file=${main_webpage_file##*/}
count=$(get_manifest_xpath "count($alternative_webroot)") ||
revert_and_fail $ERR_MANIFEST 'Fail to extract alternativeWebroot from manifest'
# Strip away local (ip/local/addon) if either of the files are or to be created.
rm -f $tmp_file
[ ! -f $ADDON_MAIN_REWRITE_FILE ] && [ $count -lt 1 ] || {
echo "RewriteRule ^/$OPKGNAME/?\$ /local/$OPKGNAME/$main_webpage_file [L]
RewriteRule ^/$OPKGNAME/(.*)\$ /local/$OPKGNAME/\$1 [N] " >$tmp_file || revert_and_fail $ERR_FILE_SYSTEM "Could not create file: $tmp_file"
}
while [ $i -lt $count ]; do
i=$(($i + 1))
url_to_redirect=$(get_manifest_xpath "string($alternative_webroot[$i])") ||
revert_and_fail $ERR_MANIFEST 'Fail to extract AlternativeRoot name from manifest'
echo "RewriteRule ^$url_to_redirect/?\$ /local/$OPKGNAME/$main_webpage_file [L]
RewriteRule ^$url_to_redirect/(.*)\$ /local/$OPKGNAME/\$1 [N]" >>$tmp_file ||
revert_and_fail $ERR_FILE_SYSTEM "Could not append to file: $tmp_file"
done
[ -f $tmp_file ] &&
fsynced_write_or_cleanup $tmp_file $alt_webroot_conf_file
# Create the symbolic links.
create_rewrites_symlinks $OPKGNAME
}
configure_fcgis() {
local fcgiUrl=//Supplies/Fcgis/Url count i=0 fcgi_file aliasurl aliasconf aliasconf_tmp fcgis_list fcgis_handlers_list
[ -d "$WEB_FOLDER" ] ||
revert_and_fail "Web folder $WEB_FOLDER doesn't exist"
FCGI_SOCK=$WEB_FOLDER/${OPKGNAME}_fcgi.socket
touch $FCGI_SOCK || revert_and_fail $ERR_FILE_SYSTEM "Failed to create fastcgi socket"
count=$(get_manifest_xpath "count($fcgiUrl)") ||
revert_and_fail $ERR_MANIFEST 'Fail to extract fcgi data from manifest'
# In case of upgrade, remove previous alias and create new
remove_addon_url_alias $OPKGNAME || revert_and_fail $ERR_FILE_SYSTEM "Failed to delete previous alias file"
aliasconf=$ALIAS_CONF_DIR/$OPKGNAME.conf
aliasconf_tmp=$aliasconf.tmp
while [ $i -lt $count ]; do
i=$(($i + 1))
fcgi_file=$(get_manifest_xpath "string($fcgiUrl[$i])") ||
revert_and_fail $ERR_MANIFEST 'Fail to extract fcgi file from manifest'
# TODO: The WSDL or DTD shall check that only valid group names are used
group=$(get_manifest_xpath "string($fcgiUrl[$i]/@AccessGroup)") ||
revert_and_fail $ERR_MANIFEST 'Fail to extract fcgi group from manifest'
aliasurl=$(get_manifest_xpath "string($fcgiUrl[$i]/@AlternativeUrl)") || {
# This warning will only occur if the function failed to extract
# the AlternativeUrl value. If the argument is not present in
# the manifest it will exit with a zero status.
syslog_warn $LOG_TAG "Failed to get AlternativeUrl for $fcgi_file"
}
touch $WEB_FOLDER/$fcgi_file || revert_and_fail $ERR_FILE_SYSTEM "Failed to create fast CGI alias $fcgi_file"
[ -z "$aliasurl" ] || echo "Alias $aliasurl $WEB_DOCUMENT_ROOT/local/$OPKGNAME/$fcgi_file" >> $aliasconf_tmp
fcgi_file=${fcgi_file##*/}
fcgis_handlers_list=$(append_addon_fcgi_handler_configuration $fcgi_file $FCGI_SOCK "$fcgis_handlers_list") || revert_and_fail $ERR_CREATE_FCGI "Missing arguments"
fcgis_list=$(append_addon_fcgi_configuration $fcgi_file $group "$fcgis_list") || revert_and_fail $ERR_CREATE_FCGI "Missing arguments"
done
[ "$fcgis_list" ] && [ "$fcgis_handlers_list" ] && {
create_addon_fcgis_handlers_configuration $OPKGNAME "$fcgis_handlers_list" || revert_and_fail $ERR_CREATE_FCGI 'Failed to create FCGI handlers configuration'
create_addon_fcgis_configuration $OPKGNAME "$fcgis_list" ||
revert_and_fail $ERR_CREATE_FCGI 'Failed to create FCGI configuration'
}
# If needed, move alias tmp config file to real config file.
# Reload of Apache HTTPD will be done in the end of the installation
[ ! -f $aliasconf_tmp ] || {
mv $aliasconf_tmp $aliasconf || revert_and_fail $ERR_CREATE_FCGI 'Failed to move configuration file'
}
}
configure_main_webpage() {
local main_webpage=//MainPage main_webpage_file group urls_list is_webroot i=0
[ "$1" ] || revert_and_fail $ERR_FILE_SYSTEM 'Missing url list while configuring main webpage'
urls_list=$1
count=$(get_manifest_xpath "count(//$main_webpage)") ||
revert_and_fail 'Fail to extract webpages data from manifest'
if [ $count -eq 1 ]; then
main_webpage_file=$(get_manifest_xpath "string($main_webpage)") ||
revert_and_fail 'Fail to extract main webpage file from manifest'
[ -f "$WEB_FOLDER/$main_webpage_file" ] ||
revert_and_fail "$WEB_FOLDER/$main_webpage_file doesn't exist"
main_webpage_file=${main_webpage_file##*/}
is_webroot=$(get_manifest_xpath "boolean($main_webpage/@WebRoot)")
[ "$is_webroot" != true ] ||
create_rewrite_webroot_conf_file $main_webpage_file
group=$(get_manifest_xpath "string($main_webpage/@AccessGroup)") ||
revert_and_fail 'Fail to extract main_webpage group from manifest'
urls_list=$(append_addon_url_configuration $main_webpage_file $group "$urls_list") || revert_and_fail $ERR_CREATE_URL "Failed to append url entry for main webpage '$main_webpage_file'"
fi
echo "$urls_list"
}
configure_webpages() {
local webpage=//Page count webpage_file group i=0 urls_list
[ "$1" ] || revert_and_fail $ERR_FILE_SYSTEM "Missing url list while configuring main webpage"
urls_list=$1
count=$(get_manifest_xpath "count($webpage)") ||
revert_and_fail 'Fail to extract webpages data from manifest'
while [ $i -lt $count ]; do
i=$(($i + 1))
webpage_file=$(get_manifest_xpath "string($webpage[$i])") ||
revert_and_fail 'Fail to extract webpage file from manifest'
[ -f "$WEB_FOLDER/$webpage_file" ] ||
revert_and_fail "$WEB_FOLDER/$webpage_file doesn't exist"
webpage_file=${webpage_file##*/}
group=$(get_manifest_xpath "string($webpage[$i]/@AccessGroup)") ||
revert_and_fail 'Fail to extract webpage group from manifest'
urls_list=$(append_addon_url_configuration $webpage_file $group "$urls_list") ||
revert_and_fail $ERR_CREATE_URL "Failed to add url entry for file '$webpage_file'"
done
echo "$urls_list"
}
configure_urls() {
local urls_list
configure_fcgis
urls_list=$(configure_license "$urls_list")
urls_list=$(configure_main_webpage "$urls_list")
urls_list=$(configure_webpages "$urls_list")
create_addon_urls_configuration $OPKGNAME "$urls_list" ||
revert_and_fail $ERR_CREATE_URL 'Failed to create URLS configuration'
}
clear_addon_configuration() {
remove_addon_configuration $OPKGNAME || :
}
configure_web_access() {
local web_sub_dir
# Sets all the access rights required for Apache to access the web folder
# and its content
# Change so WEB_FOLDER and its files are apart of the www group and is
# readable by the group.
chown -R $OPKGNAME:www $WEB_FOLDER ||
revert_and_fail $ERR_FILE_SYSTEM "Failed to change owner for $WEB_FOLDER and its content"
chmod -R $PERM_WEBFILES $WEB_FOLDER ||
revert_and_fail $ERR_FILE_SYSTEM "Failed to set permission for $WEB_FOLDER and its content"
chmod $PERM_WEBDIR $WEB_FOLDER ||
revert_and_fail $ERR_FILE_SYSTEM "Failed to set permission for $WEB_FOLDER and its content"
for web_sub_dir in $(find -H $WEB_FOLDER -type d); do
chmod $PERM_WEBDIR $web_sub_dir || revert_and_fail $ERR_FILE_SYSTEM "Failed to set permissions for $WEB_FOLDER sub directories"
done
}
# Mount the layers
mount_layers() {
# If the addon has layers defined
# Find each layer described in the layer tar of the addon
# and apply them in correct order.
local layer_tars upperdir workdir mergeddir lowerdir layer layer_dir
local lower_layer= layers_dir=/opt/layers tmp_dir layer_tar
local lower_tmp diff_tmp
tmp_dir=$(mktemp -d) || revert_and_fail "$ERR_INSTALL_ERROR" "Failed to create tmp_dir"
mkdir -p $layers_dir || revert_and_fail "$ERR_INSTALL_ERROR" "Failed to create $layers_dir"
tar -C $tmp_dir -xf /opt/$OPKGNAME/usr/misc/layer/oci_layers.tar ||
revert_and_fail "$ERR_INSTALL_ERROR" "Layers file is missing"
layer_tars=$(sed -e 's/.*"Layers":\[\([^]]*\)\].*/\1/' -e 's/,/ /g' -e 's/"//g' $tmp_dir/manifest.json)
# Support any amount of layers
for layer_tar in $layer_tars; do
layer=${layer_tar%/layer.tar}
layer_dir=$layers_dir/$layer
if [ ! -d $layer_dir ]; then
mkdir -p $layer_dir/ref ||
revert_and_fail "$ERR_INSTALL_ERROR" "Failed to create $layer_dir/ref"
mkdir -p $layer_dir/work ||
revert_and_fail "$ERR_INSTALL_ERROR" "Failed to create $layer_dir/work"
[ -z $lower_layer ] || {
lower_tmp=$layer_dir/lower.tmp
rm -f $lower_tmp
[ ! -f $layer_dir/lower ] || cat $layer_dir/lower >$lower_tmp ||
revert_and_fail "$ERR_INSTALL_ERROR" "Failed to write to $lower_tmp"
echo "$layers_dir/$lower_layer" >>$lower_tmp ||
revert_and_fail "$ERR_INSTALL_ERROR" "Failed to append to $lower_tmp"
fsynced_write_or_cleanup $lower_tmp $layer_dir/lower
}
diff_tmp=$layer_dir/diff.tmp
[ ! -d $layer_dir/diff ] || rm -rf $layer_dir/diff 2>&1
rm -rf $diff_tmp 2>&1
mkdir -p $diff_tmp ||
revert_and_fail "$ERR_INSTALL_ERROR" "Failed to create $diff_tmp"
tar -C $diff_tmp -xf $tmp_dir/$layer_tar
sync
mv $diff_tmp $layer_dir/diff || {
rm -rf $diff_tmp 2>&1
revert_and_fail "$ERR_INSTALL_ERROR" "Failed to mv tmp to $layer_dir/diff"
}
fsync $layer_dir || {
rm -rf $diff_tmp 2>&1
revert_and_fail "$ERR_INSTALL_ERROR" "Failed to fsync $layer_dir"
}
fi
[ -z $lower_layer ] || >$layers_dir/$lower_layer/ref/$layer
lower_layer=$layer
done
rm -rf $tmp_dir
upperdir=$layer_dir/diff
workdir=$layer_dir/work
mergeddir=/opt/$OPKGNAME
while [ -f $layer_dir/lower ]; do
[ -r $layer_dir/lower ] ||
revert_and_fail $ERR_INSTALL_ERROR "Cannot mount addon layers"
read layer_dir <$layer_dir/lower
lowerdir=${lowerdir:+$lowerdir:}$layer_dir/diff
done
# If there is only one layer
lowerdir=${lowerdir:-$upperdir}
rm -rf $mergeddir/*
local mount_options="lowerdir=$lowerdir,upperdir=$upperdir,workdir=$workdir $mergeddir"
mount -t overlay overlay -o $mount_options ||
revert_and_fail "$ERR_INSTALL_ERROR" "Mounting of filesystem failed"
sed -i '$ a overlay '$mergeddir' overlay '"$mount_options"' 0 0' /etc/fstab
fsync /etc/fstab
# Mark addon as layered
echo "${upperdir%/diff}" >>"$mergeddir/.layered"
}
extract_manifest_basic_data
verify_dbus_dependencies
# Check if add-on user exists
get_uid_for_user $OPKGNAME result || revert_and_fail $ERR_INSTALL_ERROR "Failed to check if Add-on user $OPKGNAME exists"
sec_groups=$(get_secondary_groups)
if [ $result -eq -1 ]; then
# If the add-on user doesn't exist create it
syslog_notice $LOG_TAG "Add-on $OPKGNAME does not exist - create addon user"
create_addon_user $OPKGNAME "$sec_groups" || revert_and_fail $ERR_INSTALL_ADDON_USER "Failed to create user $OPKGNAME"
elif [ $result -ge 500 ]; then
# If the user exists and is not permanent, it needs to be updated
# with correct groups in case requirements have changed.
syslog_notice $LOG_TAG "Add-on $OPKGNAME exist - update addon user groups - $sec_groups"
update_addon_user_groups $OPKGNAME "$sec_groups" || revert_and_fail $ERR_INSTALL_ADDON_USER "Failed to update user $OPKGNAME"
fi
# Mount layers
if [ -d /opt/$OPKGNAME/usr/misc/layer/ ]; then
mount_layers
# Configure required resources
generate_dbus_access_file
# Configures access rights for the addon files
configure_layered_addon_access
else
generate_dbus_access_file
# Configures access rights for the addon files
configure_addon_access
fi
# Create web content and configure access rights
configure_web_folder
clear_addon_configuration
configure_urls
create_rewrite_alt_root_conf_file
configure_web_access
configure_linux_cap
reload_httpd
# Systemd service files
generate_services_file