#!/bin/bash # shellcheck disable=SC2046,SC2006,SC2268,SC2009 # SC2046: Quote this to prevent word splitting. # SC2006: Use $(...) notation instead of legacy backticks `...`. # SC2268: Avoid x-prefix in comparisons as it no longer serves a purpose. # SC2009: Consider using pgrep instead of grepping ps output. GETCFG=/sbin/getcfg SETCFG=/sbin/setcfg AVAHI_DAEMON=/usr/sbin/avahi-daemon AVAHI_CONF_DIR=/etc/avahi/services /sbin/test -f ${AVAHI_DAEMON} || exit 0 AVAHI_PID_FILE="/var/run/avahi-daemon/pid" AVAHI_SET_LOCK_FILE="/var/lock/avahi_set_conf.lock" HBS_INSTALL_PATH=$(${GETCFG} HybridBackup Install_Path -d FALSE -f /etc/config/qpkg.conf) HBS_TM_CONF="${HBS_INSTALL_PATH}/timemachine.conf" HSB_TM_LOG_FILE="${HBS_INSTALL_PATH}/logs/tm.log" LOG_DUP_STDOUT=y # flag for app_log() duplicate to stdout function log_info() { # log information to app's log file /bin/echo "[$(date '+%Y/%m/%d %H:%M:%S')] [$$] $*" >> "$HSB_TM_LOG_FILE" [ -n "${LOG_DUP_STDOUT}" ] && /bin/echo "[$(date '+%Y/%m/%d %H:%M:%S')] [$$] $*" } function log_err() { # log error to app's log file /bin/echo "[$(date '+%Y/%m/%d %H:%M:%S')] [$$] [E] $*" >> "$HSB_TM_LOG_FILE" [ -n "${LOG_DUP_STDOUT}" ] && /bin/echo "[$(date '+%Y/%m/%d %H:%M:%S')] [$$] [E] $*" } function print_caller() { if [ -d "/proc/$PPID" ] && [ -f "/proc/$PPID/cmdline" ]; then log_info "caller:$PPID ($(/bin/cat /proc/$PPID/cmdline) $*)" else log_info "caller:$PPID" fi } function is_enabled_ulinux_tm() { if [ "$(${GETCFG} "TimeMachine" Enabled -d FALSE)" = "TRUE" ]; then return 0 # true else return 1 # false fi } function is_enabled_hbs_tm() { if [ "$(${GETCFG} "Global" Enable -d FALSE -f "${HBS_TM_CONF}")" = "TRUE" ]; then return 0 # true else return 1 # false fi } function is_bonjour_tm_smb() { if [ "$(${GETCFG} "Global" BonjourSMB -d FALSE -f "${HBS_TM_CONF}")" = "TRUE" ]; then return 0 # true else return 1 # false fi } function is_bonjour_tm_afp() { if [ "$(${GETCFG} "Global" BonjourAFP -d FALSE -f "${HBS_TM_CONF}")" = "TRUE" ]; then return 0 # true else return 1 # false fi } function is_enabled_shared_account() { if [ "$(${GETCFG} "SharedAccount" Enable -d FALSE -f "${HBS_TM_CONF}")" = "TRUE" ]; then return 0 # true else return 1 # false fi } function is_capacity_limited(){ cap="$(${GETCFG} "SharedAccount" CapacityGB -d 0 -f "${HBS_TM_CONF}")" if [ "$cap" -gt 0 ]; then return 0 # true else return 1 # false fi } _renew_timemachine_share_folder() { _type=$1 # for logging _bonjour_hostname=$2 _tm_service_file=$3 # parse advf (samba) AD_CHECK=`${GETCFG} global "server role" -d "x" -f /etc/config/smb.conf` if [ "$AD_CHECK" == "active directory domain controller" ]; then _tm_advf=0xa1 else LDAP_ENABLE=`${GETCFG} "LDAP" "Enable" -d "FALSE"` SAMBA_AUTH=`${GETCFG} global "passdb backend" -d "x" -f /etc/config/smb.conf` if [ "x$LDAP_ENABLE" == "xTRUE" ] && [ "$SAMBA_AUTH" != "smbpasswd" ]; then _tm_advf=0xa1 else _tm_advf=0xa3 fi fi # service _adisk._tcp start /bin/cat >> "${_tm_service_file}" <<__EOF__ ${_bonjour_hostname} _adisk._tcp 9 __EOF__ _txt_rec_afp_param="" # shared account's shared folder (dk index 0) if is_enabled_shared_account; then log_info " ${_type} add folder 'TMBackup'" if is_bonjour_tm_afp; then # shellcheck disable=SC2086 uuid=`/bin/grep \"TMBackup\" /var/netatalk/afp_voluuid.conf 2>/dev/null | /bin/cut -f 2 -d$'\t'` if [ "x${uuid}" != "x" ]; then _txt_rec_afp_param=",adVU=${uuid}" else log_err "'TMBackup' no uuid" fi fi /bin/cat >> "${_tm_service_file}" <<__EOF__ dk0=adVN=TMBackup,adVF=${_tm_advf}${_txt_rec_afp_param} __EOF__ dk_index=1 else dk_index=0 fi # other shared folder # shellcheck disable=SC2162 /sbin/user_cmd -s | while read _share_name do tm=`${GETCFG} "${_share_name}" timemachine -d "no" -f /etc/config/smb.conf` if [ "${tm}" == "yes" ]; then log_info " ${_type} add folder '${_share_name}'" _txt_rec_afp_param="" if is_bonjour_tm_afp; then # shellcheck disable=SC2086 uuid=`/bin/grep \"${_share_name}\" /var/netatalk/afp_voluuid.conf 2>/dev/null | /bin/cut -f 2 -d$'\t'` if [ "x${uuid}" != "x" ]; then _txt_rec_afp_param=",adVU=${uuid}" else log_err "'${_share_name}' no uuid" fi fi # replace "homes" as "home" as backup folder by nas account if [ "${_share_name}" == "homes" ]; then _share_name="home" fi /bin/cat >> "${_tm_service_file}" <<__EOF__ dk$dk_index=adVN=${_share_name},adVF=${_tm_advf}${_txt_rec_afp_param} __EOF__ # shellcheck disable=SC2004 dk_index=$(($dk_index+1)) fi done # service _adisk._tcp end /bin/cat >> "${_tm_service_file}" <<__EOF__ __EOF__ } # version_ge: Check if version $1 >= $2 # Returns 0 (true) if v1 >= v2, 1 (false) otherwise # Compatible with POSIX sh and older systems without sort -V version_ge() { _vge_v1=$1 _vge_v2=$2 # Handle empty versions [ -z "$_vge_v1" ] && _vge_v1="0" [ -z "$_vge_v2" ] && _vge_v2="0" # Compare each segment using parameter expansion (POSIX compatible) _vge_remain1=$_vge_v1 _vge_remain2=$_vge_v2 while :; do # Extract first segment before '.' _vge_seg1=${_vge_remain1%%.*} _vge_seg2=${_vge_remain2%%.*} # Treat empty or non-numeric as 0 case "$_vge_seg1" in ''|*[!0-9]*) _vge_seg1=0 ;; esac case "$_vge_seg2" in ''|*[!0-9]*) _vge_seg2=0 ;; esac # Numeric comparison using arithmetic expansion for safety if [ $((_vge_seg1)) -gt $((_vge_seg2)) ]; then return 0 elif [ $((_vge_seg1)) -lt $((_vge_seg2)) ]; then return 1 fi # Check if we've processed all segments case "$_vge_remain1" in *.*) _vge_remain1=${_vge_remain1#*.} ;; *) _vge_remain1="" ;; esac case "$_vge_remain2" in *.*) _vge_remain2=${_vge_remain2#*.} ;; *) _vge_remain2="" ;; esac # Handle different segment counts explicitly # v1 exhausted but v2 has more -> v1 < v2 [ -z "$_vge_remain1" ] && [ -n "$_vge_remain2" ] && return 1 # v1 has more but v2 exhausted -> v1 > v2 [ -n "$_vge_remain1" ] && [ -z "$_vge_remain2" ] && return 0 # Both exhausted means equal, so v1 >= v2 is true [ -z "$_vge_remain1" ] && [ -z "$_vge_remain2" ] && return 0 done } _generate_avahi_tm_conf() { _type=$1 # prepare local var # After apply, use `avahi-browse -rt _adisk._tcp` to query mDNS for test _version=$(${GETCFG} System Version) # Get system version if version_ge "$_version" "5.3.0"; then # if fw >= 5.3.0 _hostname=$(${GETCFG} -f /etc/config.local/uLinux.conf System "Server Name") log_info " fw version: $_version. read hostname from /etc/config.local/uLinux.conf: $_hostname" else _hostname=$(${GETCFG} System "Server Name") fi if [ -z "$_hostname" ]; then /sbin/gen_hostname /bin/sync _hostname=`${GETCFG} System "Server Name"` fi if [ "$_type" = "basic" ]; then _bonjour_hostname="${_hostname}.local" _bonjour_name="${_hostname}(TimeMachine)" _tm_service_file="${AVAHI_CONF_DIR}/timemachine.service" elif [ "$_type" = "tbt" ]; then _bonjour_hostname="${_hostname}tbt.local" _bonjour_name="${_hostname}(TimeMachine)(Thunderbolt)" _tm_service_file="${AVAHI_CONF_DIR}/tbt.timemachine.service" fi # generate bonjour tm service file depend on hbs time machine setting /bin/cat > "${_tm_service_file}" <<__EOF__ ${_bonjour_name} __EOF__ _renew_timemachine_share_folder "$_type" "${_bonjour_hostname}" "${_tm_service_file}" if is_bonjour_tm_smb; then /bin/cat >> "${_tm_service_file}" <<__EOF__ ${_bonjour_hostname} _smb._tcp 445 __EOF__ fi if is_bonjour_tm_afp; then /bin/cat >> "${_tm_service_file}" <<__EOF__ ${_bonjour_hostname} _afpovertcp._tcp 548 __EOF__ fi /bin/cat >> "${_tm_service_file}" <<__EOF__ ${_bonjour_hostname} _device-info._tcp 0 model=Xserve __EOF__ } _clean_avahi_tm_conf() { /bin/rm -rf ${AVAHI_CONF_DIR}/timemachine.service >&/dev/null /bin/rm -rf ${AVAHI_CONF_DIR}/tbt.timemachine.service >&/dev/null } _set_avahi_tm_conf() { _clean_avahi_tm_conf if is_enabled_hbs_tm; then _generate_avahi_tm_conf "basic" if [ -x /sbin/hal_app ]; then if [ "x$(/sbin/hal_app --check_tbt_support)" = "xyes" ]; then if [ x`/bin/ls /sys/class/net/ | /bin/grep tbtbr` != "x" ]; then _generate_avahi_tm_conf "tbt" fi fi fi else log_info " timemachine bonjour setting is disabled" fi } # Compatible with smb.sh / atalk.sh, it read uLinux.conf [TimeMachine]. # Save hbs config to uLinux.conf before let smbd/afpd start script know # hbs's settings about shared account. _enable_ulinux_tm_conf() { log_info " [${FUNCNAME[0]}] begin" $SETCFG "TimeMachine" "Enabled" "TRUE" $SETCFG "TimeMachine" "Storage Type" "1" $SETCFG "TimeMachine" "User Name" "TimeMachine" if is_enabled_shared_account; then capGB="$(${GETCFG} "SharedAccount" CapacityGB -d 0 -f "${HBS_TM_CONF}")" $SETCFG "TimeMachine" "Capacity" "${capGB}" else $SETCFG "TimeMachine" "Capacity" "0" fi log_info " [${FUNCNAME[0]}] done" } _disable_ulinux_tm_conf() { log_info " [${FUNCNAME[0]}] begin" if is_enabled_ulinux_tm; then $SETCFG "TimeMachine" "Enabled" "FALSE" fi log_info " [${FUNCNAME[0]}] done" } avahi_tm_start() { log_info " [${FUNCNAME[0]}] begin" _set_avahi_tm_conf _avahi_daemon_reload log_info " [${FUNCNAME[0]}] done" } avahi_tm_stop() { log_info " [${FUNCNAME[0]}] begin" _clean_avahi_tm_conf _avahi_daemon_reload log_info " [${FUNCNAME[0]}] done" } _avahi_daemon_reload() { log_info " [${FUNCNAME[0]}] begin" CURRENT_AVAHI_PID=`/bin/cat ${AVAHI_PID_FILE} 2>/dev/null` if [ -n "$CURRENT_AVAHI_PID" ]; then if [ -f ${AVAHI_SET_LOCK_FILE} ]; then log_err " unexpect avahi lock file existed" return fi touch ${AVAHI_SET_LOCK_FILE} /bin/kill -HUP "$CURRENT_AVAHI_PID" 2>/dev/null 1>/dev/null rm -f ${AVAHI_SET_LOCK_FILE} else log_err " avahi not runing" fi log_info " [${FUNCNAME[0]}] done" } apply_hbs_tm_settings() { log_info "[${FUNCNAME[0]}] begin" case "$1" in enable) log_info " enable tm service" _enable_ulinux_tm_conf if is_enabled_shared_account; then if is_bonjour_tm_smb || is_capacity_limited; then log_info " smb restarting" /etc/init.d/smb.sh restart >/dev/null 2>/dev/null log_info " smb started" fi fi if is_bonjour_tm_afp; then log_info " atalk restarting" /etc/init.d/atalk.sh restart 1>/dev/null 2>/dev/null log_info " atalk started" fi # perform bonjour of timemachine service at least # to avoid avahi.sh setting the old design avahi_tm_start ;; disable) log_info " disable tm service" # QTSHBS00-3914 alway disable bonjour and uLinux.conf [TimeMachine] # when HBS qpkg disabled or timemachine global setting is off _disable_ulinux_tm_conf avahi_tm_stop ;; esac log_info "[${FUNCNAME[0]}] done" } cd "$HBS_INSTALL_PATH" &>/dev/null || (echo "install path not exist" && exit 1) print_caller "$@" if [ "$(${GETCFG} "Bonjour Service" Enable -d FALSE)" = "FALSE" ]; then log_err "Bonjour service disabled" fi case "$1" in apply) if is_enabled_hbs_tm; then apply_hbs_tm_settings "enable" else apply_hbs_tm_settings "disable" fi ;; stop) apply_hbs_tm_settings "disable" ;; restart) if is_enabled_hbs_tm; then apply_hbs_tm_settings "disable" apply_hbs_tm_settings "enable" else apply_hbs_tm_settings "disable" fi ;; *) if [ "$1" != "" ]; then $1 "$2" "$3" "$4" "$5"; else echo "" /bin/echo "Usage: $0 {apply|restart}" echo "" exit 1 fi esac exit 0