query($sql)->fetchColumn(0); } catch (PDOException $e){ // no pref table therefore Airtime is not installed. //We only get here if airtime database exists, but the table doesn't //This state sometimes happens if a previous Airtime uninstall couldn't remove //the database because it was busy, so it just removed the tables instead. return null; } //if version is empty string, then version is older than version 1.8.0 if ($version == '') { try { // If this table exists, then it's version 1.7.0 $sql = "SELECT * FROM cc_show_rebroadcast LIMIT 1"; $result = $con->query($sql)->fetchColumn(0); $version = "1.7.0"; } catch (Exception $e) { $version = null; } } return $version; } public static function DbTableExists($p_name) { $con = Propel::getConnection(); try { $sql = "SELECT * FROM ".$p_name." LIMIT 1"; $con->query($sql); } catch (PDOException $e){ return false; } return true; } public static function InstallQuery($sql, $verbose = true) { $con = Propel::getConnection(); try { $con->exec($sql); if ($verbose) { echo "done.\n"; } } catch (Exception $e) { echo "Error!\n".$e->getMessage()."\n"; echo " SQL statement was:\n"; echo " ".$sql."\n\n"; } } public static function DropSequence($p_sequenceName) { AirtimeInstall::InstallQuery("DROP SEQUENCE IF EXISTS $p_sequenceName"); } /** * Try to connect to the database. Return true on success, false on failure. * @param boolean $p_exitOnError * Exit the program on failure. * @return boolean */ public static function DbConnect($p_exitOnError = true) { global $CC_CONFIG; try { $con = Propel::getConnection(); } catch (Exception $e) { echo $e->getMessage().PHP_EOL; echo "Database connection problem.".PHP_EOL; echo "Check if database '{$CC_CONFIG['dsn']['database']}' exists". " with corresponding permissions.".PHP_EOL; if ($p_exitOnError) { exit(1); } return false; } return true; } /* TODO: This function should be moved to the media-monitor * install script. */ public static function InstallStorageDirectory() { global $CC_CONFIG; echo "* Storage directory setup".PHP_EOL; $ini = parse_ini_file(__DIR__."/airtime-install.ini"); $stor_dir = $ini["storage_dir"]; $dirs = array($stor_dir, $stor_dir."/organize"); foreach ($dirs as $dir){ if (!file_exists($dir)) { if (mkdir($dir, 02775, true)){ $rp = realpath($dir); echo "* Directory $rp created".PHP_EOL; } else { echo "* Failed creating {$dir}".PHP_EOL; exit(1); } } else if (is_writable($dir)) { $rp = realpath($dir); echo "* Skipping directory already exists: $rp".PHP_EOL; } else { $rp = realpath($dir); echo "* Error: Directory already exists, but is not writable: $rp".PHP_EOL; exit(1); } echo "* Giving Apache permission to access $rp".PHP_EOL; $success = chgrp($rp, $CC_CONFIG["webServerUser"]); $success = chmod($rp, 02775); } } public static function CreateDatabaseUser() { global $CC_CONFIG; echo " * Creating Airtime database user".PHP_EOL; $username = $CC_CONFIG['dsn']['username']; $password = $CC_CONFIG['dsn']['password']; $command = "echo \"CREATE USER $username ENCRYPTED PASSWORD '$password' LOGIN CREATEDB NOCREATEUSER;\" | su postgres -c psql 2>/dev/null"; @exec($command, $output, $results); if ($results == 0) { echo " * Database user '{$CC_CONFIG['dsn']['username']}' created.".PHP_EOL; } else { if (count($output) > 0) { echo " * Could not create user '{$CC_CONFIG['dsn']['username']}': ".PHP_EOL; echo implode(PHP_EOL, $output); } else { echo " * Database user '{$CC_CONFIG['dsn']['username']}' already exists.".PHP_EOL; } } } public static function CreateDatabase() { global $CC_CONFIG; echo " * Creating Airtime database".PHP_EOL; $database = $CC_CONFIG['dsn']['database']; $username = $CC_CONFIG['dsn']['username']; #$command = "echo \"CREATE DATABASE $database OWNER $username\" | su postgres -c psql 2>/dev/null"; $command = "su postgres -c \"createdb $database --encoding UTF8 --owner $username\""; @exec($command, $output, $results); if ($results == 0) { echo " * Database '{$CC_CONFIG['dsn']['database']}' created.".PHP_EOL; } else { if (count($output) > 0) { echo " * Could not create database '{$CC_CONFIG['dsn']['database']}': ".PHP_EOL; echo implode(PHP_EOL, $output); } else { echo " * Database '{$CC_CONFIG['dsn']['database']}' already exists.".PHP_EOL; } } $databaseExisted = ($results != 0); return $databaseExisted; } public static function InstallPostgresScriptingLanguage() { $con = Propel::getConnection(); // Install postgres scripting language $sql = 'SELECT COUNT(*) FROM pg_language WHERE lanname = \'plpgsql\''; $langIsInstalled = $con->query($sql)->fetchColumn(0); if ($langIsInstalled == '0') { echo " * Installing Postgres scripting language".PHP_EOL; $sql = "CREATE LANGUAGE 'plpgsql'"; AirtimeInstall::InstallQuery($sql, false); } else { echo " * Postgres scripting language already installed".PHP_EOL; } } public static function CreateDatabaseTables($p_dbuser, $p_dbpasswd, $p_dbname, $p_dbhost) { echo " * Creating database tables".PHP_EOL; // Put Propel sql files in Database //$command = AirtimeInstall::CONF_DIR_WWW."/library/propel/generator/bin/propel-gen ".AirtimeInstall::CONF_DIR_WWW."/build/ insert-sql 2>/dev/null"; $dir = self::GetAirtimeSrcDir()."/build/sql/"; $files = array("schema.sql", "sequences.sql", "views.sql", "triggers.sql", "defaultdata.sql"); foreach ($files as $f){ $command = "export PGPASSWORD=$p_dbpasswd && psql --username $p_dbuser --dbname $p_dbname --host $p_dbhost --file $dir$f 2>/dev/null"; @exec($command, $output, $results); } AirtimeInstall::$databaseTablesCreated = true; } public static function BypassMigrations($dir, $version) { $appDir = AirtimeInstall::GetAirtimeSrcDir(); $command = "php $appDir/library/doctrine/migrations/doctrine-migrations.phar ". "--configuration=$dir/../../DoctrineMigrations/migrations.xml ". "--db-configuration=$appDir/library/doctrine/migrations/migrations-db.php ". "--no-interaction --add migrations:version $version"; system($command); } public static function MigrateTablesToVersion($dir, $version) { $appDir = AirtimeInstall::GetAirtimeSrcDir(); $command = "php $appDir/library/doctrine/migrations/doctrine-migrations.phar ". "--configuration=$dir/../../DoctrineMigrations/migrations.xml ". "--db-configuration=$appDir/library/doctrine/migrations/migrations-db.php ". "--no-interaction migrations:migrate $version"; system($command); } public static function SetAirtimeVersion($p_version) { $con = Propel::getConnection(); $sql = "DELETE FROM cc_pref WHERE keystr = 'system_version'"; $con->exec($sql); $sql = "INSERT INTO cc_pref (keystr, valstr) VALUES ('system_version', '$p_version')"; $result = $con->exec($sql); if ($result < 1) { return false; } return true; } public static function SetUniqueId() { $con = Propel::getConnection(); $uniqueId = md5(uniqid("", true)); $sql = "INSERT INTO cc_pref (keystr, valstr) VALUES ('uniqueId', '$uniqueId')"; $result = $con->exec($sql); if ($result < 1) { return false; } return true; } public static function SetDefaultTimezone() { $con = Propel::getConnection(); $defaultTimezone = exec("cat /etc/timezone"); $sql = "INSERT INTO cc_pref (keystr, valstr) VALUES ('timezone', '$defaultTimezone')"; $result = $con->exec($sql); if ($result < 1) { return false; } return true; } public static function SetImportTimestamp() { $con = Propel::getConnection(); $sql = "INSERT INTO cc_pref (keystr, valstr) VALUES ('import_timestamp', '0')"; $result = $con->exec($sql); if ($result < 1) { return false; } return true; } public static function GetAirtimeVersion() { $con = Propel::getConnection(); $sql = "SELECT valstr FROM cc_pref WHERE keystr = 'system_version' LIMIT 1"; $version = $con->query($sql)->fetchColumn(0); return $version; } public static function DeleteFilesRecursive($p_path) { $command = "rm -rf \"$p_path\""; exec($command); } public static function CreateSymlinksToUtils() { echo "* Creating /usr/bin symlinks".PHP_EOL; AirtimeInstall::RemoveSymlinks(); echo "* Installing airtime-import".PHP_EOL; $dir = AirtimeInstall::CONF_DIR_BINARIES."/utils/airtime-import/airtime-import"; exec("ln -s $dir /usr/bin/airtime-import"); echo "* Installing airtime-update-db-settings".PHP_EOL; $dir = AirtimeInstall::CONF_DIR_BINARIES."/utils/airtime-update-db-settings"; exec("ln -s $dir /usr/bin/airtime-update-db-settings"); echo "* Installing airtime-check-system".PHP_EOL; $dir = AirtimeInstall::CONF_DIR_BINARIES."/utils/airtime-check-system"; exec("ln -s $dir /usr/bin/airtime-check-system"); echo "* Installing airtime-user".PHP_EOL; $dir = AirtimeInstall::CONF_DIR_BINARIES."/utils/airtime-user"; exec("ln -s $dir /usr/bin/airtime-user"); echo "* Installing airtime-log".PHP_EOL; $dir = AirtimeInstall::CONF_DIR_BINARIES."/utils/airtime-log"; exec("ln -s $dir /usr/bin/airtime-log"); } public static function RemoveSymlinks() { exec("rm -f /usr/bin/airtime-import"); exec("rm -f /usr/bin/airtime-update-db-settings"); exec("rm -f /usr/bin/airtime-check-system"); exec("rm -f /usr/bin/airtime-user"); exec("rm -f /usr/bin/airtime-log"); exec("rm -f /usr/bin/airtime-clean-storage"); } public static function InstallPhpCode() { global $CC_CONFIG; echo "* Installing PHP code to ".AirtimeInstall::CONF_DIR_WWW.PHP_EOL; exec("mkdir -p ".AirtimeInstall::CONF_DIR_WWW); exec("cp -R ".AirtimeInstall::GetAirtimeSrcDir()."/* ".AirtimeInstall::CONF_DIR_WWW); } public static function UninstallPhpCode() { echo "* Removing PHP code from ".AirtimeInstall::CONF_DIR_WWW.PHP_EOL; exec('rm -rf "'.AirtimeInstall::CONF_DIR_WWW.'"'); } public static function InstallBinaries() { echo "* Installing binaries to ".AirtimeInstall::CONF_DIR_BINARIES.PHP_EOL; exec("mkdir -p ".AirtimeInstall::CONF_DIR_BINARIES); exec("cp -R ".AirtimeInstall::GetUtilsSrcDir()." ".AirtimeInstall::CONF_DIR_BINARIES); } public static function UninstallBinaries() { echo "* Removing Airtime binaries from ".AirtimeInstall::CONF_DIR_BINARIES.PHP_EOL; exec('rm -rf "'.AirtimeInstall::CONF_DIR_BINARIES.'"'); } public static function DirCheck() { echo "Legend: \"+\" means the dir/file exists, \"-\" means that it does not.".PHP_EOL; $dirs = array(AirtimeInstall::CONF_DIR_BINARIES, AirtimeInstall::CONF_DIR_WWW, AirtimeIni::CONF_FILE_AIRTIME, AirtimeIni::CONF_FILE_LIQUIDSOAP, AirtimeIni::CONF_FILE_PYPO, AirtimeIni::CONF_FILE_RECORDER, "/usr/lib/airtime/pypo", "/var/log/airtime", "/var/log/airtime/pypo", "/var/tmp/airtime/pypo"); foreach ($dirs as $f) { if (file_exists($f)) { echo "+ $f".PHP_EOL; } else { echo "- $f".PHP_EOL; } } } public static function CreateZendPhpLogFile(){ global $CC_CONFIG; $path = AirtimeInstall::CONF_DIR_LOG; $file = $path.'/zendphp.log'; if (!file_exists($path)){ mkdir($path, 0755, true); } touch($file); chmod($file, 0644); chown($file, $CC_CONFIG['webServerUser']); chgrp($file, $CC_CONFIG['webServerUser']); } public static function RemoveLogDirectories(){ $path = AirtimeInstall::CONF_DIR_LOG; echo "* Removing logs directory ".$path.PHP_EOL; exec("rm -rf \"$path\""); } public static function CreateCronFile(){ echo "* Creating Cron File".PHP_EOL; // Create CRON task to run every day. Time of day is initialized to a random time. $hour = rand(0,23); $minute = rand(0,59); $fp = fopen('/etc/cron.d/airtime-crons','w'); fwrite($fp, "$minute $hour * * * root /usr/lib/airtime/utils/phone_home_stat\n"); fclose($fp); } public static function removeVirtualEnvDistributeFile(){ echo "* Removing distribute-0.6.10.tar.gz".PHP_EOL; if(file_exists('/usr/share/python-virtualenv/distribute-0.6.10.tar.gz')){ exec("rm -f /usr/share/python-virtualenv/distribute-0.6.10.tar.gz"); } } public static function printUsage($opts) { $msg = $opts->getUsageMessage(); echo PHP_EOL."Usage: airtime-install [options]"; echo substr($msg, strpos($msg, "\n")).PHP_EOL; } public static function getOpts() { try { $autoloader = Zend_Loader_Autoloader::getInstance(); $opts = new Zend_Console_Getopt( array( 'help|h' => 'Displays usage information.', 'overwrite|o' => 'Overwrite any existing config files.', 'preserve|p' => 'Keep any existing config files.', 'no-db|n' => 'Turn off database install.', 'reinstall|r' => 'Force a fresh install of this Airtime Version', 'webonly|w' => 'Install only web files' ) ); $opts->parse(); } catch (Zend_Console_Getopt_Exception $e) { print $e->getMessage() .PHP_EOL; AirtimeInstall::printUsage($opts); return NULL; } return $opts; } }