1. Overview
The ClamdConfig component is a configuration model and persistence utility for managing ClamAV daemon settings (typically stored in clamd.conf). It provides a structured interface to:
- Load and parse configuration files while preserving original formatting
- Read and update key/value options (including boolean yes/no values)
- Manage on-access scan include paths (
OnAccessIncludePath) - Persist updates back to disk while retaining unmodified lines and comments
- Create backups before applying changes
This module is designed for UI-driven configuration workflows (e.g., Settings pages) where maintaining the user’s original file structure and comments is important.
2. Data Model
Internally, the configuration is represented using two complementary structures:
- rawLines – an ordered list of parsed lines (including comments and unknown entries) that preserves file structure
- options – a key/value map containing the effective non-commented configuration values
Each entry in rawLines is represented by a Line structure containing:
text– original line string as read from filekey– parsed directive key (if detected)value– parsed value (single token value)commented– whether the line was originally commented out with#
This dual representation enables accurate round-trip save behavior while still supporting fast lookups and updates.
3. Configuration Loading
3.1 Parsing Strategy
The configuration is loaded via:
bool load(const std::string& path)
Load behavior:
- Clears both
rawLinesandoptionsto ensure a fresh model - Reads the file line-by-line
- Detects comment prefix (
#) and recordscommented=true - Parses the remaining content using a token-based approach:
keyandvalueare extracted usingistringstream(iss >> key >> value)- Only the first two tokens are captured (multi-token values are not expanded)
- For non-commented parsed directives, updates
options[key] = value - Always appends a
Linerecord torawLinesto preserve full file content
If the file cannot be opened, load() returns false.
4. Persistence and Round-trip Save
4.1 Standard Save
Saving is performed via:
bool save(const std::string& path)
Save strategy:
- Iterates through
rawLinesin original order - If a line has a parsed
keyand that key exists inoptions, the output line is rewritten using the current value - If the original line was commented, the
#prefix is preserved - Lines not associated with tracked keys are written exactly as originally read (
ln.text)
This approach preserves:
- Unknown directives
- Non-directive lines
- Whitespace patterns embedded in unmodified lines
- Commented-out directive lines (while still allowing their values to be updated if tracked)
If the output file cannot be opened, save() returns false.
4.2 Backup and Safe Save
ClamdConfig provides a backup mechanism:
bool backupFile(const std::string& path) const
Backup behavior:
- If
pathexists, a copy is created at<path>.bak - Existing backups are overwritten
- Exceptions are caught and reported to
stderr(localized message)
A combined safe-save entry point is provided:
bool saveWithBackup(const std::string& path)
This performs:
- Backup creation (
backupFile()) - Save execution (
save())
If the backup step fails, persistence is aborted and an error is logged.
5. Option Accessors
5.1 Generic Options
The module exposes generic set/get operations:
void setOption(const std::string& key, const std::string& value)std::string getOption(const std::string& key) const
Options are stored in the options map and represent the effective (non-commented) configuration values. Missing keys return an empty string.
5.2 Boolean Options
Boolean helpers provide yes/no semantics:
bool getOptionBool(const std::string& key) constvoid setOptionBool(const std::string& key, bool enabled)
Normalization is handled by isYes(), which lowercases the value and treats the following as true:
yestrue1
All other values are treated as false.
6. On-access Include Path Management
6.1 Enumerating Paths
On-access monitored folders are represented by repeated directives:
OnAccessIncludePath <path>
The method:
std::vector<std::string> getOnAccessPaths() const
collects all non-commented occurrences of OnAccessIncludePath from rawLines.
6.2 Adding a Path
Adding a path is performed via:
void addOnAccessPath(const std::string& path)
Behavior:
- Creates a new
Linerecord with keyOnAccessIncludePathand value set to the provided path - Appends it to
rawLines(preserving existing entries) - Also sets
options["OnAccessIncludePath"] = path
Note: because OnAccessIncludePath is a multi-occurrence directive, storing it in options as a single value implies that the map will hold only the last added instance. The authoritative multi-value representation is the rawLines list.
6.3 Removing a Path
Removal is performed via:
void removeOnAccessPath(const std::string& path)
This erases any line from rawLines where:
ln.key == "OnAccessIncludePath"andln.value == path
This operation updates the serialized output but does not remove any corresponding entry from options, because options is not a complete representation of multi-occurrence directives.
7. Advanced Scan Options Extraction
7.1 Enumerating yes/no Scan Options
The method:
std::map<std::string, bool> getScanOptions() const
extracts configuration directives that use explicit yes or no values. For each line:
- If the line has a non-empty key and its value is exactly
yesorno, it is included - The resulting boolean is true only if the line is not commented and the value is affirmative
This provides a convenient UI-ready model for rendering advanced boolean toggles without hardcoding option names.
7.2 Updating a Scan Option
Scan option updates are performed via:
void setScanOption(const std::string& key, bool enabled)
Behavior:
- Updates
options[key]toyesorno - Iterates over
rawLinesand rewrites matching key lines:ln.valueset toyes/noln.textrewritten, preserving comment prefix ifln.commentedis true
This ensures round-trip consistency between the in-memory options map and the serialized file representation.
8. Security and Operational Considerations
- Round-trip preservation: the design favors preserving original file structure, comments, and unknown directives.
- Tokenization limitation: only two tokens (
keyand a single-tokenvalue) are parsed; multi-token values may require extension if needed by specific directives. - Multi-occurrence directives: directives like
OnAccessIncludePathare represented fully inrawLines; theoptionsmap stores only the last seen/assigned value for such keys. - Backup strategy: backups are created with a simple
.baksuffix; upstream installers may extend this to timestamped backups if required. - Privilege separation: ClamdConfig itself performs file I/O; privileged installation (e.g., writing to system clamd.conf paths) should be handled by higher-level modules (e.g., Settings page using
pkexec).
In summary, ClamdConfig acts as a practical configuration round-tripping layer for ClamAV, enabling UI-driven edits of clamd.conf while preserving formatting and minimizing the risk of destructive rewrites.