-
Notifications
You must be signed in to change notification settings - Fork 100
Dev Docs Components Netatalk
WIP - ALL LINKS IN THIS WIKI STRUCTURE ARE CURRENTLY BROKEN DURING WIKI MIGRATION
THESE ARE COMMUNITY DOCS
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.
-
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
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
-
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
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
};
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
// 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");
}
}
// 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;
}
}
}
}
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 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);
}
}
-
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
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 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...
}
}
-
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
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);
}
// 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;
}
}
// 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;
}
-
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
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;
}
-
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
// 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;
}
// 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;
}
-
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
// 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];
};
-
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 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.
Resources
- Getting Started
- FAQ
- Troubleshooting
- Connect to AFP Server
- Webmin Module
- Benchmarks
- Interoperability with Samba
OS Specific Guides
- Installing Netatalk on Alpine Linux
- Installing Netatalk on Debian Linux
- Installing Netatalk on Fedora Linux
- Installing Netatalk on FreeBSD
- Installing Netatalk on macOS
- Installing Netatalk on NetBSD
- Installing Netatalk on OmniOS
- Installing Netatalk on OpenBSD
- Installing Netatalk on OpenIndiana
- Installing Netatalk on openSUSE
- Installing Netatalk on Solaris
- Installing Netatalk on Ubuntu
Tech Notes
- Kerberos
- Special Files and Folders
- Spotlight
- MySQL CNID Backend
- Slow AFP read performance
- Limiting Time Machine volumes
- Netatalk and ZFS nbmand property
Retro AFP
Development