$row['currentsession'])); if ($lecture !== false) { $row['currentsession'] = $lecture['displayname']; $row['lectureid'] = $lecture['lectureid']; } $row['session'] = $row['currentsession']; return; } } $res = Database::simpleQuery('SELECT dateline, username, data FROM statistic' . " WHERE clientip = :ip AND typeid = '.vmchooser-session-name'" . ' AND dateline BETWEEN :start AND :end', array( 'ip' => $row['clientip'], 'start' => $row['logintime'] - 60, 'end' => $row['logintime'] + 300, )); $session = false; while ($r = $res->fetch(PDO::FETCH_ASSOC)) { if ($session === false || abs($session['dateline'] - $row['logintime']) > abs($r['dateline'] - $row['logintime'])) { $session = $r; } } if ($session !== false) { $row['session'] = $session['data']; if (empty($row['currentuser'])) { $row['username'] = $session['username']; } } } private static function showMachine($uuid) { $client = Database::queryFirst('SELECT machineuuid, locationid, macaddr, clientip, firstseen, lastseen, logintime, lastboot, state, mbram, live_tmpsize, live_tmpfree, live_swapsize, live_swapfree, live_memsize, live_memfree, live_cpuload, live_cputemp, Length(position) AS hasroomplan, kvmstate, cpumodel, id44mb, data, hostname, currentuser, currentsession, notes FROM machine WHERE machineuuid = :uuid', array('uuid' => $uuid)); if ($client === false) { Message::addError('unknown-machine', $uuid); return; } if (Module::isAvailable('locations') && !Location::isLeaf($client['locationid'])) { $client['hasroomplan'] = false; } User::assertPermission('machine.view-details', (int)$client['locationid']); // Hack: Get raw collected data if (Request::get('raw', false)) { Header('Content-Type: text/plain; charset=utf-8'); die($client['data']); } // Runmode if (Module::isAvailable('runmode')) { $data = RunMode::getRunMode($uuid, RunMode::DATA_STRINGS); if ($data !== false) { $client += $data; } } // Rebootcontrol if (Module::get('rebootcontrol') !== false) { $client['canReboot'] = (User::hasPermission('.rebootcontrol.action.reboot', (int)$client['locationid'])); $client['canShutdown'] = (User::hasPermission('.rebootcontrol.action.shutdown', (int)$client['locationid'])); $client['canWol'] = (User::hasPermission('.rebootcontrol.action.wol', (int)$client['locationid'])); $client['canExec'] = (User::hasPermission('.rebootcontrol.action.exec', (int)$client['locationid'])); $client['rebootcontrol'] = $client['canReboot'] || $client['canShutdown'] || $client['canWol'] || $client['canExec']; } // Baseconfig if (Module::get('baseconfig') !== false && User::hasPermission('.baseconfig.view', (int)$client['locationid'])) { $cvs = Database::queryFirst('SELECT Count(*) AS cnt FROM setting_machine WHERE machineuuid = :uuid', ['uuid' => $uuid]); $client['overriddenVars'] = is_array($cvs) ? $cvs['cnt'] : 0; $client['hasBaseconfig'] = true; } if (!isset($client['isclient'])) { $client['isclient'] = true; } // Mangle fields $NOW = time(); if (!$client['isclient']) { if ($client['state'] === 'IDLE') { $client['state'] = 'OCCUPIED'; } } else { if ($client['state'] === 'OCCUPIED') { self::fillSessionInfo($client); } } $client['state_' . $client['state']] = true; $client['firstseen_s'] = date('d.m.Y H:i', $client['firstseen']); $client['lastseen_s'] = date('d.m.Y H:i', $client['lastseen']); $client['logintime_s'] = date('d.m.Y H:i', $client['logintime']); if ($client['lastboot'] == 0) { $client['lastboot_s'] = '-'; } else { $uptime = $NOW - $client['lastboot']; $client['lastboot_s'] = date('d.m.Y H:i', $client['lastboot']); if ($client['state'] === 'IDLE' || $client['state'] === 'OCCUPIED') { $client['lastboot_s'] .= ' (Up ' . floor($uptime / 86400) . 'd ' . gmdate('H:i', $uptime) . ')'; } } $client['gbram'] = round(ceil($client['mbram'] / 512) / 2, 1); $client['gbtmp'] = round($client['id44mb'] / 1024); foreach (['tmp', 'swap', 'mem'] as $item) { if ($client['live_' . $item . 'size'] == 0) continue; $client['live_' . $item . 'percent'] = round(($client['live_' . $item . 'free'] / $client['live_' . $item . 'size']) * 100, 2); $client['live_' . $item . 'free_s'] = Util::readableFileSize($client['live_' . $item . 'free'], -1, 2); } if ($client['live_cpuload'] <= 100) { $client['live_cpuload_s'] = $client['live_cpuload'] . "\xe2\x80\x89%"; $client['live_cpuidle'] = 100 - $client['live_cpuload']; } $client['live_cputemppercent'] = max(0, min(100, 110 - $client['live_cputemp'])); $client['ramclass'] = StatisticsStyling::ramColorClass($client['mbram']); $client['kvmclass'] = StatisticsStyling::kvmColorClass($client['kvmstate']); $client['hddclass'] = StatisticsStyling::hddColorClass($client['gbtmp']); // Parse the giant blob of data if (strpos($client['data'], "\r") !== false) { $client['data'] = str_replace("\r", "\n", $client['data']); } $hdds = array(); if (preg_match_all('/##### ([^#]+) #+$(.*?)^#####/ims', $client['data'] . '########', $out, PREG_SET_ORDER)) { foreach ($out as $section) { if ($section[1] === 'CPU') { Parser::parseCpu($client, $section[2]); } if ($section[1] === 'dmidecode') { Parser::parseDmiDecode($client, $section[2]); } if ($section[1] === 'Partition tables') { Parser::parseHdd($hdds, $section[2]); } if ($section[1] === 'PCI ID') { $client['lspci1'] = $client['lspci2'] = array(); Parser::parsePci($client['lspci1'], $client['lspci2'], $section[2]); } if (isset($hdds['hdds']) && $section[1] === 'smartctl') { // This currently requires that the partition table section comes first... Parser::parseSmartctl($hdds['hdds'], $section[2]); } } } unset($client['data']); // BIOS update check if (!empty($client['biosrevision'])) { $mainboard = $client['mobomanufacturer'] . '##' . $client['mobomodel']; $system = $client['pcmanufacturer'] . '##' . $client['pcmodel']; $ret = self::checkBios($mainboard, $system, $client['biosdate'], $client['biosrevision']); if ($ret === false) { // Not loaded, use AJAX $params = [ 'mainboard' => $mainboard, 'system' => $system, 'date' => $client['biosdate'], 'revision' => $client['biosrevision'], ]; $client['biosurl'] = '?do=statistics&action=bios&' . http_build_query($params); } elseif (!isset($ret['status']) || $ret['status'] !== 0) { $client['bioshtml'] = Render::parse('machine-bios-update', $ret); } } // Get locations if (Module::isAvailable('locations')) { $locs = Location::getLocationsAssoc(); $next = (int)$client['locationid']; $output = array(); while (isset($locs[$next])) { array_unshift($output, $locs[$next]); $next = $locs[$next]['parentlocationid']; } $client['locations'] = $output; } // Screens TODO Move everything else to hw table instead of blob parsing above // `devicetype`, `devicename`, `subid`, `machineuuid` $res = Database::simpleQuery("SELECT m.hwid, h.hwname, m.devpath AS connector, m.disconnecttime," . " p.value AS resolution, q.prop AS projector FROM machine_x_hw m" . " INNER JOIN statistic_hw h ON (m.hwid = h.hwid AND h.hwtype = :screen)" . " LEFT JOIN machine_x_hw_prop p ON (m.machinehwid = p.machinehwid AND p.prop = 'resolution')" . " LEFT JOIN statistic_hw_prop q ON (m.hwid = q.hwid AND q.prop = 'projector')" . " WHERE m.machineuuid = :uuid", array('screen' => DeviceType::SCREEN, 'uuid' => $uuid)); $client['screens'] = array(); $ports = array(); while ($row = $res->fetch(PDO::FETCH_ASSOC)) { if ($row['disconnecttime'] != 0) continue; $ports[] = $row['connector']; $client['screens'][] = $row; } array_multisort($ports, SORT_ASC, $client['screens']); Permission::addGlobalTags($client['perms'], null, ['hardware.projectors.edit', 'hardware.projectors.view']); // Throw output at user Render::addTemplate('machine-main', $client); // Sessions $NOW = time(); $cutoff = $NOW - 86400 * 7; //if ($cutoff < $client['firstseen']) $cutoff = $client['firstseen']; $scale = 100 / ($NOW - $cutoff); $res = Database::simpleQuery('SELECT dateline, typeid, data FROM statistic' . " WHERE dateline > :cutoff AND typeid IN (:sessionLength, :offlineLength) AND machineuuid = :uuid ORDER BY dateline ASC", array( 'cutoff' => $cutoff - 86400 * 14, 'uuid' => $uuid, 'sessionLength' => Statistics::SESSION_LENGTH, 'offlineLength' => Statistics::OFFLINE_LENGTH, )); $spans['rows'] = array(); $spans['graph'] = ''; $last = false; $first = true; while ($row = $res->fetch(PDO::FETCH_ASSOC)) { if (!$client['isclient'] && $row['typeid'] === Statistics::SESSION_LENGTH) continue; // Don't differentiate between session and idle for non-clients if ($first && $row['dateline'] > $cutoff && $client['lastboot'] > $cutoff) { // Special case: offline before $spans['graph'] .= '