Skip to content

Dev Docs Components Netatalk

Andy Lemin edited this page Aug 16, 2025 · 2 revisions

WIP - ALL LINKS IN THIS WIKI STRUCTURE ARE CURRENTLY BROKEN DURING WIKI MIGRATION

THESE ARE COMMUNITY DOCS

Netatalk Master Daemon

Overview

The netatalk daemon serves as the master 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 coordination
  • etc/netatalk/netatalk.h - Master daemon definitions and structures
  • etc/netatalk/afp_config.c - Configuration parsing and management
  • etc/netatalk/afp_options.c - Command-line option processing
  • libatalk/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
    
    A --> B
    B --> C
    C --> F
    C --> G
    C --> H
    D --> E
    B --> I
    I --> J
    I --> K
    H --> L
Loading

Core Functionality

Implementation Files

  • etc/netatalk/service.c - Service lifecycle management and coordination
  • libatalk/util/daemon.c - Daemon utilities and process control
  • include/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
Loading

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
Loading

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 utilities
  • etc/netatalk/netatalk_event.c - Master daemon event loop implementation
  • libatalk/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 management
  • etc/netatalk/dbus.c - D-Bus service integration
  • etc/netatalk/avahi.c - Avahi/mDNS service discovery integration
  • libatalk/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 library
  • etc/netatalk/extmap.c - File extension mapping configuration
  • libatalk/util/cnid_open.c - CNID configuration handling
  • libatalk/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 management
  • libatalk/util/server_child.c - Process pool and child management
  • etc/netatalk/status.c - Health monitoring and status reporting
  • libatalk/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 tool
  • etc/netatalk/status.c - Runtime status collection
  • libatalk/util/server_ipc.c - Inter-process communication for monitoring
  • contrib/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 integration
  • distrib/initscripts/ - System V init scripts
  • etc/netatalk/systemd.c - systemd notification integration
  • contrib/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.

Clone this wiki locally