From b33b859cf29cf02a67b98aacba53d8c4bac9c2cc Mon Sep 17 00:00:00 2001 From: Christoph Date: Tue, 15 Sep 2026 21:01:03 +0200 Subject: [PATCH] =?UTF-8?q?Fix:=20Vorzeitiger=20Abbruch=20bei=20gro=C3=9Fe?= =?UTF-8?q?n=20Accounts=20nach=203600s=20Laufzeit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Betroffen: scan_, recover_, restore_, recreate_bad_signature.sh und diagnose_share_key.sh Bei Accounts mit sehr vielen bzw. sehr großen Dateien konnte der jeweilige Pro-Account-Durchlauf länger als eine Stunde dauern und wurde dann von PHP mit "Maximum execution time of 3600 seconds exceeded" abgebrochen - mitten im Lauf, ohne jedes Ergebnis. - su -c "$PHP_BIN ..." ruft PHP jetzt zusätzlich mit -d max_execution_time=0 auf. - Das allein reicht nicht: Nextclouds eigenes lib/base.php setzt beim Bootstrap unbedingt (fest einprogrammiert, nicht konfigurierbar) set_time_limit(3600) und überschreibt damit den CLI-Flag wieder. Daher zusätzlich direkt nach dem require von lib/base.php ein erneutes set_time_limit(0) in jedem der fünf eingebetteten PHP-Scripte, das Nextclouds Reset seinerseits rückgängig macht. Kein Verhaltensunterschied für kleine/normale Accounts, betrifft nur die maximale Laufzeit pro Account. --- diagnose_share_key.sh | 13 ++++++++++++- recover_bad_signature.sh | 22 ++++++++++++++-------- recreate_bad_signature.sh | 21 ++++++++++++++------- restore_bad_signature.sh | 21 +++++++++++++++------ scan_bad_signature.sh | 15 ++++++++++++++- 5 files changed, 69 insertions(+), 23 deletions(-) diff --git a/diagnose_share_key.sh b/diagnose_share_key.sh index 330bb20..89963f5 100755 --- a/diagnose_share_key.sh +++ b/diagnose_share_key.sh @@ -645,6 +645,13 @@ if ($oldWorkingDir === false) { } chdir(__DIR__); require_once __DIR__ . '/lib/base.php'; +// Nextcloud's own bootstrap (lib/base.php) unconditionally calls +// set_time_limit(3600) as part of the require above - this OVERRIDES +// whatever -d max_execution_time was passed on the PHP command line, +// since it is a later, explicit runtime call. Undo that here, now that +// the require is done, so diagnosing a large number of files isn't +// killed after exactly one hour regardless of the CLI flag. +set_time_limit(0); chdir($oldWorkingDir); if (function_exists('posix_getuid') && posix_getuid() === 0) { @@ -791,7 +798,11 @@ for _user in "${selected_user_arr[@]}" ; do owner_result_tsv="${LOCK_DIR}/owner_${_user}.tsv" echononl " Resolving ownership for account \033[1;37m${_user}\033[m (${_user_selected} files).." - su -c "$PHP_BIN $diag_php_file $_user $path_list_file" -s /bin/bash $HTTP_USER > "$owner_result_tsv" 2> "$log_file" + # -d max_execution_time=0: resolving ownership/key-material for a + # large number of files can run well over an hour; without this the + # PHP CLI process is killed by PHP's own execution-time limit + # (typically inherited from the webserver's php.ini) mid-run. + su -c "$PHP_BIN -d max_execution_time=0 $diag_php_file $_user $path_list_file" -s /bin/bash $HTTP_USER > "$owner_result_tsv" 2> "$log_file" _rc=$? if [[ $_rc -ne 0 ]]; then diff --git a/recover_bad_signature.sh b/recover_bad_signature.sh index c4c7b5e..81c3d07 100755 --- a/recover_bad_signature.sh +++ b/recover_bad_signature.sh @@ -813,13 +813,8 @@ if ! $_revalidate_only_explicit && $terminal ; then blank_line echo -e "\033[37m\033[1mWhich mode should this run use?\033[m" echo "" - echo -e " \033[1m[1] Recovery\033[m - decrypt bad-signature files (temporarily skips the signature check), - write them under \033[1m${DEFAULT_RECOVERY_BASE_DIR}/\033[m and validate them" - echo "" - echo " [2] Revalidate-only - re-run just the validation checks against files a previous recovery run - already wrote to disk (same as '-V'); nothing is decrypted again and no config - value is touched" - + echo -e " \033[1m[1] Recovery\033[m - decrypt bad-signature files (temporarily skips the signature check), write them under ${DEFAULT_RECOVERY_BASE_DIR}/ and validate them" + echo " [2] Revalidate-only - re-run just the validation checks against files a previous recovery run already wrote to disk (same as '-V'); nothing is decrypted again and no config value is touched" info "Just press Return to use the default: [1] Recovery." echo -n " Select mode by number [1]: " read _mode_choice @@ -1204,6 +1199,13 @@ if ($oldWorkingDir === false) { } chdir(__DIR__); require_once __DIR__ . '/lib/base.php'; +// Nextcloud's own bootstrap (lib/base.php) unconditionally calls +// set_time_limit(3600) as part of the require above - this OVERRIDES +// whatever -d max_execution_time was passed on the PHP command line, +// since it is a later, explicit runtime call. Undo that here, now that +// the require is done, so recovering a large account isn't killed +// after exactly one hour regardless of the CLI flag. +set_time_limit(0); chdir($oldWorkingDir); if (function_exists('posix_getuid') && posix_getuid() === 0) { @@ -1438,7 +1440,11 @@ for _user in "${selected_user_arr[@]}" ; do chown -R "$HTTP_USER":"$HTTP_GROUP" "$recovery_dir" 2> /dev/null echononl " Recovering account \033[1;37m${_user}\033[m (${_user_total} files).." - su -c "$PHP_BIN $recovery_php_file $_user $list_file $user_out_dir" -s /bin/bash $HTTP_USER > "$user_result_tsv" 2> "$log_file" + # -d max_execution_time=0: decrypting/validating every file of a + # large account can run well over an hour; without this the PHP + # CLI process is killed by PHP's own execution-time limit + # (typically inherited from the webserver's php.ini) mid-run. + su -c "$PHP_BIN -d max_execution_time=0 $recovery_php_file $_user $list_file $user_out_dir" -s /bin/bash $HTTP_USER > "$user_result_tsv" 2> "$log_file" _rc=$? fi diff --git a/recreate_bad_signature.sh b/recreate_bad_signature.sh index 41e492b..e29bbb0 100755 --- a/recreate_bad_signature.sh +++ b/recreate_bad_signature.sh @@ -782,12 +782,8 @@ if ! $_dry_run_explicit && $terminal ; then blank_line echo -e "\033[37m\033[1mWhich mode should this run use?\033[m" echo "" - echo -e " \033[1m[1] Dry-run\033[m - go through everything (selection, re-validation, share check, - reporting), but delete, back up, create or verify NOTHING" - echo "" - echo " [2] Real recreate - actually back up, DELETE the broken file, create it fresh - and verify each one" - + echo -e " \033[1m[1] Dry-run\033[m - go through everything (selection, re-validation, share check, reporting), but delete, back up, create or verify NOTHING" + echo " [2] Real recreate - actually back up, DELETE the broken file, create it fresh and verify each one" info "Just press Return to use the default: [1] Dry-run." echo -n " Select mode by number [1]: " read _mode_choice @@ -1166,6 +1162,13 @@ if ($oldWorkingDir === false) { } chdir(__DIR__); require_once __DIR__ . '/lib/base.php'; +// Nextcloud's own bootstrap (lib/base.php) unconditionally calls +// set_time_limit(3600) as part of the require above - this OVERRIDES +// whatever -d max_execution_time was passed on the PHP command line, +// since it is a later, explicit runtime call. Undo that here, now that +// the require is done, so recreating a large account isn't killed +// after exactly one hour regardless of the CLI flag. +set_time_limit(0); chdir($oldWorkingDir); if (function_exists('posix_getuid') && posix_getuid() === 0) { @@ -1767,7 +1770,11 @@ for _user in "${selected_user_arr[@]}" ; do _php_args=("$recreate_php_file" "$_user" "$list_file" "$DATA_DIR") $DRY_RUN && _php_args+=("--dry-run") $FORCE_SHARED && _php_args+=("--force") - su -c "$PHP_BIN ${_php_args[*]}" -s /bin/bash $HTTP_USER > "$user_result_tsv" 2> "$log_file" + # -d max_execution_time=0: recreating every selected file of a + # large account can run well over an hour; without this the PHP + # CLI process is killed by PHP's own execution-time limit + # (typically inherited from the webserver's php.ini) mid-run. + su -c "$PHP_BIN -d max_execution_time=0 ${_php_args[*]}" -s /bin/bash $HTTP_USER > "$user_result_tsv" 2> "$log_file" _rc=$? else echo -e "path\tbytes_written\tstatus\tdetail" > "$user_result_tsv" diff --git a/restore_bad_signature.sh b/restore_bad_signature.sh index 1a9f78f..09e20d7 100755 --- a/restore_bad_signature.sh +++ b/restore_bad_signature.sh @@ -812,11 +812,8 @@ if ! $_dry_run_explicit && $terminal ; then blank_line echo -e "\033[37m\033[1mWhich mode should this run use?\033[m" echo "" - echo -e " \033[1m[1] Dry-run\033[m - go through everything (selection, re-validation, reporting), - but write, back up and verify NOTHING" - echo "" + echo -e " \033[1m[1] Dry-run\033[m - go through everything (selection, re-validation, reporting), but write, back up and verify NOTHING" echo " [2] Real restore - actually back up, overwrite and verify each file in Nextcloud" - info "Just press Return to use the default: [1] Dry-run." echo -n " Select mode by number [1]: " read _mode_choice @@ -1228,6 +1225,13 @@ if ($oldWorkingDir === false) { } chdir(__DIR__); require_once __DIR__ . '/lib/base.php'; +// Nextcloud's own bootstrap (lib/base.php) unconditionally calls +// set_time_limit(3600) as part of the require above - this OVERRIDES +// whatever -d max_execution_time was passed on the PHP command line, +// since it is a later, explicit runtime call. Undo that here, now that +// the require is done, so restoring a large account isn't killed +// after exactly one hour regardless of the CLI flag. +set_time_limit(0); chdir($oldWorkingDir); if (function_exists('posix_getuid') && posix_getuid() === 0) { @@ -1498,10 +1502,15 @@ for _user in "${selected_user_arr[@]}" ; do fi if [[ -s "$list_file" ]] ; then + # -d max_execution_time=0: re-validating and writing back every + # selected file of a large account can run well over an hour; + # without this the PHP CLI process is killed by PHP's own + # execution-time limit (typically inherited from the webserver's + # php.ini) mid-run. if $DRY_RUN ; then - su -c "$PHP_BIN $restore_php_file $_user $list_file --dry-run" -s /bin/bash $HTTP_USER > "$user_result_tsv" 2> "$log_file" + su -c "$PHP_BIN -d max_execution_time=0 $restore_php_file $_user $list_file --dry-run" -s /bin/bash $HTTP_USER > "$user_result_tsv" 2> "$log_file" else - su -c "$PHP_BIN $restore_php_file $_user $list_file" -s /bin/bash $HTTP_USER > "$user_result_tsv" 2> "$log_file" + su -c "$PHP_BIN -d max_execution_time=0 $restore_php_file $_user $list_file" -s /bin/bash $HTTP_USER > "$user_result_tsv" 2> "$log_file" fi _rc=$? else diff --git a/scan_bad_signature.sh b/scan_bad_signature.sh index 53ee9da..56067f3 100755 --- a/scan_bad_signature.sh +++ b/scan_bad_signature.sh @@ -582,6 +582,14 @@ fwrite(STDERR, "DEBUG: vor require lib/base.php\n"); require_once __DIR__ . '/lib/base.php'; fwrite(STDERR, "DEBUG: nach require lib/base.php - Bootstrap abgeschlossen\n"); +// Nextcloud's own bootstrap (lib/base.php) unconditionally calls +// set_time_limit(3600) as part of require_once above - this OVERRIDES +// whatever -d max_execution_time was passed on the PHP command line, +// since it is a later, explicit runtime call. Undo that here, now that +// the require is done, so a full-content scan of a large account isn't +// killed after exactly one hour regardless of the CLI flag. +set_time_limit(0); + chdir($oldWorkingDir); if (function_exists('posix_getuid') && posix_getuid() === 0) { @@ -810,7 +818,12 @@ for _user in "${selected_user_arr[@]}" ; do } >> "$report_file" echononl " Scanning account \033[1;37m${_user}\033[m.." - su -c "$PHP_BIN $scan_php_file $_user" -s /bin/bash $HTTP_USER > "$user_tsv" 2> "$log_file" + # -d max_execution_time=0: a full-content read of every file of a + # large account can easily run well over an hour; without this the + # PHP CLI process is killed by PHP's own execution-time limit + # (typically inherited from the webserver's php.ini) mid-scan, long + # before any actual error in the account's files. + su -c "$PHP_BIN -d max_execution_time=0 $scan_php_file $_user" -s /bin/bash $HTTP_USER > "$user_tsv" 2> "$log_file" _rc=$? if [[ $_rc -ne 0 ]]; then