#!/bin/sh /etc/rc.common # shellcheck shell=ash # cspell:words CFGDIR SYSCFG USRCFG cfgfile chgrp defval getline hostlist # cspell:words htpasswd radicale tmpconf tmpusers multifilesystem # shellcheck disable=SC2034 START=99 USE_PROCD=1 PROG=/usr/bin/radicale3 CFGDIR=/var/etc/radicale3 SYSCFG=$CFGDIR/config USRCFG=$CFGDIR/users DATADIR="/var/radicale3/data" conf_line() { local cfgfile="$1" local option="$2" local value="$3" if [ -n "$value" ]; then echo "$option = $value" >> "$cfgfile" fi } conf_getline() { local cfg="$1" local cfgfile="$2" local option="$3" local defval="$4" local boolean="$5" # Note: $value is used by the caller, so we do not declare it local here. unset value if [ "$boolean" != "1" ]; then config_get value "$cfg" "$option" "$defval" conf_line "$cfgfile" "$option" "$value" else config_get_bool value "$cfg" "$option" "$defval" # config_get_bool returns 0/1 in value if [ -n "$value" ]; then if [ "$value" -eq 1 ]; then conf_line "$cfgfile" "$option" "True" else conf_line "$cfgfile" "$option" "False" fi fi fi } build_hosts_line() { local val="$1" append hostlist "$val" ", " } conf_section() { local cfg="$1" local cfgfile="$2" local hostlist="" local value echo "[$cfg]" >> "$cfgfile" case $cfg in server) config_list_foreach "$cfg" host build_hosts_line conf_line "$cfgfile" hosts "$hostlist" conf_getline "$cfg" "$cfgfile" max_connections conf_getline "$cfg" "$cfgfile" max_content_length conf_getline "$cfg" "$cfgfile" timeout conf_getline "$cfg" "$cfgfile" ssl 0 1 if [ "$value" -eq 1 ]; then conf_getline "$cfg" "$cfgfile" certificate if [ "$value" != "" ]; then chgrp radicale3 "$value" chmod g+r "$value" fi conf_getline "$cfg" "$cfgfile" key if [ "$value" != "" ]; then chgrp radicale3 "$value" chmod g+r "$value" fi conf_getline "$cfg" "$cfgfile" certificate_authority if [ "$value" != "" ]; then chgrp radicale3 "$value" chmod g+r "$value" fi conf_getline "$cfg" "$cfgfile" protocol conf_getline "$cfg" "$cfgfile" ciphers fi ;; encoding) conf_getline "$cfg" "$cfgfile" request conf_getline "$cfg" "$cfgfile" stock ;; auth) conf_getline "$cfg" "$cfgfile" "type" htpasswd if [ "$value" = "htpasswd" ]; then conf_getline "$cfg" "$cfgfile" htpasswd_filename "$USRCFG" conf_getline "$cfg" "$cfgfile" htpasswd_encryption plain fi conf_getline "$cfg" "$cfgfile" realm conf_getline "$cfg" "$cfgfile" delay ;; rights) conf_getline "$cfg" "$cfgfile" "type" if [ "$value" = "from_file" ]; then conf_getline "$cfg" "$cfgfile" "file" fi ;; storage) conf_getline "$cfg" "$cfgfile" filesystem_folder "$DATADIR" # Update global DATADIR if user specified a custom one, so we can mkdir it later if [ -n "$value" ]; then DATADIR="$value" fi conf_getline "$cfg" "$cfgfile" type conf_getline "$cfg" "$cfgfile" max_sync_token_age conf_getline "$cfg" "$cfgfile" hook ;; web) conf_getline "$cfg" "$cfgfile" "type" ;; logging) conf_getline "$cfg" "$cfgfile" level info 0 conf_getline "$cfg" "$cfgfile" trace_on_debug 0 1 conf_getline "$cfg" "$cfgfile" mask_passwords 1 1 ;; headers) config_get cors "$cfg" cors if [ -n "$cors" ]; then echo "Access-Control-Allow-Origin = $cors" >> "$cfgfile" fi ;; esac echo "" >> "$cfgfile" } add_missing_sections() { local cfgfile="$1" for section in server encoding auth rights storage web logging headers; do if ! grep -q "\[$section\]" "$cfgfile"; then echo "[$section]" >> "$cfgfile" case $section in server) echo "hosts = 127.0.0.1:5232, [::1]:5232" >> "$cfgfile" ;; auth) echo "type = htpasswd" >> "$cfgfile" echo "htpasswd_filename = $USRCFG" >> "$cfgfile" echo "htpasswd_encryption = plain" >> "$cfgfile" ;; storage) echo "filesystem_folder = $DATADIR" >> "$cfgfile" ;; esac echo "" >> "$cfgfile" fi done } add_user() { local cfg="$1" local tmpfile="$2" local name password config_get name "$cfg" name config_get password "$cfg" password [ -n "$name" ] && echo "$name:$password" >> "$tmpfile" } build_users() { local tmpfile="$1" config_foreach add_user user "$tmpfile" } build_config() { local tmpconf local tmpusers tmpconf=$(mktemp) tmpusers=$(mktemp) chmod 0640 "$tmpconf" "$tmpusers" config_load radicale3 config_foreach conf_section section "$tmpconf" add_missing_sections "$tmpconf" build_users "$tmpusers" # Apply permissions mkdir -p "$CFGDIR" chmod 0750 "$CFGDIR" chgrp radicale3 "$CFGDIR" cat "$tmpconf" > "$SYSCFG" cat "$tmpusers" > "$USRCFG" chmod 0640 "$SYSCFG" "$USRCFG" chgrp radicale3 "$SYSCFG" "$USRCFG" rm -f "$tmpconf" "$tmpusers" } prepare_config() { # If custom config (/etc/radicale3/config) absent, build it from UCI if [ ! -f /etc/radicale3/config ]; then build_config CFG_FILE="$SYSCFG" # Ensure data dir exists (DATADIR might have been updated by build_config) mkdir -p "$DATADIR" chown radicale3:radicale3 "$DATADIR" else CFG_FILE="/etc/radicale3/config" # We assume user handles directory creation if using manual config, # but we could attempt it if we parsed it. simpler to leave it for now. fi } start_service() { prepare_config procd_open_instance procd_set_param command "$PROG" --config "$CFG_FILE" procd_set_param user radicale3 procd_set_param respawn procd_set_param stdout 1 procd_set_param stderr 1 procd_close_instance } reload_service() { prepare_config if pgrep radicale3 >/dev/null 2>/dev/null; then procd_send_signal radicale3 '*' HUP else start_service fi } service_triggers() { procd_add_reload_trigger "radicale3" }