Dev Docs Netatalk Controller Daemon
Netatalk Controller Daemon
Overview
The netatalk daemon serves as the coordinator for all Netatalk services. It manages service lifecycle, configuration, process supervision, and graceful shutdown coordination. This daemon was introduced to provide centralized management of the various Netatalk components.
Implementation Files
etc/netatalk/netatalk.c- Main master daemon implementation and service coordinationetc/netatalk/netatalk.h- Master daemon definitions and structuresetc/netatalk/afp_config.c- Configuration parsing and managementetc/netatalk/afp_options.c- Command-line option processinglibatalk/util/server_child.c- Child process management utilities
Architecture
Master-Coordinator Design
graph TB
subgraph "netatalk Master Daemon"
A[Configuration Manager]
B[Service Coordinator]
C[Process Supervisor]
D[Event Handler]
E[Signal Handler]
end
subgraph "Managed Services"
F[afpd - AFP Daemon]
G[cnid_metad - CNID Metadata]
H[dbus - D-Bus Integration]
I[Spotlight Services]
end
subgraph "External Dependencies"
J[Avahi/mDNS]
K[GNOME Tracker]
L[System D-Bus]
end
subgraph "CNID Database"
M[cnid_dbd - CNID Database Access Daemon]
end
A --> B
B --> C
C --> F
C --> G
C --> H
D --> E
B --> I
I --> J
I --> K
G --> M
H --> L
Core Functionality
Implementation Files
etc/netatalk/service.c- Service lifecycle management and coordinationlibatalk/util/daemon.c- Daemon utilities and process controlinclude/atalk/service.h- Service management definitions
1. Service Management
The master daemon manages the lifecycle of all Netatalk services:
// Service state definitions
typedef enum {
NETATALK_SRV_NEEDED = -1, // Required service
NETATALK_SRV_OPTIONAL = 0, // Optional service
NETATALK_SRV_ERROR = -1 // Error state
} service_state_t;
// Service tracking structure
struct service_info {
const char *name; // Service name
const char *path; // Executable path
pid_t pid; // Process ID
service_state_t required; // Required/optional flag
uint restart_count; // Restart counter
time_t last_start; // Last start time
bool enabled; // Service enabled flag
};
2. Process Supervision
Startup Sequence
sequenceDiagram
participant Init as System Init
participant Master as netatalk
participant CNID as cnid_metad
participant AFP as afpd
participant DBus as D-Bus Service
Init->>Master: Start netatalk
Master->>Master: Parse configuration
Master->>CNID: Start CNID metadata daemon
CNID-->>Master: CNID service ready
Master->>AFP: Start AFP daemon
AFP-->>Master: AFP service ready
Master->>DBus: Start D-Bus integration
DBus-->>Master: D-Bus service ready
Master->>Master: Register signal handlers
Note over Master: All services running
Service Monitoring
// Process monitoring implementation
static void monitor_services(void) {
// Check AFP daemon
if (!service_running(afpd_pid)) {
if (afpd_pid == NETATALK_SRV_NEEDED) {
LOG(log_error, "AFP daemon required but not running");
restart_service("afpd");
}
}
// Check CNID metadata daemon
if (!service_running(cnid_metad_pid)) {
if (cnid_metad_pid == NETATALK_SRV_NEEDED) {
LOG(log_error, "CNID metadata daemon required but not running");
restart_service("cnid_metad");
}
}
// Check optional services
if (dbus_enabled && !service_running(dbus_pid)) {
LOG(log_info, "D-Bus service not running, attempting restart");
restart_service("dbus");
}
}
3. Configuration Management
Configuration Loading
// Configuration structure
struct netatalk_config {
struct afp_config afp; // AFP daemon configuration
struct cnid_config cnid; // CNID system configuration
struct spotlight_config sl; // Spotlight configuration
struct global_config global;// Global settings
bool services_enabled[SERVICE_COUNT];
char *config_file; // Configuration file path
time_t config_mtime; // Config modification time
};
// Configuration reload handling
static void reload_configuration(void) {
struct stat st;
if (stat(config.config_file, &st) == 0) {
if (st.st_mtime > config.config_mtime) {
LOG(log_info, "Configuration file changed, reloading");
// Parse new configuration
struct netatalk_config new_config;
if (parse_config_file(&new_config) == 0) {
// Apply configuration changes
apply_config_changes(&config, &new_config);
config = new_config;
config.config_mtime = st.st_mtime;
}
}
}
}
4. Signal Handling
Graceful Shutdown Process
sequenceDiagram
participant System as System Signal
participant Master as netatalk
participant AFP as afpd
participant CNID as cnid_metad
participant DBus as D-Bus Service
System->>Master: SIGTERM
Master->>Master: Set shutdown flag
Master->>AFP: SIGTERM (graceful)
Master->>CNID: SIGTERM (graceful)
Master->>DBus: SIGTERM (graceful)
Note over Master: Wait for graceful shutdown
alt Graceful shutdown successful
AFP-->>Master: Process exit
CNID-->>Master: Process exit
DBus-->>Master: Process exit
else Timeout exceeded
Master->>AFP: SIGKILL (forced)
Master->>CNID: SIGKILL (forced)
Master->>DBus: SIGKILL (forced)
end
Master->>Master: Cleanup and exit
Signal Handler Implementation
// Signal handling for graceful shutdown
static void handle_sigterm(int sig) {
LOG(log_info, "Received SIGTERM, initiating graceful shutdown");
in_shutdown = 1;
// Send SIGTERM to all child processes
kill_childs(SIGTERM, afpd_pid, cnid_metad_pid, dbus_pid, 0);
// Set timer for graceful shutdown period
struct timeval tv;
tv.tv_sec = KILL_GRACETIME;
tv.tv_usec = 0;
if (timer_ev) {
event_add(timer_ev, &tv);
}
}
// Forced shutdown if graceful shutdown times out
static void handle_timer(int fd, short event, void *arg) {
if (in_shutdown) {
LOG(log_warning, "Graceful shutdown timeout, forcing termination");
kill_childs(SIGKILL, afpd_pid, cnid_metad_pid, dbus_pid, 0);
exit(1);
}
}
Event-Driven Architecture
Implementation Files
libatalk/util/event.c- Event handling wrapper utilitiesetc/netatalk/netatalk_event.c- Master daemon event loop implementationlibatalk/util/signal.c- Signal handling utilities
libevent Integration
The master daemon uses libevent for efficient event handling:
// Event base initialization
struct event_base *base;
struct event *sigterm_ev, *sigquit_ev, *sigchld_ev, *sighup_ev, *timer_ev;
static int setup_event_handling(void) {
// Initialize event base
base = event_base_new();
if (!base) {
LOG(log_error, "Failed to create event base");
return -1;
}
// Setup signal events
sigterm_ev = evsignal_new(base, SIGTERM, handle_sigterm, NULL);
sigquit_ev = evsignal_new(base, SIGQUIT, handle_sigterm, NULL);
sigchld_ev = evsignal_new(base, SIGCHLD, handle_sigchld, NULL);
sighup_ev = evsignal_new(base, SIGHUP, handle_sighup, NULL);
// Add events to event base
event_add(sigterm_ev, NULL);
event_add(sigquit_ev, NULL);
event_add(sigchld_ev, NULL);
event_add(sighup_ev, NULL);
return 0;
}
Child Process Management
// Child process restart logic
static void handle_sigchld(int sig) {
pid_t pid;
int status;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
LOG(log_info, "Child process %d exited with status %d", pid, status);
// Identify which service exited
if (pid == afpd_pid) {
afpd_pid = NETATALK_SRV_NEEDED;
afpd_restarts++;
if (!in_shutdown && afpd_restarts < MAX_RESTARTS) {
LOG(log_info, "Restarting AFP daemon");
restart_afpd();
}
} else if (pid == cnid_metad_pid) {
cnid_metad_pid = NETATALK_SRV_NEEDED;
cnid_metad_restarts++;
if (!in_shutdown && cnid_metad_restarts < MAX_RESTARTS) {
LOG(log_info, "Restarting CNID metadata daemon");
restart_cnid_metad();
}
}
// Handle other services...
}
}
Service Integration Features
Implementation Files
etc/netatalk/spotlight.c- Spotlight service integration and volume managementetc/netatalk/dbus.c- D-Bus service integrationetc/netatalk/avahi.c- Avahi/mDNS service discovery integrationlibatalk/util/zeroconf.c- Zero-configuration networking utilities
1. Spotlight Volume Management
The master daemon coordinates Spotlight indexing across volumes:
// Set up Spotlight indexing for volumes
static int setup_spotlight_volumes(void) {
const struct vol *volumes, *vol;
struct bstrList *vollist = bstrListCreate();
volumes = getvolumes();
for (vol = volumes; vol; vol = vol->v_next) {
if (vol->v_flags & AFPVOL_SPOTLIGHT) {
bstring volpath = bfromcstr(vol->v_path);
bstrListPush(vollist, volpath);
LOG(log_info, "Adding volume '%s' to Spotlight indexing",
vol->v_path);
}
}
// Configure Tracker to index these volumes
return configure_tracker_volumes(vollist);
}
2. D-Bus Service Integration
// D-Bus service management
static pid_t start_dbus_service(void) {
if (dbus_path == NULL) {
LOG(log_debug, "D-Bus service path not configured");
return NETATALK_SRV_OPTIONAL;
}
pid_t pid = run_process(dbus_path, NULL);
if (pid > 0) {
LOG(log_info, "Started D-Bus service with PID %d", pid);
return pid;
} else {
LOG(log_error, "Failed to start D-Bus service");
return NETATALK_SRV_ERROR;
}
}
3. Avahi/mDNS Service Discovery
// Service discovery integration
static int setup_service_discovery(void) {
// Register AFP service
if (register_afp_service() != 0) {
LOG(log_error, "Failed to register AFP service");
return -1;
}
// Register additional services if enabled
if (config.global.adisk_enabled) {
register_adisk_service();
}
if (config.global.devfs_enabled) {
register_devfs_service();
}
return 0;
}
Configuration File Integration
Implementation Files
libatalk/iniparser/- INI configuration file parser libraryetc/netatalk/extmap.c- File extension mapping configurationlibatalk/util/cnid_open.c- CNID configuration handlinglibatalk/util/volinfo.c- Volume configuration utilities
Configuration Parsing
The master daemon parses the main configuration file and distributes settings to appropriate services:
// Main configuration parsing
static int parse_main_config(const char *configfile) {
dictionary *conf = iniparser_load(configfile);
if (!conf) {
LOG(log_error, "Failed to load configuration file: %s", configfile);
return -1;
}
// Parse global settings
parse_global_section(conf, &config.global);
// Parse AFP settings
parse_afp_section(conf, &config.afp);
// Parse CNID settings
parse_cnid_section(conf, &config.cnid);
// Parse volume definitions
parse_volume_sections(conf, &config.volumes);
iniparser_freedict(conf);
return 0;
}
Performance and Reliability Features
Implementation Files
libatalk/util/server_lock.c- Resource locking and managementlibatalk/util/server_child.c- Process pool and child managementetc/netatalk/status.c- Health monitoring and status reportinglibatalk/util/logger.c- Logging system for monitoring
1. Resource Management
// Resource limit enforcement
static int setup_resource_limits(void) {
struct rlimit rl;
// Set file descriptor limits
if (config.global.max_connections > 0) {
rl.rlim_cur = config.global.max_connections + 64; // Extra for system use
rl.rlim_max = rl.rlim_cur;
if (setrlimit(RLIMIT_NOFILE, &rl) != 0) {
LOG(log_warning, "Failed to set file descriptor limit: %s",
strerror(errno));
}
}
return 0;
}
2. Health Monitoring
// Service health checking
static void check_service_health(void) {
static time_t last_check = 0;
time_t now = time(NULL);
if (now - last_check < HEALTH_CHECK_INTERVAL) {
return;
}
// Check AFP daemon responsiveness
if (service_running(afpd_pid)) {
if (!check_afp_responsiveness()) {
LOG(log_warning, "AFP daemon appears unresponsive");
// Could implement automatic restart logic here
}
}
// Check CNID database health
if (service_running(cnid_metad_pid)) {
if (!check_cnid_health()) {
LOG(log_warning, "CNID system appears unhealthy");
}
}
last_check = now;
}
Runtime Statistics and Monitoring
Implementation Files
bin/netatalk-config/netatalk-config.c- Configuration reporting tooletc/netatalk/status.c- Runtime status collectionlibatalk/util/server_ipc.c- Inter-process communication for monitoringcontrib/shell_utils/- Administrative shell utilities
Status Information
// Runtime status structure
struct netatalk_status {
time_t start_time; // Master daemon start time
uint32_t connections_total; // Total connections served
uint32_t connections_active;// Current active connections
uint32_t afpd_restarts; // AFP daemon restart count
uint32_t cnid_restarts; // CNID daemon restart count
size_t memory_usage; // Memory usage estimate
struct service_status {
pid_t pid; // Service PID
time_t start_time; // Service start time
bool responding; // Service responsiveness
} services[SERVICE_COUNT];
};
Integration with System Services
Implementation Files
distrib/systemd/- systemd service files and integrationdistrib/initscripts/- System V init scriptsetc/netatalk/systemd.c- systemd notification integrationcontrib/macusers/- macOS client integration utilities
systemd Integration
// systemd service notification
static void notify_systemd_ready(void) {
#ifdef HAVE_SYSTEMD
if (getenv("NOTIFY_SOCKET")) {
sd_notify(0, "READY=1\n"
"STATUS=Netatalk services started\n"
"MAINPID=%lu", (unsigned long)getpid());
}
#endif
}
The master daemon provides centralized management and coordination for all Netatalk services, ensuring reliable operation, proper startup/shutdown sequencing, and efficient resource utilization while maintaining compatibility with various system service managers.
Footnotes
This is a mirror of the Netatalk GitHub Wiki
Last updated 2025-12-27