Skip to content

Commit fd29b9a

Browse files
committed
Replace trivial calls to snprintf with safe_strcpy
1 parent 170ae09 commit fd29b9a

10 files changed

Lines changed: 50 additions & 47 deletions

src/core/config.c

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -307,17 +307,17 @@ void load_default_config(config_t *config) {
307307
}
308308

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

314314
// Syslog settings
315315
config->syslog_enabled = false;
316-
snprintf(config->syslog_ident, sizeof(config->syslog_ident), "lightnvr");
316+
safe_strcpy(config->syslog_ident, "lightnvr", sizeof(config->syslog_ident), 0);
317317
config->syslog_facility = LOG_USER;
318318

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

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

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

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

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

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

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

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

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

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

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

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

12941294
// Add logging to debug

src/database/db_recordings.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ int get_recording_count(time_t start_time, time_t end_time,
626626
char sql[8192];
627627

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

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

970970
// Add LIMIT and OFFSET for pagination
971971
char limit_clause[64];
972-
snprintf(limit_clause, sizeof(limit_clause), " LIMIT ? OFFSET ?");
972+
safe_strcpy(limit_clause, " LIMIT ? OFFSET ?", sizeof(limit_clause), 0);
973973
safe_strcat(sql, limit_clause, sizeof(sql));
974974

975975
log_debug("SQL query for get_recording_metadata_paginated: %s", sql);

src/video/go2rtc/go2rtc_api.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -652,14 +652,14 @@ bool go2rtc_api_get_application_info(int *rtsp_port,
652652
if (version && version_size > 0) {
653653
cJSON *version_obj = cJSON_GetObjectItem(json, "version");
654654
if (version_obj && cJSON_IsString(version_obj)) {
655-
snprintf(version, version_size, "%s", cJSON_GetStringValue(version_obj));
655+
safe_strcpy(version, cJSON_GetStringValue(version_obj), version_size, 0);
656656
}
657657
}
658658

659659
if (revision && revision_size > 0) {
660660
cJSON *revision_obj = cJSON_GetObjectItem(json, "revision");
661661
if (revision_obj && cJSON_IsString(revision_obj)) {
662-
snprintf(revision, revision_size, "%s", cJSON_GetStringValue(revision_obj));
662+
safe_strcpy(revision, cJSON_GetStringValue(revision_obj), revision_size, 0);
663663
}
664664
}
665665

src/video/hls/hls_unified_thread.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2752,7 +2752,7 @@ int stop_hls_unified_stream(const char *stream_name) {
27522752

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

27572757
// Safely get and clear the writer pointer
27582758
const hls_writer_t *writer_to_cleanup = NULL;

src/video/onvif_discovery.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ int discover_onvif_devices(const char *network, onvif_device_info_t *devices,
257257
}
258258

259259
addr.s_addr = htonl(ip);
260-
snprintf(ip_addr, sizeof(ip_addr), "%s", inet_ntoa(addr));
260+
safe_strcpy(ip_addr, inet_ntoa(addr), sizeof(ip_addr), 0);
261261

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

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

315315
dest_addr.sin_addr.s_addr = htonl(broadcast);

src/video/onvif_discovery_thread.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
#include "video/onvif_discovery_thread.h"
2-
#include "video/onvif_discovery_network.h"
3-
#include "video/onvif_discovery_probe.h"
4-
#include "video/onvif_discovery_response.h"
5-
#include "core/logger.h"
61
#include <stdio.h>
72
#include <stdlib.h>
83
#include <string.h>
@@ -13,6 +8,13 @@
138
#include <errno.h>
149
#include <time.h>
1510

11+
#include "video/onvif_discovery_thread.h"
12+
#include "video/onvif_discovery_network.h"
13+
#include "video/onvif_discovery_probe.h"
14+
#include "video/onvif_discovery_response.h"
15+
#include "core/logger.h"
16+
#include "utils/strings.h"
17+
1618
// Maximum number of discovered devices
1719
#define MAX_DISCOVERED_DEVICES 32
1820

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

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

6567
// Send multiple probes to broadcast address
6668
addr.s_addr = htonl(broadcast);
67-
snprintf(ip_addr, sizeof(ip_addr), "%s", inet_ntoa(addr));
69+
safe_strcpy(ip_addr, inet_ntoa(addr), sizeof(ip_addr), 0);
6870
log_info("Sending multiple discovery probes to broadcast address: %s", ip_addr);
6971

7072
for (int i = 0; i < 5; i++) {

src/web/api_handlers_recordings_batch_download.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ static void *zip_worker(void *arg) {
269269
/* Build entry name: stream_YYYY-MM-DDTHH-mm-ss.ext */
270270
const char *base = strrchr(rec.file_path, '/');
271271
base = base ? base+1 : rec.file_path;
272-
snprintf(entries[entry_count].name, sizeof(entries[entry_count].name), "%s", base);
272+
safe_strcpy(entries[entry_count].name, base, sizeof(entries[entry_count].name), 0);
273273

274274
uint64_t fsize = 0;
275275
uint32_t crc = crc32_of_file(rec.file_path, &fsize);

src/web/api_handlers_streams_test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ static int test_stream_connection(const char *url, int protocol,
8484
}
8585

8686
if (video_stream_index == -1) {
87-
snprintf(error_msg, error_msg_size, "No video stream found");
87+
safe_strcpy(error_msg, "No video stream found", error_msg_size, 0);
8888
log_error("%s", error_msg);
8989
ret = -1;
9090
goto cleanup;

src/web/api_handlers_system.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,15 +180,15 @@ static void add_versions_to_json(cJSON *info) {
180180
char os_version[256] = {0};
181181

182182
if (read_os_release_value("PRETTY_NAME", pretty_name, sizeof(pretty_name))) {
183-
snprintf(os_version, sizeof(os_version), "%s", pretty_name);
183+
safe_strcpy(os_version, pretty_name, sizeof(os_version), 0);
184184
} else if (read_os_release_value("NAME", name, sizeof(name))) {
185185
if (read_os_release_value("VERSION_ID", version_id, sizeof(version_id))) {
186186
snprintf(os_version, sizeof(os_version), "%s %s", name, version_id);
187187
} else {
188-
snprintf(os_version, sizeof(os_version), "%s", name);
188+
safe_strcpy(os_version, name, sizeof(os_version), 0);
189189
}
190190
} else {
191-
snprintf(os_version, sizeof(os_version), "%s", system_info.sysname);
191+
safe_strcpy(os_version, system_info.sysname, sizeof(os_version), 0);
192192
}
193193

194194
snprintf(details, sizeof(details), "%s %s • %s",
@@ -224,7 +224,7 @@ static void add_versions_to_json(cJSON *info) {
224224
snprintf(curl_details, sizeof(curl_details), "%s • zlib %s",
225225
curl_info->ssl_version, curl_info->libz_version);
226226
} else if (curl_info->ssl_version) {
227-
snprintf(curl_details, sizeof(curl_details), "%s", curl_info->ssl_version);
227+
safe_strcpy(curl_details, curl_info->ssl_version, sizeof(curl_details), 0);
228228
} else if (curl_info->libz_version) {
229229
snprintf(curl_details, sizeof(curl_details), "zlib %s", curl_info->libz_version);
230230
}
@@ -1254,7 +1254,7 @@ void handle_get_system_info(const http_request_t *req, http_response_t *res) {
12541254
// Compute recordings directory size using native filesystem traversal.
12551255
// storage_path is NEVER passed to a shell command (prevents injection).
12561256
char recordings_dir[512];
1257-
snprintf(recordings_dir, sizeof(recordings_dir), "%s", g_config.storage_path);
1257+
safe_strcpy(recordings_dir, g_config.storage_path, sizeof(recordings_dir), 0);
12581258
/* strip any trailing slash so lstat/opendir work consistently */
12591259
size_t rd_len = strlen(recordings_dir);
12601260
if (rd_len > 1 && recordings_dir[rd_len - 1] == '/')

src/web/thumbnail_thread.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#define LOG_COMPONENT "Thumbnail"
2323
#include "core/logger.h"
2424
#include "utils/memory.h"
25+
#include "utils/strings.h"
2526

2627
// Maximum concurrent thumbnail generations
2728
#define MAX_CONCURRENT_THUMBNAILS 4
@@ -305,8 +306,8 @@ int thumbnail_thread_submit(uint64_t recording_id, int index,
305306

306307
work->recording_id = recording_id;
307308
work->index = index;
308-
snprintf(work->input_path, sizeof(work->input_path), "%s", input_path);
309-
snprintf(work->output_path, sizeof(work->output_path), "%s", output_path);
309+
safe_strcpy(work->input_path, input_path, sizeof(work->input_path), 0);
310+
safe_strcpy(work->output_path, output_path, sizeof(work->output_path), 0);
310311
work->seek_seconds = seek_seconds;
311312
work->deferred_action = deferred_action;
312313
work->callback = callback;

0 commit comments

Comments
 (0)