Skip to content
Merged
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
57 changes: 57 additions & 0 deletions include/core/path_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define LIGHTNVR_PATH_UTILS_H

#include <stddef.h>
#include <sys/types.h>

/**
* Sanitize a stream name for use as a path or object name.
Expand All @@ -13,4 +14,60 @@
*/
void sanitize_stream_name(const char *input, char *output, size_t output_size);

/**
* Ensure the specified directory exists, creating it if necessary. Does not recur.
* Sets errno on failure.
*
* @param path Directory path to create
* @return 0 on success, negative errno on error
*/
int ensure_dir(const char *path);

/**
* Create a directory recursively (like mkdir -p)
* This replaces system("mkdir -p ...") calls
*
* @param path Directory path to create
* @return 0 on success, -1 on error
*/
int mkdir_recursive(const char *path);

/**
* Ensure a directory exists for a file path by recursively creating
* parent directories.
*
* @param path File path to create parent directories for
* @return 0 on success, -1 on error
*/
int ensure_path(const char *path);

/**
* Set permissions on a file or directory (like chmod)
*
* @param path Path to set permissions on
* @param mode Permission mode (e.g., 0755)
* @return 0 on success, -1 on error
*/
int chmod_path(const char *path, mode_t mode);

/**
* Set permissions on a parent directory
*
* @param path Path to the file inside the parent directory
* @param mode Permission mode (e.g., 0755)
* @return 0 on success, -1 on error
*/
int chmod_parent(const char *path, mode_t mode);

/**
* Recursively set permissions on a directory and its contents (like chmod -R)
*
* @param path Directory path to chmod recursively
* @param mode Permission mode (e.g., 0755)
* @return 0 on success, -1 on error
*/
int chmod_recursive(const char *path, mode_t mode);

// TODO: create recursive chmod for folders only and use that instead of chmod_recursive

#endif /* LIGHTNVR_PATH_UTILS_H */
27 changes: 0 additions & 27 deletions include/video/ffmpeg_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,31 +157,4 @@ void jpeg_encoder_cleanup_all(void);
int ffmpeg_concat_ts_to_mp4(const char **segment_paths, int segment_count,
const char *output_path);

/**
* Create a directory recursively (like mkdir -p)
* This replaces system("mkdir -p ...") calls
*
* @param path Directory path to create
* @return 0 on success, -1 on error
*/
int mkdir_recursive(const char *path);

/**
* Set permissions on a file or directory (like chmod)
*
* @param path Path to set permissions on
* @param mode Permission mode (e.g., 0777)
* @return 0 on success, -1 on error
*/
int chmod_path(const char *path, mode_t mode);

/**
* Recursively set permissions on a directory and its contents (like chmod -R)
*
* @param path Directory path to chmod recursively
* @param mode Permission mode (e.g., 0777)
* @return 0 on success, -1 on error
*/
int chmod_recursive(const char *path, mode_t mode);

#endif /* FFMPEG_UTILS_H */
68 changes: 11 additions & 57 deletions src/core/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "ini.h"
#include "core/config.h"
#include "core/logger.h"
#include "core/path_utils.h"
#include "database/database_manager.h"
#include "utils/strings.h"

Expand Down Expand Up @@ -471,93 +472,46 @@ void load_default_config(config_t *config) {
config->mqtt_ha_snapshot_interval = 30; // 30 seconds default
}

// Create directory if it doesn't exist
static int create_directory(const char *path) {
struct stat st;

// Check if directory already exists
if (stat(path, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
return 0; // Directory exists
} else {
return -1; // Path exists but is not a directory
}
}

// Create directory with permissions 0755
if (mkdir(path, 0755) != 0) {
if (errno == ENOENT) {
// Parent directory doesn't exist, try to create it recursively
char *parent_path = strdup(path);
if (!parent_path) {
return -1;
}

const char *parent_dir = dirname(parent_path);
int ret = create_directory(parent_dir);
free(parent_path);

if (ret != 0) {
return -1;
}

// Try again to create the directory
if (mkdir(path, 0755) != 0) {
return -1;
}
} else {
return -1;
}
}

return 0;
}

// Ensure all required directories exist
static int ensure_directories(const config_t *config) {
// Storage directory
if (create_directory(config->storage_path) != 0) {
if (mkdir_recursive(config->storage_path) != 0) {
log_error("Failed to create storage directory: %s", config->storage_path);
return -1;
}

// HLS storage directory if specified
if (config->storage_path_hls[0] != '\0') {
if (create_directory(config->storage_path_hls) != 0) {
if (mkdir_recursive(config->storage_path_hls) != 0) {
log_error("Failed to create HLS storage directory: %s", config->storage_path_hls);
return -1;
}
log_info("Created HLS storage directory: %s", config->storage_path_hls);
}

// Models directory
if (create_directory(config->models_path) != 0) {
if (mkdir_recursive(config->models_path) != 0) {
log_error("Failed to create models directory: %s", config->models_path);
return -1;
}

// Database directory
// Some dirname implementations actually modify the path argument and
// will segfault when passed a read-only const string.
char tmp_path[MAX_PATH_LENGTH];
safe_strcpy(tmp_path, config->db_path, MAX_PATH_LENGTH, 0);
char *dir = dirname(tmp_path);
if (create_directory(dir) != 0) {
log_error("Failed to create database directory: %s", dir);
if (ensure_path(config->db_path)) {
log_error("Failed to create database directory: %s", config->db_path);
return -1;
}

// Web root directory
if (create_directory(config->web_root) != 0) {
if (mkdir_recursive(config->web_root) != 0) {
log_error("Failed to create web root directory: %s", config->web_root);
return -1;
}

// Log directory
safe_strcpy(tmp_path, config->log_file, MAX_PATH_LENGTH, 0);
dir = dirname(tmp_path);
if (create_directory(dir) != 0) {
log_error("Failed to create log directory: %s", dir);
if (ensure_path(config->log_file)) {
log_error("Failed to create log directory: %s", config->log_file);
return -1;
}

Expand All @@ -566,7 +520,7 @@ static int ensure_directories(const config_t *config) {
if (cfg_log_fd < 0) {
log_warn("Log file %s is not writable: %s", config->log_file, strerror(errno));
// Try to fix log directory permissions
if (chmod(dir, 0755) != 0) {
if (chmod_parent(config->log_file, 0755)) {
log_warn("Failed to change log directory permissions: %s", strerror(errno));
}
} else {
Expand Down Expand Up @@ -1452,7 +1406,7 @@ int save_config(const config_t *config, const char *path) {
struct stat st;
if (stat(dir_path, &st) != 0) {
log_warn("Directory %s does not exist, attempting to create it", dir_path);
if (create_directory(dir_path) != 0) {
if (mkdir_recursive(dir_path) != 0) {
log_error("Failed to create directory %s: %s", dir_path, strerror(errno));
return -1;
}
Expand Down
21 changes: 5 additions & 16 deletions src/core/daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "web/web_server.h"
#include "core/logger.h"
#include "core/daemon.h"
#include "core/path_utils.h"
#include "utils/strings.h"

extern volatile bool running; // Reference to the global variable defined in main.c
Expand Down Expand Up @@ -196,24 +197,12 @@ static void daemon_signal_handler(int sig) {
// Write PID file
int write_pid_file(const char *pid_file) {
// Make sure the directory exists
const char *last_slash = strrchr(pid_file, '/');
if (last_slash) {
char dir_path[MAX_PATH_LENGTH] = {0};
size_t dir_len = (size_t)(last_slash - pid_file);
memcpy(dir_path, pid_file, dir_len);
dir_path[dir_len] = '\0';

// Create directory if it doesn't exist
struct stat st;
if (stat(dir_path, &st) != 0) {
if (mkdir(dir_path, 0755) != 0 && errno != EEXIST) {
log_error("Could not create directory for PID file: %s", strerror(errno));
return -1;
}
}
if (ensure_path(pid_file) != 0) {
log_error("Failed to create PID file directory %s: %s", pid_file, strerror(errno));
return -1;
}

// Open the file with exclusive locking
// Open the file initially without exclusive locking
int fd = open(pid_file, O_RDWR | O_CREAT, 0644);
if (fd < 0) {
log_error("Failed to open PID file %s: %s", pid_file, strerror(errno));
Expand Down
45 changes: 2 additions & 43 deletions src/core/logger.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "core/config.h"
#include "core/logger.h"
#include "core/logger_json.h"
#include "core/path_utils.h"
#include "utils/strings.h"

// Logger state
Expand Down Expand Up @@ -183,48 +184,6 @@ void set_log_level(log_level_t level) {
}
}

// Create directory if it doesn't exist
static int create_directory(const char *path) {
struct stat st;

// Check if directory already exists
if (stat(path, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
return 0; // Directory exists
} else {
return -1; // Path exists but is not a directory
}
}

// Create directory with permissions 0755
if (mkdir(path, 0755) != 0) {
if (errno == ENOENT) {
// Parent directory doesn't exist, try to create it recursively
char *parent_path = strdup(path);
if (!parent_path) {
return -1;
}

const char *parent_dir = dirname(parent_path);
int ret = create_directory(parent_dir);
free(parent_path);

if (ret != 0) {
return -1;
}

// Try again to create the directory
if (mkdir(path, 0755) != 0) {
return -1;
}
} else {
return -1;
}
}

return 0;
}

// Set the log file
int set_log_file(const char *filename) {
if (!filename) return -1;
Expand All @@ -245,7 +204,7 @@ int set_log_file(const char *filename) {
}

const char *dir = dirname(dir_path);
if (create_directory(dir) != 0) {
if (mkdir_recursive(dir) != 0) {
free(dir_path);
pthread_mutex_unlock(&logger.mutex);
return -1;
Expand Down
45 changes: 2 additions & 43 deletions src/core/logger_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "core/config.h"
#include "core/logger.h"
#include "core/logger_json.h"
#include "core/path_utils.h"
#include "utils/strings.h"
#include <cjson/cJSON.h>

Expand All @@ -37,48 +38,6 @@ static const char *json_log_level_strings[] = {
"debug"
};

// Create directory if it doesn't exist (copied from logger.c)
static int create_directory(const char *path) {
struct stat st;

// Check if directory already exists
if (stat(path, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
return 0; // Directory exists
} else {
return -1; // Path exists but is not a directory
}
}

// Create directory with permissions 0755
if (mkdir(path, 0755) != 0) {
if (errno == ENOENT) {
// Parent directory doesn't exist, try to create it recursively
char *parent_path = strdup(path);
if (!parent_path) {
return -1;
}

const char *parent_dir = dirname(parent_path);
int ret = create_directory(parent_dir);
free(parent_path);

if (ret != 0) {
return -1;
}

// Try again to create the directory
if (mkdir(path, 0755) != 0) {
return -1;
}
} else {
return -1;
}
}

return 0;
}

/**
* @brief Initialize the JSON logger
*
Expand All @@ -104,7 +63,7 @@ int init_json_logger(const char *filename) {
}

const char *dir = dirname(dir_path);
if (create_directory(dir) != 0) {
if (mkdir_recursive(dir) != 0) {
free(dir_path);
pthread_mutex_unlock(&json_logger.mutex);
return -1;
Expand Down
Loading
Loading