1<?php 2// must be run within Dokuwiki 3if (!defined('DOKU_INC')) die(); 4if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 5 6class helper_plugin_maintenance extends DokuWiki_Plugin { 7 8 function __construct() { 9 global $conf; 10 $this->temp_dir = $conf['tmpdir'].'/maintenance'; 11 $this->script_last_log_file = $this->temp_dir.'/last.log'; 12 $this->script_last_pid_file = $this->temp_dir.'/last.pid'; 13 $this->script_last_script_file = $this->temp_dir.'/last.script'; 14 $this->manual_lock_file = $this->temp_dir.'/.lock'; 15 // put environmental variables to make shell scripts work right 16 $user = posix_getpwuid(posix_geteuid()); 17 putenv('HOME='.$user['dir']); 18 putenv('USER='.$user['name']); 19 putenv('LANG='."en_US.UTF-8"); 20 } 21 22 /** 23 * Gets the configured script 24 */ 25 function get_script() { 26 $script = $this->getConf('script'); 27 $script = str_replace( 28 array('%dokuwiki%', '%bin%'), 29 array(substr(DOKU_INC, 0, -1), dirname(__FILE__).'/bin'), 30 $script ); 31 return $script; 32 } 33 34 /** 35 * Checks whether the site is currently locked 36 * @return integer 1: locked, 0: not locked 37 */ 38 function is_locked() { 39 $locks = glob($this->temp_dir.'/*.lock'); 40 if (!empty($locks)) return 1; 41 if (is_file($this->temp_dir.'/.lock')) return 1; 42 return 0; 43 } 44 45 /** 46 * Runs a script and locks the site during running 47 * 48 * @return integer 2: already run, 1: success, 0: fail 49 */ 50 function script_start($script) { 51 $script_hash = sha1($script); 52 $lockfile = $this->temp_dir.'/'.$script_hash.'.lock'; 53 @io_mkdir_p(dirname($lockfile)); 54 $fh = fopen($lockfile, 'wb'); 55 if (flock($fh, LOCK_EX | LOCK_NB)) { 56 $cmd = 'nohup bash '.escapeshellarg($script).' > '.escapeshellarg($this->script_last_log_file). ' 2>&1 & echo $!'; 57 exec($cmd, $output, $result); 58 if ($result != 0) return 0; 59 file_put_contents($this->script_last_pid_file, $output[0]); 60 file_put_contents($this->script_last_script_file, $script_hash); 61 return 1; 62 } 63 return 2; 64 } 65 66 /** 67 * Kills the last started script 68 * 69 * @return integer 2: already not run, 1: success, 0: fail 70 */ 71 function script_stop() { 72 $script_hash = trim(file_get_contents($this->script_last_script_file)); 73 $lockfile = $this->temp_dir.'/'.$script_hash.'.lock'; 74 $result = $this->script_updatelock($lockfile); 75 if ($result != 1) return 2; 76 $pid = trim(file_get_contents($this->script_last_pid_file)); 77 $cmd = "ps p $pid >&-"; 78 exec($cmd, $output, $result); 79 if ($result != 0) return 2; 80 $cmd = "kill -9 $pid"; 81 exec($cmd, $output, $result); 82 if ($result != 0) return 0; 83 return 1; 84 } 85 86 /** 87 * Checks whether it's time to run 88 */ 89 function script_autocheck() { 90 $file = $this->script_last_pid_file; 91 $last_run = (is_file($file)) ? filemtime($file) : 0; 92 $interval = $this->getConf('script_auto_interval'); 93 $now = time(); 94 if ($now > $last_run+$interval) return true; 95 return false; 96 } 97 98 /** 99 * Checks all script locks 100 */ 101 function script_updatelockall() { 102 // glob doesn't match hidden (started with ".") files 103 $locks = glob($this->temp_dir.'/*.lock'); 104 foreach ($locks as $lock) { 105 $this->script_updatelock($lock); 106 } 107 } 108 109 /** 110 * Checks a script lock and removes it if already terminated 111 * 112 * @return integer 3: already no lock, 2: terminated and removed, 1: not terminated, 0: terminated and failed to remove 113 */ 114 function script_updatelock($lockfile) { 115 if (!is_file($lockfile)) return 3; 116 $fh = fopen($lockfile, 'wb'); 117 if (flock($fh, LOCK_EX | LOCK_NB)) { 118 @flock($fh, LOCK_UN); 119 @unlink($lockfile); 120 if (!is_file($lockfile)) return 2; 121 return 0; 122 } 123 return 1; 124 } 125 126 /** 127 * Locks the site manually, must unlock manually 128 * 129 * @return integer 2: already locked, 1: success, 0: fail 130 */ 131 function manual_lock() { 132 if (is_file($this->manual_lock_file)) return 2; 133 @io_mkdir_p(dirname($this->manual_lock_file)); 134 @touch($this->manual_lock_file); 135 if (is_file($this->manual_lock_file)) return 1; 136 return 0; 137 } 138 139 /** 140 * Removes a manual lock 141 * 142 * @return integer 2: already no lock, 1: success, 0: fail 143 */ 144 function manual_unlock() { 145 if (!is_file($this->manual_lock_file)) return 2; 146 @unlink($this->manual_lock_file); 147 if (!is_file($this->manual_lock_file)) return 1; 148 return 0; 149 } 150 151} 152