Skip to content

Commit e2bc0fa

Browse files
matteiusclaude
andcommitted
Avoid recursive chown/chmod on large recording directories (fixes #368)
On deployments with hundreds of thousands of recording files, the recursive `chown -R` and `chmod -R` in docker-entrypoint.sh blocked container startup for hours on spinning disks. - Only recurse into small directories (config, logs, database, models) - For recording and data directories, fix the directory entry itself without walking its contents - Add SKIP_PERMISSIONS_CHECK=true env var to bypass entirely - Replace chmod_recursive() with chmod_path() in mp4_recording_core.c since only the output directory needs permission fixes, not every file within it Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent cdb2e11 commit e2bc0fa

2 files changed

Lines changed: 33 additions & 15 deletions

File tree

docker-entrypoint.sh

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -214,15 +214,33 @@ EOF
214214
fi
215215

216216
# Ensure proper permissions (may fail on NFS, which is okay)
217-
log_info "Setting permissions..."
218-
CURRENT_UID="$(id -u)"
219-
CURRENT_GID="$(id -g)"
220-
chown -R "${CURRENT_UID}:${CURRENT_GID}" /var/lib/lightnvr 2>/dev/null || log_warn "Could not set ownership on /var/lib/lightnvr (may be on NFS)"
221-
chown -R "${CURRENT_UID}:${CURRENT_GID}" /etc/lightnvr 2>/dev/null || log_warn "Could not set ownership on /etc/lightnvr (may be on NFS)"
222-
chown -R "${CURRENT_UID}:${CURRENT_GID}" /var/log/lightnvr 2>/dev/null || log_warn "Could not set ownership on /var/log/lightnvr"
223-
chmod -R 755 /var/lib/lightnvr 2>/dev/null || log_warn "Could not set permissions on /var/lib/lightnvr (may be on NFS)"
224-
chmod -R 755 /etc/lightnvr 2>/dev/null || log_warn "Could not set permissions on /etc/lightnvr (may be on NFS)"
225-
chmod -R 755 /var/log/lightnvr 2>/dev/null || log_warn "Could not set permissions on /var/log/lightnvr"
217+
# Skip entirely if the user opts out via environment variable
218+
if [ "${SKIP_PERMISSIONS_CHECK:-false}" = "true" ]; then
219+
log_info "Skipping permissions check (SKIP_PERMISSIONS_CHECK=true)"
220+
else
221+
log_info "Setting permissions..."
222+
CURRENT_UID="$(id -u)"
223+
CURRENT_GID="$(id -g)"
224+
225+
# Recursive chown/chmod on small directories only (config, logs, database, models)
226+
for dir in /etc/lightnvr /var/log/lightnvr \
227+
/var/lib/lightnvr/data/database /var/lib/lightnvr/data/models; do
228+
[ -d "$dir" ] || continue
229+
chown -R "${CURRENT_UID}:${CURRENT_GID}" "$dir" 2>/dev/null || log_warn "Could not set ownership on $dir (may be on NFS)"
230+
chmod -R 755 "$dir" 2>/dev/null || log_warn "Could not set permissions on $dir (may be on NFS)"
231+
done
232+
233+
# For data directories that may contain hundreds of thousands of recording
234+
# files, only fix the directory itself (non-recursive) to avoid an O(n)
235+
# walk that can block startup for hours on large deployments (see #368).
236+
for dir in /var/lib/lightnvr /var/lib/lightnvr/data \
237+
/var/lib/lightnvr/data/recordings /var/lib/lightnvr/data/recordings/mp4 \
238+
/var/lib/lightnvr/www; do
239+
[ -d "$dir" ] || continue
240+
chown "${CURRENT_UID}:${CURRENT_GID}" "$dir" 2>/dev/null || true
241+
chmod 755 "$dir" 2>/dev/null || true
242+
done
243+
fi
226244

227245
# Test write permissions on critical directories
228246
log_info "Testing write permissions..."

src/video/mp4_recording_core.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ static void *mp4_recording_thread(void *arg) {
141141
}
142142

143143
// Set permissions
144-
if (chmod_recursive(mp4_dir, 0755) != 0) {
144+
if (chmod_path(mp4_dir, 0755) != 0) {
145145
log_warn("Failed to set permissions on directory: %s", mp4_dir);
146146
}
147147

@@ -153,7 +153,7 @@ static void *mp4_recording_thread(void *arg) {
153153
log_error("Output directory is not writable: %s", mp4_dir);
154154

155155
// Try to fix permissions
156-
if (chmod_recursive(mp4_dir, 0755) != 0) {
156+
if (chmod_path(mp4_dir, 0755) != 0) {
157157
log_warn("Failed to set permissions on directory: %s", mp4_dir);
158158
}
159159

@@ -689,7 +689,7 @@ int start_mp4_recording(const char *stream_name) {
689689
}
690690

691691
// Set appropriate permissions for MP4 directory (owner rwx, group/others rx)
692-
if (chmod_recursive(mp4_dir, 0755) != 0) {
692+
if (chmod_path(mp4_dir, 0755) != 0) {
693693
log_warn("Failed to set permissions on MP4 directory: %s", mp4_dir);
694694
}
695695

@@ -859,7 +859,7 @@ int start_mp4_recording_with_url(const char *stream_name, const char *url) {
859859
}
860860

861861
// Set permissions for MP4 directory (owner rwx, group/others rx)
862-
if (chmod_recursive(mp4_dir, 0755) != 0) {
862+
if (chmod_path(mp4_dir, 0755) != 0) {
863863
log_warn("Failed to set permissions on MP4 directory: %s", mp4_dir);
864864
}
865865

@@ -1075,7 +1075,7 @@ int start_mp4_recording_with_trigger(const char *stream_name, const char *trigge
10751075
}
10761076

10771077
// Set permissions for MP4 directory (owner rwx, group/others rx)
1078-
if (chmod_recursive(mp4_dir, 0755) != 0) {
1078+
if (chmod_path(mp4_dir, 0755) != 0) {
10791079
log_warn("Failed to set permissions on MP4 directory: %s", mp4_dir);
10801080
}
10811081

@@ -1230,7 +1230,7 @@ int start_mp4_recording_with_url_and_trigger(const char *stream_name, const char
12301230
}
12311231

12321232
// Set permissions for MP4 directory (owner rwx, group/others rx)
1233-
if (chmod_recursive(mp4_dir, 0755) != 0) {
1233+
if (chmod_path(mp4_dir, 0755) != 0) {
12341234
log_warn("Failed to set permissions on MP4 directory: %s", mp4_dir);
12351235
}
12361236

0 commit comments

Comments
 (0)