Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 24 additions & 24 deletions src/core/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,17 +307,17 @@ void load_default_config(config_t *config) {
}

// General settings
snprintf(config->pid_file, MAX_PATH_LENGTH, "/var/run/lightnvr.pid");
snprintf(config->log_file, MAX_PATH_LENGTH, "/var/log/lightnvr.log");
safe_strcpy(config->pid_file, "/var/run/lightnvr.pid", MAX_PATH_LENGTH, 0);
safe_strcpy(config->log_file, "/var/log/lightnvr.log", MAX_PATH_LENGTH, 0);
config->log_level = LOG_LEVEL_INFO;

// Syslog settings
config->syslog_enabled = false;
snprintf(config->syslog_ident, sizeof(config->syslog_ident), "lightnvr");
safe_strcpy(config->syslog_ident, "lightnvr", sizeof(config->syslog_ident), 0);
config->syslog_facility = LOG_USER;

// Storage settings
snprintf(config->storage_path, MAX_PATH_LENGTH, "/var/lib/lightnvr/recordings");
safe_strcpy(config->storage_path, "/var/lib/lightnvr/recordings", MAX_PATH_LENGTH, 0);
config->storage_path_hls[0] = '\0'; // Empty by default, will use storage_path if not specified
config->max_storage_size = 0; // 0 means unlimited
config->retention_days = 30;
Expand All @@ -328,35 +328,35 @@ void load_default_config(config_t *config) {

// MP4 recording settings
config->record_mp4_directly = false;
snprintf(config->mp4_storage_path, sizeof(config->mp4_storage_path), "/var/lib/lightnvr/recordings/mp4");
safe_strcpy(config->mp4_storage_path, "/var/lib/lightnvr/recordings/mp4", sizeof(config->mp4_storage_path), 0);
config->mp4_segment_duration = 900; // 15 minutes
config->mp4_retention_days = 30;

// Models settings
snprintf(config->models_path, MAX_PATH_LENGTH, "/var/lib/lightnvr/models");
safe_strcpy(config->models_path, "/var/lib/lightnvr/models", MAX_PATH_LENGTH, 0);

// API detection settings
snprintf(config->api_detection_url, MAX_URL_LENGTH, "http://localhost:8000/detect");
snprintf(config->api_detection_backend, 32, "onnx"); // Default to ONNX backend
safe_strcpy(config->api_detection_url, "http://localhost:8000/detect", MAX_URL_LENGTH, 0);
safe_strcpy(config->api_detection_backend, "onnx", 32, 0); // Default to ONNX backend

// Global detection defaults
config->default_detection_threshold = 50; // 50% confidence threshold
config->default_pre_detection_buffer = 5; // 5 seconds before detection
config->default_post_detection_buffer = 10; // 10 seconds after detection
snprintf(config->default_buffer_strategy, 32, "auto"); // Auto-select buffer strategy
safe_strcpy(config->default_buffer_strategy, "auto", 32, 0); // Auto-select buffer strategy

// Database settings
snprintf(config->db_path, MAX_PATH_LENGTH, "/var/lib/lightnvr/lightnvr.db");
safe_strcpy(config->db_path, "/var/lib/lightnvr/lightnvr.db", MAX_PATH_LENGTH, 0);
config->db_backup_interval_minutes = 60;
config->db_backup_retention_count = 24;
config->db_post_backup_script[0] = '\0';

// Web server settings
config->web_port = 8080;
snprintf(config->web_bind_ip, 32, "0.0.0.0");
snprintf(config->web_root, MAX_PATH_LENGTH, "/var/lib/lightnvr/www");
safe_strcpy(config->web_bind_ip, "0.0.0.0", 32, 0);
safe_strcpy(config->web_root, "/var/lib/lightnvr/www", MAX_PATH_LENGTH, 0);
config->web_auth_enabled = true;
snprintf(config->web_username, 32, "admin");
safe_strcpy(config->web_username, "admin", 32, 0);
// No default password - will be generated randomly on first run
config->web_password[0] = '\0';
config->webrtc_disabled = false; // WebRTC is enabled by default
Expand Down Expand Up @@ -385,7 +385,7 @@ void load_default_config(config_t *config) {
// Memory optimization
config->buffer_size = 1024; // 1024 KB (1 MB) buffer size
config->use_swap = true;
snprintf(config->swap_file, MAX_PATH_LENGTH, "/var/lib/lightnvr/swap");
safe_strcpy(config->swap_file, "/var/lib/lightnvr/swap", MAX_PATH_LENGTH, 0);
config->swap_size = (uint64_t)128 * 1024 * 1024; // 128MB swap

// Hardware acceleration
Expand All @@ -399,14 +399,14 @@ void load_default_config(config_t *config) {
// CMake passes these as string literals already (e.g. -DGO2RTC_BINARY_PATH_RAW="/usr/local/bin/go2rtc"),
// so they must be used directly — NOT through STRINGIFY, which would double-quote the value.
#ifdef GO2RTC_BINARY_PATH_RAW
snprintf(config->go2rtc_binary_path, MAX_PATH_LENGTH, "%s", GO2RTC_BINARY_PATH_RAW);
safe_strcpy(config->go2rtc_binary_path, GO2RTC_BINARY_PATH_RAW, MAX_PATH_LENGTH, 0);
#else
snprintf(config->go2rtc_binary_path, MAX_PATH_LENGTH, "/usr/local/bin/go2rtc");
safe_strcpy(config->go2rtc_binary_path, "/usr/local/bin/go2rtc", MAX_PATH_LENGTH, 0);
#endif
#ifdef GO2RTC_CONFIG_DIR_RAW
snprintf(config->go2rtc_config_dir, MAX_PATH_LENGTH, "%s", GO2RTC_CONFIG_DIR_RAW);
safe_strcpy(config->go2rtc_config_dir, GO2RTC_CONFIG_DIR_RAW, MAX_PATH_LENGTH, 0);
#else
snprintf(config->go2rtc_config_dir, MAX_PATH_LENGTH, "/etc/lightnvr/go2rtc");
safe_strcpy(config->go2rtc_config_dir, "/etc/lightnvr/go2rtc", MAX_PATH_LENGTH, 0);
#endif
config->go2rtc_api_port = 1984;
config->go2rtc_rtsp_port = 8554; // Default RTSP listen port
Expand All @@ -417,7 +417,7 @@ void load_default_config(config_t *config) {
config->go2rtc_webrtc_enabled = true; // Enable WebRTC by default
config->go2rtc_webrtc_listen_port = 8555; // Default WebRTC listen port
config->go2rtc_stun_enabled = true; // Enable STUN by default for NAT traversal
snprintf(config->go2rtc_stun_server, sizeof(config->go2rtc_stun_server), "stun.l.google.com:19302");
safe_strcpy(config->go2rtc_stun_server, "stun.l.google.com:19302", sizeof(config->go2rtc_stun_server), 0);
config->go2rtc_external_ip[0] = '\0'; // Empty by default (auto-detect)
config->go2rtc_ice_servers[0] = '\0'; // Empty by default (use STUN server)

Expand All @@ -430,7 +430,7 @@ void load_default_config(config_t *config) {
// ONVIF discovery settings
config->onvif_discovery_enabled = false; // Disabled by default
config->onvif_discovery_interval = 300; // 5 minutes between scans
snprintf(config->onvif_discovery_network, sizeof(config->onvif_discovery_network), "auto");
safe_strcpy(config->onvif_discovery_network, "auto", sizeof(config->onvif_discovery_network), 0);

// Initialize default values for detection-based recording in streams
for (int i = 0; i < config->max_streams; i++) {
Expand Down Expand Up @@ -458,16 +458,16 @@ void load_default_config(config_t *config) {
config->mqtt_broker_port = 1883; // Default MQTT port
config->mqtt_username[0] = '\0'; // Optional
config->mqtt_password[0] = '\0'; // Optional
snprintf(config->mqtt_client_id, sizeof(config->mqtt_client_id), "lightnvr");
snprintf(config->mqtt_topic_prefix, sizeof(config->mqtt_topic_prefix), "lightnvr");
safe_strcpy(config->mqtt_client_id, "lightnvr", sizeof(config->mqtt_client_id), 0);
safe_strcpy(config->mqtt_topic_prefix, "lightnvr", sizeof(config->mqtt_topic_prefix), 0);
config->mqtt_tls_enabled = false; // No TLS by default
config->mqtt_keepalive = 60; // 60 seconds keepalive
config->mqtt_qos = 1; // QoS 1 (at least once)
config->mqtt_retain = false; // Don't retain messages by default

// Home Assistant MQTT auto-discovery settings
config->mqtt_ha_discovery = false; // Disabled by default
snprintf(config->mqtt_ha_discovery_prefix, sizeof(config->mqtt_ha_discovery_prefix), "homeassistant");
safe_strcpy(config->mqtt_ha_discovery_prefix, "homeassistant", sizeof(config->mqtt_ha_discovery_prefix), 0);
config->mqtt_ha_snapshot_interval = 30; // 30 seconds default
}

Expand Down Expand Up @@ -1288,7 +1288,7 @@ int load_config(config_t *config) {
// Set default web root if not specified
if (strlen(config->web_root) == 0) {
// Set a default web root path
snprintf(config->web_root, sizeof(config->web_root), "%s", "/var/www/lightnvr"); // or another appropriate default
safe_strcpy(config->web_root, "/var/www/lightnvr", sizeof(config->web_root), 0); // or another appropriate default
}

// Add logging to debug
Expand Down
4 changes: 2 additions & 2 deletions src/database/db_recordings.c
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ int get_recording_count(time_t start_time, time_t end_time,
char sql[8192];

// Use trigger_type and/or detections table to filter detection-based recordings
snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM recordings r WHERE r.is_complete = 1 AND r.end_time IS NOT NULL");
safe_strcpy(sql, "SELECT COUNT(*) FROM recordings r WHERE r.is_complete = 1 AND r.end_time IS NOT NULL", sizeof(sql), 0);

if (has_detection == 1) {
// Filter by trigger_type = 'detection' OR existence of linked detections via recording_id (fast index lookup)
Expand Down Expand Up @@ -969,7 +969,7 @@ int get_recording_metadata_paginated(time_t start_time, time_t end_time,

// Add LIMIT and OFFSET for pagination
char limit_clause[64];
snprintf(limit_clause, sizeof(limit_clause), " LIMIT ? OFFSET ?");
safe_strcpy(limit_clause, " LIMIT ? OFFSET ?", sizeof(limit_clause), 0);
safe_strcat(sql, limit_clause, sizeof(sql));

log_debug("SQL query for get_recording_metadata_paginated: %s", sql);
Expand Down
4 changes: 2 additions & 2 deletions src/video/go2rtc/go2rtc_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -652,14 +652,14 @@ bool go2rtc_api_get_application_info(int *rtsp_port,
if (version && version_size > 0) {
cJSON *version_obj = cJSON_GetObjectItem(json, "version");
if (version_obj && cJSON_IsString(version_obj)) {
snprintf(version, version_size, "%s", cJSON_GetStringValue(version_obj));
safe_strcpy(version, cJSON_GetStringValue(version_obj), version_size, 0);
}
}

if (revision && revision_size > 0) {
cJSON *revision_obj = cJSON_GetObjectItem(json, "revision");
if (revision_obj && cJSON_IsString(revision_obj)) {
snprintf(revision, revision_size, "%s", cJSON_GetStringValue(revision_obj));
safe_strcpy(revision, cJSON_GetStringValue(revision_obj), revision_size, 0);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/video/hls/hls_unified_thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -2752,7 +2752,7 @@ int stop_hls_unified_stream(const char *stream_name) {

// Store a local copy of the stream name for logging
char writer_stream_name[MAX_STREAM_NAME];
snprintf(writer_stream_name, sizeof(writer_stream_name), "%s", stream_name); // Use the stream_name we already have
safe_strcpy(writer_stream_name, stream_name, sizeof(writer_stream_name), 0); // Use the stream_name we already have

// Safely get and clear the writer pointer
const hls_writer_t *writer_to_cleanup = NULL;
Expand Down
4 changes: 2 additions & 2 deletions src/video/onvif_discovery.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ int discover_onvif_devices(const char *network, onvif_device_info_t *devices,
}

addr.s_addr = htonl(ip);
snprintf(ip_addr, sizeof(ip_addr), "%s", inet_ntoa(addr));
safe_strcpy(ip_addr, inet_ntoa(addr), sizeof(ip_addr), 0);

// Check if port 3702 (ONVIF) or port 80 (HTTP) is open with a shorter timeout
if (is_port_open(ip_addr, 3702, 25) || is_port_open(ip_addr, 80, 25)) {
Expand Down Expand Up @@ -309,7 +309,7 @@ int discover_onvif_devices(const char *network, onvif_device_info_t *devices,

// Send probes to broadcast address
addr.s_addr = htonl(broadcast);
snprintf(ip_addr, sizeof(ip_addr), "%s", inet_ntoa(addr));
safe_strcpy(ip_addr, inet_ntoa(addr), sizeof(ip_addr), 0);
log_info("Sending discovery probes to broadcast address: %s", ip_addr);

dest_addr.sin_addr.s_addr = htonl(broadcast);
Expand Down
16 changes: 9 additions & 7 deletions src/video/onvif_discovery_thread.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
#include "video/onvif_discovery_thread.h"
#include "video/onvif_discovery_network.h"
#include "video/onvif_discovery_probe.h"
#include "video/onvif_discovery_response.h"
#include "core/logger.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand All @@ -13,6 +8,13 @@
#include <errno.h>
#include <time.h>

#include "video/onvif_discovery_thread.h"
#include "video/onvif_discovery_network.h"
#include "video/onvif_discovery_probe.h"
#include "video/onvif_discovery_response.h"
#include "core/logger.h"
#include "utils/strings.h"

// Maximum number of discovered devices
#define MAX_DISCOVERED_DEVICES 32

Expand Down Expand Up @@ -53,7 +55,7 @@ void *discovery_thread_func(void *arg) {
// Send discovery probes to all addresses in the range
for (uint32_t ip = network + 1; ip < broadcast && thread_data->running; ip++) {
addr.s_addr = htonl(ip);
snprintf(ip_addr, sizeof(ip_addr), "%s", inet_ntoa(addr));
safe_strcpy(ip_addr, inet_ntoa(addr), sizeof(ip_addr), 0);

// Send discovery probe
send_discovery_probe(ip_addr);
Expand All @@ -64,7 +66,7 @@ void *discovery_thread_func(void *arg) {

// Send multiple probes to broadcast address
addr.s_addr = htonl(broadcast);
snprintf(ip_addr, sizeof(ip_addr), "%s", inet_ntoa(addr));
safe_strcpy(ip_addr, inet_ntoa(addr), sizeof(ip_addr), 0);
log_info("Sending multiple discovery probes to broadcast address: %s", ip_addr);

for (int i = 0; i < 5; i++) {
Expand Down
2 changes: 1 addition & 1 deletion src/web/api_handlers_recordings_batch_download.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ static void *zip_worker(void *arg) {
/* Build entry name: stream_YYYY-MM-DDTHH-mm-ss.ext */
const char *base = strrchr(rec.file_path, '/');
base = base ? base+1 : rec.file_path;
snprintf(entries[entry_count].name, sizeof(entries[entry_count].name), "%s", base);
safe_strcpy(entries[entry_count].name, base, sizeof(entries[entry_count].name), 0);

uint64_t fsize = 0;
uint32_t crc = crc32_of_file(rec.file_path, &fsize);
Expand Down
2 changes: 1 addition & 1 deletion src/web/api_handlers_streams_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ static int test_stream_connection(const char *url, int protocol,
}

if (video_stream_index == -1) {
snprintf(error_msg, error_msg_size, "No video stream found");
safe_strcpy(error_msg, "No video stream found", error_msg_size, 0);
log_error("%s", error_msg);
ret = -1;
goto cleanup;
Expand Down
10 changes: 5 additions & 5 deletions src/web/api_handlers_system.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,15 +180,15 @@ static void add_versions_to_json(cJSON *info) {
char os_version[256] = {0};

if (read_os_release_value("PRETTY_NAME", pretty_name, sizeof(pretty_name))) {
snprintf(os_version, sizeof(os_version), "%s", pretty_name);
safe_strcpy(os_version, pretty_name, sizeof(os_version), 0);
} else if (read_os_release_value("NAME", name, sizeof(name))) {
if (read_os_release_value("VERSION_ID", version_id, sizeof(version_id))) {
snprintf(os_version, sizeof(os_version), "%s %s", name, version_id);
} else {
snprintf(os_version, sizeof(os_version), "%s", name);
safe_strcpy(os_version, name, sizeof(os_version), 0);
}
} else {
snprintf(os_version, sizeof(os_version), "%s", system_info.sysname);
safe_strcpy(os_version, system_info.sysname, sizeof(os_version), 0);
}

snprintf(details, sizeof(details), "%s %s • %s",
Expand Down Expand Up @@ -224,7 +224,7 @@ static void add_versions_to_json(cJSON *info) {
snprintf(curl_details, sizeof(curl_details), "%s • zlib %s",
curl_info->ssl_version, curl_info->libz_version);
} else if (curl_info->ssl_version) {
snprintf(curl_details, sizeof(curl_details), "%s", curl_info->ssl_version);
safe_strcpy(curl_details, curl_info->ssl_version, sizeof(curl_details), 0);
} else if (curl_info->libz_version) {
snprintf(curl_details, sizeof(curl_details), "zlib %s", curl_info->libz_version);
}
Expand Down Expand Up @@ -1254,7 +1254,7 @@ void handle_get_system_info(const http_request_t *req, http_response_t *res) {
// Compute recordings directory size using native filesystem traversal.
// storage_path is NEVER passed to a shell command (prevents injection).
char recordings_dir[512];
snprintf(recordings_dir, sizeof(recordings_dir), "%s", g_config.storage_path);
safe_strcpy(recordings_dir, g_config.storage_path, sizeof(recordings_dir), 0);
/* strip any trailing slash so lstat/opendir work consistently */
size_t rd_len = strlen(recordings_dir);
if (rd_len > 1 && recordings_dir[rd_len - 1] == '/')
Expand Down
5 changes: 3 additions & 2 deletions src/web/thumbnail_thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#define LOG_COMPONENT "Thumbnail"
#include "core/logger.h"
#include "utils/memory.h"
#include "utils/strings.h"

// Maximum concurrent thumbnail generations
#define MAX_CONCURRENT_THUMBNAILS 4
Expand Down Expand Up @@ -305,8 +306,8 @@ int thumbnail_thread_submit(uint64_t recording_id, int index,

work->recording_id = recording_id;
work->index = index;
snprintf(work->input_path, sizeof(work->input_path), "%s", input_path);
snprintf(work->output_path, sizeof(work->output_path), "%s", output_path);
safe_strcpy(work->input_path, input_path, sizeof(work->input_path), 0);
safe_strcpy(work->output_path, output_path, sizeof(work->output_path), 0);
work->seek_seconds = seek_seconds;
work->deferred_action = deferred_action;
work->callback = callback;
Expand Down
Loading