function deactivate_user($username) { global $users, $is_control_node, $is_compute_node, $conf_base_path, $is_svn_node, $svn_node_addr, $conf_svn_problems_log, $conf_ssh_tunneling; $userdata = setup_paths($username); // If this is a simple compute node, just kill nodejs if ($is_compute_node && !$is_control_node) { stop_node($username, true); // $cleanup=true -- kill everything owned by user $users[$username]['status'] = "inactive"; unset($users[$username]['collaborate']); unset($users[$username]['server']); unset($users[$username]['port']); write_files(); } else { if ($is_control_node) { debug_log("deactivate_user {$username}"); // Update logout file $script = "date > " . $userdata['workspace'] . "/.logout"; run_as($username, $script); // Remove user from nginx - this will inform user that they are logged out $server = $users[$username]['server']; $users[$username]['status'] = "inactive"; $port = $users[$username]['port']; unset($users[$username]['collaborate']); unset($users[$username]['server']); unset($users[$username]['port']); write_nginx_config(); // Stop nodejs on server where user is running if (is_local($server) || empty($server)) { stop_node($username, false); } else { run_on($server, "{$conf_base_path}/bin/webidectl logout " . $userdata['esa']); if ($conf_ssh_tunneling) { foreach (ps_ax("localhost") as $process) { if (strstr($process['cmd'], "ssh -N -L {$port}")) { exec("kill " . $process['pid']); } } } } if (!$is_svn_node) { proc_close(proc_open("ssh {$svn_node_addr} \"{$conf_base_path}/bin/webidectl logout " . $userdata['esa'] . "\" 2>&1 &", array(), $foo)); } } } if ($is_svn_node) { $users[$username]['status'] = "inactive"; write_files(); // Syncsvn deactivate sleep(1); // Give some time for syncsvn to sync .logout if (file_exists($userdata['svn_watch'])) { $pid = trim(file_get_contents($userdata['svn_watch'])); if (file_exists("/proc/{$pid}")) { exec("kill {$pid}"); } unlink($userdata['svn_watch']); } stop_inotify($username); // Commit remaining stuff to svn $script = "cd " . $userdata['workspace'] . "; "; $script .= "echo USER: {$username} >> {$conf_svn_problems_log}; "; $script .= "svn ci -m deactivate_user . 2>&1 >> {$conf_svn_problems_log}"; run_as($username, $script); fixsvn($username); } else { if ($is_control_node) { // run_on($svn_node_addr, "$conf_base_path/bin/webidectl logout " . $userdata['esa']); } } if ($is_control_node) { // Users file is updated only now, to prevent user from logging back in during other procedures // (BFL should prevent it but alas...) write_files(); } }
function fixsvn($command) { global $username, $userdata, $debug, $sleep, $conf_base_path, $conf_c9_group; if ($debug) { print "Command: {$command}\n"; } $output = run_as($username, "cd " . $userdata['workspace'] . "; {$command} 2>&1"); if ($debug) { print "Result: \n"; } $ok = false; if (empty($output)) { $ok = true; } foreach (explode("\n", $output) as $line) { if ($debug) { print "{$line}\n"; } $matches = array(); if (strstr($line, "Committed revision")) { $ok = true; break; } else { if (strstr($line, "Previous operation has not finished")) { fixsvn("svn cleanup"); fixsvn($command); $ok = true; break; } else { if (strstr($line, "is already locked")) { fixsvn("svn cleanup"); fixsvn($command); $ok = true; break; } else { if (preg_match("/File '(.*?)' is out of date/", $line, $matches) || preg_match("/Base checksum mismatch on '(.*?)'/", $line, $matches)) { $filename = basename($matches[1]); $wsname = substr($matches[1], strlen($userdata['workspace']) + 1); unlink("/tmp/{$filename}"); fixsvn("cp \"" . $matches[1] . "\" \"/tmp/{$filename}\""); unlink($matches[1]); fixsvn("svn update --accept mine-full \"{$wsname}\""); fixsvn("cp \"/tmp/{$filename}\" \"{$wsname}\""); unlink("/tmp/{$filename}"); fixsvn("svn ci -m fixsvn \"{$wsname}\""); fixsvn($command); $ok = true; break; } else { if (preg_match("/Directory '(.*?)' is out of date/", $line, $matches)) { // Let's hope there are no local changes to files... $filename = basename($matches[1]); $wsname = substr($matches[1], strlen($userdata['workspace']) + 1); fixsvn("svn update --accept mine-full \"{$wsname}\""); fixsvn($command); $ok = true; break; } else { if (preg_match("/Aborting commit: '(.*?)' remains in conflict/", $line, $matches) || preg_match("/Tree conflict can only be resolved to 'working' state: '(.*?)' not resolved/", $line, $matches)) { $filename = basename($matches[1]); $wsname = substr($matches[1], strlen($userdata['workspace']) + 1); fixsvn("svn resolve --accept mine-full \"{$wsname}\""); fixsvn($command); $ok = true; break; } else { if (preg_match("/Can't change perms of file '(.*?)': No such file or directory/", $line, $matches) || preg_match("/'(.*?)' is scheduled for addition, but is missing/", $line, $matches)) { $filename = basename($matches[1]); $wsname = substr($matches[1], strlen($userdata['workspace']) + 1); run_as($username, "cd " . $userdata['workspace'] . "; touch \"{$wsname}\""); fixsvn($command); $ok = true; break; } else { if (preg_match("/Node '(.*?)' has unexpectedly changed kind/", $line, $matches)) { $filename = basename($matches[1]); $wsname = substr($matches[1], strlen($userdata['workspace']) + 1); if (is_dir($matches[1])) { $files = scandir($matches[1]); if (count($files) == 2) { // Directory empty, add an empty file instead rmdir($matches[1]); run_as($username, "cd " . $userdata['workspace'] . "; touch \"{$wsname}\""); fixsvn($command); $ok = true; } else { // Directory not empty // Copy to tmp, commit file, readd `rm -fr /tmp/{$filename}`; run_as($username, "mv \"" . $matches[1] . "\" /tmp/{$filename}"); run_as($username, "cd " . $userdata['workspace'] . "; touch \"{$wsname}\""); fixsvn("svn ci -m fixsvn \"{$wsname}\""); fixsvn("svn remove \"{$wsname}\""); fixsvn("svn ci -m fixsvn \"{$wsname}\""); run_as($username, "mv /tmp/{$filename} \"" . $matches[1] . "\""); fixsvn("svn add \"{$wsname}\""); fixsvn("svn ci -m fixsvn \"{$wsname}\""); } } else { $contents = file_get_contents($matches[1]); unlink($matches[1]); run_as($username, "cd " . $userdata['workspace'] . "; mkdir \"{$wsname}\""); fixsvn($command); if (!empty($contents)) { // After $command directory may become file again! if (is_dir($matches[1])) { $newname = $matches[1] . "/" . $filename; file_put_contents($newname, $contents); exec("chown {$username}:{$conf_c9_group} \"{$newname}\""); } else { file_put_contents($matches[1], $contents); fixsvn("svn add \"{$wsname}\""); fixsvn("svn ci -m fixsvn \"{$wsname}\""); } } $ok = true; } break; } else { if (preg_match("/Invalid control character '.*?' in path '(.*?)'/", $line, $matches) || preg_match("/Error converting entry in directory '(.*?)' to/", $line, $matches) || preg_match("/'(.*?)': a peg revision is not allowed here/", $line, $matches)) { $basedir = $matches[1]; if (strstr($line, "Invalid control") || strstr($line, "a peg revision")) { $basedir = dirname($basedir); } if (strstr($line, "a peg revision")) { $basedir = $userdata['workspace'] . "/" . $basedir; } $dh = opendir($basedir); while ($filename = readdir($dh)) { //print "Filename: $filename\n"; if (preg_match('/[[:^print:]]/', $filename) || strstr($filename, "@")) { $new_filename = preg_replace('/[[:^print:]]/', '?', $filename); $new_filename = str_replace('@', '?', $new_filename); print "Renaming {$filename} to {$new_filename}\n"; rename($basedir . "/" . $filename, $basedir . "/" . $new_filename); } } fixsvn($command); $ok = true; break; } else { if (preg_match("/Can't move '.*?' to '(.*?)': Permission denied/", $line, $matches)) { $path = dirname($matches[1]); exec("chown -R {$username}:{$conf_c9_group} " . escapeshellarg($path)); fixsvn($command); $ok = true; break; } else { if (strstr($line, "Directory '/' is out of date")) { fixsvn("svn update ."); fixsvn($command); $ok = true; break; } else { if (strstr($line, "Could not add all targets because some targets are already versioned") || strstr($line, "Could not add all targets because some targets don't exist")) { $ok = true; } else { if (strstr($line, "Resolved conflicted state of")) { $ok = true; } else { if (strstr($line, "Updated to revision") || strstr($line, "At revision") || strstr($line, "Committed revision")) { $ok = true; } else { if (strstr($line, "D ") || strstr($line, "A ")) { $ok = true; } } } } } } } } } } } } } } } } if (!$ok) { print "Unkown error!\n\n"; $sleep += 5; exec("php {$conf_base_path}/bin/fixsvn.php " . $userdata['esa'] . " {$sleep} &"); exit(1); } }