diff -upNr ./includes/bootstrap.inc /home/joshua/public_html/d7/includes/bootstrap.inc --- ./includes/bootstrap.inc 2009-08-06 22:45:49.740609377 -0500 +++ /home/joshua/public_html/d7/includes/bootstrap.inc 2009-08-06 17:04:35.938289481 -0500 @@ -1585,6 +1585,13 @@ function drupal_installation_attempted() } /** + * Return TRUE if a Drupal recovery is being attempted. + */ +function drupal_recovery_attempted() { + return defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'recovery'; +} + +/** * Return the name of the localization function. Use in code that needs to * run both during installation and normal operation. */ diff -upNr ./includes/module.inc /home/joshua/public_html/d7/includes/module.inc --- ./includes/module.inc 2009-08-05 11:16:41.000000000 -0500 +++ /home/joshua/public_html/d7/includes/module.inc 2009-08-06 17:05:08.516198684 -0500 @@ -299,8 +299,12 @@ function module_disable($module_list) { node_access_needs_rebuild(TRUE); } - module_load_install($module); - module_invoke($module, 'disable'); + // If a recovery is in place we can assume this failed in the past. + if (!drupal_recovery_attempted()) { + module_load_install($module); + module_invoke($module, 'disable'); + } + db_update('system') ->fields(array('status' => 0)) ->condition('type', 'module') diff -upNr ./modules/system/system.admin.inc /home/joshua/public_html/d7/modules/system/system.admin.inc --- ./modules/system/system.admin.inc 2009-08-05 14:40:55.000000000 -0500 +++ /home/joshua/public_html/d7/modules/system/system.admin.inc 2009-08-06 20:44:03.573635104 -0500 @@ -299,7 +299,8 @@ function system_themes_form_submit($form menu_rebuild(); drupal_theme_rebuild(); drupal_set_message(t('The configuration options have been saved.')); - $form_state['redirect'] = 'admin/appearance'; + + $form_state['redirect'] = drupal_recovery_attempted() ? 'recovery.php' : 'admin/appearance'; // Notify locale module about new themes being enabled, so translations can // be imported. This might start a batch, and only return to the redirect @@ -607,6 +608,12 @@ function system_modules($form_state = ar foreach ($files as $filename => $module) { $extra = array(); $extra['enabled'] = (bool) $module->status; + + // Users don't need to be able to enable modules from the recovery console. + if (!$extra['enabled'] && drupal_recovery_attempted()) { + continue; + } + // If this module requires other modules, add them to the array. foreach ($module->requires as $requires => $v) { if (!isset($files[$requires])) { @@ -686,6 +693,12 @@ function system_modules($form_state = ar ); $form['#action'] = url('admin/structure/modules/list/confirm'); + // Since modules get loaded during the validation step, validating could + // cause even the recovery console to be unable to remove a stubborn module. + if (drupal_recovery_attempted()) { + $form['#action'] = 'recovery.php'; +// $form['#submit'] = 'system_modules_submit'; + } return $form; } @@ -957,6 +970,9 @@ function system_modules_submit($form, &$ drupal_clear_js_cache(); $form_state['redirect'] = 'admin/structure/modules'; + if (drupal_recovery_attempted()) { + $form_state['redirect'] = 'recovery.php'; + } // Notify locale module about module changes, so translations can be // imported. This might start a batch, and only return to the redirect @@ -2207,12 +2223,21 @@ function theme_system_themes_form($form) $row[] = array('data' => $status, 'align' => 'center'); if ($form['theme_default']) { $row[] = array('data' => drupal_render($form['theme_default'][$key]), 'align' => 'center'); - $row[] = array('data' => drupal_render($form[$key]['operations']), 'align' => 'center'); + if (!drupal_recovery_attempted()) { + $row[] = array('data' => drupal_render($form[$key]['operations']), 'align' => 'center'); + } + else { + unset($form[$key]['operations']); + } } $rows[] = $row; } - $header = array(t('Screenshot'), t('Name'), t('Version'), t('Enabled'), t('Default'), t('Operations')); + $header = array(t('Screenshot'), t('Name'), t('Version'), t('Enabled'), t('Default')); + if (!defined('MAINTENANCE_MODE')) { + $header[] = t('Operations'); + } + $output = theme('table', $header, $rows); $output .= drupal_render_children($form); return $output; diff -upNr ./modules/user/user.module /home/joshua/public_html/d7/modules/user/user.module --- ./modules/user/user.module 2009-08-06 00:06:00.000000000 -0500 +++ /home/joshua/public_html/d7/modules/user/user.module 2009-08-06 17:07:35.238683932 -0500 @@ -1702,7 +1702,7 @@ function user_login_submit($form, &$form $user = user_load($form_state['uid']); user_login_finalize(); - $form_state['redirect'] = 'user/' . $user->uid; + $form_state['redirect'] = drupal_recovery_attempted() ? 'recovery.php' : 'user/' . $user->uid; } /** diff -upNr ./recovery.php /home/joshua/public_html/d7/recovery.php --- /dev/null 1969-12-31 18:00:00.000000000 -0600 +++ ./recovery.php 2009-08-06 22:48:31.490586888 -0500 @@ -0,0 +1,101 @@ +In order to recover Drupal, you must be logged in as the admin user (the first user you created). You can use the form below. If you cannot log in you will have to edit settings.php to bypass this access check. To do this:

+
    +
  1. With a text editor find the settings.php file on your system. From the main Drupal directory that you installed all the files into, go to sites/your_site_name if such directory exists, or else to sites/default which applies otherwise.
  2. +
  3. There is a line inside your settings.php file that says $update_free_access = FALSE;. Change it to $update_free_access = TRUE;.
  4. +
  5. As soon as the recover.php script is done, you must change the settings.php file back to its original form with $update_free_access = FALSE;.
  6. +
'; +} + +/** + * Display instructions to UID 1. + */ +function recovery_instruction_page() { + return '

Before you continue, please keep this in mind: The recovery console is not meant for day to day maintainence. It is only meant to be used to deactivate modules or themes which cripple a Drupal installation.

'; +} + +/** + * Display information form the module page. + */ +function recovery_module_page() { + return '

This form is designed to be used when all other attempts have failed. To make sure that this does not fail, no part of the module is loaded. Thus, any hooks which would normally run when disabling a module will not be run.

Also, since this form is designed for removing defective modules, modules which are inactive will not be displayed.

'; +} + +/* Begin Recovery Section */ + +// Boot the core of Drupal without loading any unneccessary modules. +require DRUPAL_ROOT . '/includes/bootstrap.inc'; +drupal_bootstrap(DRUPAL_BOOTSTRAP_CORE); +foreach (array('system', 'filter', 'user', 'node', 'field') AS $module) { + drupal_load('module', $module); +} +drupal_maintenance_theme(); + +// Decide which page to send us to. +$recovery_access_allowed = !empty($update_free_access) || $user->uid == 1; +if (!$recovery_access_allowed) { + + // If we aren't authorized to use the console, give a login prompt. + drupal_set_title('Recovery Login'); + $user = drupal_anonymous_user(); + $output = recovery_login_page(); + $output .= drupal_render(drupal_get_form('user_login')); +} +elseif (empty($_GET['op']) && empty($_POST)) { + + // If we are authorized but haven't specified a page, show the instructions. + drupal_set_title('Recovery Instructions'); + $output = recovery_instruction_page(); + $output .= '

' . l(t('Module recovery.'), 'recovery.php', array('query' => 'op=modules')) . '

'; + $output .= '

' . l(t('Theme recovery.'), 'recovery.php', array('query' => 'op=theme')) . '

'; +} +elseif (empty($_GET['op'])) { + + // Data is being submitted from the modules page. + drupal_render(drupal_get_form('system_modules')); +} +elseif ($_GET['op'] == 'modules') { + + // Allow for a chance to remove modules. + drupal_set_title('Module recovery'); + $output = recovery_module_page(); + $output .= '

' . l(t('Return to the instructions.'), 'recovery.php') . '

'; + $output .= drupal_render(drupal_get_form('system_modules')); +} +else { + + // Allow the user to change themes. + $output = '

' . l(t('Return to the instructions.'), 'recovery.php') . '

'; + $output .= drupal_render(drupal_get_form('system_themes_form')); +} + +print theme('update_page', $output); +exit(0); +