#!/bin/sh /etc/rc.common # Copyright (C) 2010-2025 OpenWrt.org START=85 STOP=10 USE_PROCD=1 PROG_netatalk='/usr/sbin/netatalk' # Default config file location config_file='/etc/afp.conf' # Config file contents and status afpd_config='' config_overwrite='' config_error=0 setup_error=0 # Log tag log_tag='afpd-init' # Configuration dictionary valid_global='|' valid_global=$valid_global'ad_domain|admin_auth_user|admin_group|force_user|force_group|k5_keytab|k5_service|k5_realm|' valid_global=$valid_global'nt_domain|nt_separator|save_password|set_password|uam_list|uam_path|mac_charset|unix_charset|' valid_global=$valid_global'vol_charset|passwd_file|passwd_minlen|afp_interfaces|afp_listen|afp_port|appletalk|' valid_global=$valid_global'cnid_listen|cnid_server|ddp_address|ddp_zone|disconnect_time|dsireadbuf|hostname|' valid_global=$valid_global'max_connections|sleep_time|chmod_request|dircachesize|extmap_file|' valid_global=$valid_global'force_xattr_with_sticky_bit|guest_account|ignored_attributes|legacy_icon|login_message|' valid_global=$valid_global'mimic_model|vol_dbpath|zeroconf_name|log_file|log_level|map_acls|ldap_auth_method|' valid_global=$valid_global'ldap_auth_dn|ldap_auth_pw|ldap_uri|ldap_userbase|ldap_userscope|ldap_groupbase|' valid_global=$valid_global'ldap_groupscope|ldap_uuid_attr|ldap_name_attr|ldap_group_attr|ldap_uuid_string|' valid_global=$valid_global'ldap_uuid_encoding|ldap_user_filter|ldap_group_filter|vol_dbnest|fce_ignore_names|' valid_homes='|basedir_regex|path|home_name|' valid_volume='|' valid_volume=$valid_volume'mac_charset|unix_charset|vol_charset|casefold|chmod_request|force_xattr_with_sticky_bit|' valid_volume=$valid_volume'ignored_attributes|login_message|vol_dbpath|path|server_name|vol_size_limit|valid_users|' valid_volume=$valid_volume'invalid_users|hosts_allow|hosts_deny|ea|password|file_perm|directory_perm|umask|preexec|' valid_volume=$valid_volume'postexec|root_preexec|root_postexec|rolist|rwlist|veto_files|acls|case_sensitive|prodos|' valid_volume=$valid_volume'read_only|time_machine|vol_dbnest|cnid_scheme|volume_name|' valid_share='share_name' NL=$'\n' generate_config() { # Save name of sections config_name='' global_name='' homes_name='' volume_names='' # Volume name validation share_names='' fixed_names='' # Call-back per section config_cb() { section_type="$1" section_name="$2" # Call-back per option option_cb() { local name="$1" local value="$2" # Validate options against dictionary of possible values if [ "$section_type" = 'setup' -a "$CONFIG_SECTION" = "$config_name" ]; then if [ "$name" = 'config_overwrite' ]; then if [ "$value" = "0" -o "$value" = "1" ]; then config_overwrite=$value else # Garbage on this option means we should not proceed no matter what logger -p err -t $log_tag "Invalid SETUP config_overwrite option: $value" setup_error=1 fi elif [ "$name" = 'config_file' ]; then config_file="$value" else config_error=1 && logger -p err -t $log_tag "Invalid SETUP configuration option: $name:$value" fi elif [ "$section_type" = 'global' -a "$CONFIG_SECTION" = "$global_name" ]; then case "$valid_global" in *'|'$name'|'*) afpd_config=$afpd_config"${name//_/ } = $value$NL" ;; *) config_error=1 && logger -p err -t $log_tag "Invalid GLOBAL configuration option: $name:$value" ;; esac elif [ "$section_type" = 'homes' -a "$CONFIG_SECTION" = "$homes_name" ]; then case "$valid_homes" in *'|'$name'|'*) afpd_config=$afpd_config"${name//_/ } = $value$NL" ;; *) config_error=1 && logger -p err -t $log_tag "Invalid HOMES configuration option: $name:$value" ;; esac elif [ "$section_type" = 'volume' ]; then if [ "$name" = "$valid_share" ]; then # Special case - share name... check for duplicates... track changes... fix heading. case "||$share_names" in *'||'$value'||'*) config_error=1 && logger -p err -t $log_tag "Duplicated share name $CONFIG_SECTION-$name:$value" ;; *) ;; esac share_names=$share_names"$value||" fixed_names=$fixed_names"$CONFIG_SECTION " afpd_config="${afpd_config//\[\[$CONFIG_SECTION\]\]/[$value]}" else case "$valid_volume" in *'|'$name'|'*) afpd_config=$afpd_config"${name//_/ } = $value$NL" ;; *) config_error=1 && logger -p err -t $log_tag "Invalid VOLUME $CONFIG_SECTION configuration option: $name:$value" ;; esac fi else config_error=1 && logger -p err -t $log_tag "Invalid option. Section: $CONFIG_SECTION ($section_type), option: $name:$value" fi } # Call-back per list - error, we don't use lists list_cb() { config_error=1 && logger -p err -t $log_tag "Invalid list in $CONFIG_SECTION: $1:$2" } # Identify sections and create section headers (placeholder for volumes) if [ "$section_type" = 'setup' ]; then # Find the name of the first (and only?) setup (control) section if [ -z "$config_name" ]; then config_name=$section_name else config_error=1 && logger -p err -t $log_tag 'Multiple SETUP sections defined' fi elif [ "$section_type" = 'global' ]; then # Find the name of the first (and only?) global section if [ -z "$global_name" ]; then global_name=$section_name [ -z "$afpd_config" ] || afpd_config=$afpd_config"$NL" afpd_config=$afpd_config"[Global]$NL" else config_error=1 && logger -p err -t $log_tag 'Multiple GLOBAL sections defined' fi elif [ "$section_type" = 'homes' ]; then # Find the name of the first (and only?) homes section if [ -z "$homes_name" ]; then homes_name=$section_name [ -z "$afpd_config" ] || afpd_config=$afpd_config"$NL" afpd_config=$afpd_config"[Homes]$NL" else config_error=1 && logger -p err -t $log_tag 'Multiple HOMES sections defined' fi elif [ "$section_type" = 'volume' ]; then # Collect the names of the volume sections volume_names=$volume_names"$section_name " [ -z "$afpd_config" ] || afpd_config=$afpd_config"$NL" afpd_config=$afpd_config"[[$section_name]]$NL" elif [ "$section_type" != '' ]; then # It's not the end of file config_error=1 && logger -p err -t $log_tag "Invalid $section_type section defined" fi } # Load config (trigger callbacks) config_load afpd # config_overwrite is messed up... don't know what to do if [ "$setup_error" -eq 1 ]; then exit 1 fi # So, should we? Shouldn't? Nobody said but gave us share details. [ -z "$config_overwrite" ] && [ -n "$volume_names" -o -n "$homes_name" ] && { logger -p warn -t $log_tag "No valid config_overwrite at SETUP config. Ignoring defined VOLUMES and/or HOMES" } # Only update configuration file if UCI config asks for it build_config=$(expr "${config_overwrite}" == "1") if [ "$build_config" -eq 1 ]; then # One last check for valid volume names [ "$volume_names" = "$fixed_names" ] || { config_error=1 && logger -p err -t $log_tag "Not all volumes have valid option $valid_share" } # Continue only if configuration was decent - any errors were logged already if [ "$config_error" -eq 1 ]; then exit 1 fi # Create file mkdir -p `dirname "$config_file"` echo "$afpd_config" > "$config_file" logger -p info -t $log_tag "Configuration written to $config_file" else logger -p info -t $log_tag 'Configuration not modified - setup:config_overwrite=0 or missing' fi } start_service() { mkdir -p /var/netatalk/CNID/ generate_config procd_open_instance procd_set_param command $PROG_netatalk -d -F $config_file procd_set_param file $config_file procd_set_param respawn procd_close_instance }