#!/usr/bin/php -q . // // Copyright 2006, Rob Thomas // Copyright 2009, Bandwith.com // require_once ("libfreepbx.install.php"); require_once(dirname(__FILE__) . '/amp_conf/htdocs/admin/libraries/php-upgrade.functions.php'); require_once(dirname(__FILE__) . '/amp_conf/htdocs/admin/libraries/sql.functions.php'); require_once(dirname(__FILE__) . '/amp_conf/htdocs/admin/libraries/utility.functions.php'); # constants define("AMP_CONF", "/etc/amportal.conf"); define("ASTERISK_CONF", "/etc/asterisk/asterisk.conf"); define("UPGRADE_DIR", dirname(__FILE__)."/upgrades"); define("MODULE_DIR", dirname(__FILE__)."/amp_conf/htdocs/admin/modules/"); # semi constants $webroot = "/var/www/html"; $fopwebroot = ""; // if blank, will use $webroot/panel $ampsbin_dir = "/usr/local/sbin"; // default if not set $ampbin_dir = "/var/lib/asterisk/bin"; $asterisk_user = "asteriskuser"; $asterisk_pass = "amp109"; /********************************************************************************************************************/ function showHelp() { out("Optional parameters:",false); out(" --help, -h, -? Show this help",false); out(" --dbhost Use a remote database server",false); out(" --dbname databasename Use database name specified, instead of 'asterisk'",false); out(" --username Use to connect to db and write config",false); out(" --password Use to connect to db and write config",false); out(" --fopwebroot Web path where fop will be installed",false); out(" --webroot Web root where FreePBX will be installed",false); out(" --cgibin Path where cgi-bin's lives",false); out(" --bin Path of asterisk binaries",false); out(" --sbin Path of system admin binaries",false); out(" --asteriskuser Asterisk Manager username",false); out(" --asteriskpass Asterisk Manager password",false); out(" --debug Enable debug output",false); out(" --dry-run Don't actually do anything",false); out(" --force-version Force upgrade from version ",false); out(" --skip-module-install Don't run install scripts for packaged modules, the files are still loaded.",false); out(" In a development environment you may not want the install scripts run.",false); out(" --no-files Just run updates without installing files",false); out(" --force-overwrite Don't ask if it is ok to overwrite modified files, assume yes for all.",false); out(" --install-moh Install default music-on-hold files (normally doesn't, unless ",false); out(" it's a new installation)",false); out(" --install-fop false Don't install FOP and don't display it anywhere on the interface",false); out(" --dev-links Make links to files in the source directory instead of copying",false); out(" (intended for developers only)",false); out(" --my-svn-is-correct Ignore Asterisk version, assume it is correct",false); out(" --engine Use the specified PBX Engine ('asterisk')",false); out(" --uid Set ownership of files to user",false); out(" --gid Set ownership of files to group",false); out(" --scripted Scripted install. Do not ask any questions.",false); out(" (Intended for unattended installers only)",false); } function install_parse_amportal_conf($filename) { $file = file($filename); foreach ($file as $line) { if (preg_match("/^\s*([a-zA-Z0-9]+)\s*=\s*(.*)\s*([;#].*)?/",$line,$matches)) { $conf[ $matches[1] ] = $matches[2]; } } // use same defaults as function.inc.php if ( !isset($conf["AMPDBENGINE"]) || ($conf["AMPDBENGINE"] == "")) { $conf["AMPDBENGINE"] = "mysql"; } if ( !isset($conf["AMPDBNAME"]) || ($conf["AMPDBNAME"] == "")) { $conf["AMPDBNAME"] = "asterisk"; } if ( !isset($conf["AMPENGINE"]) || ($conf["AMPENGINE"] == "")) { $conf["AMPENGINE"] = "asterisk"; } return $conf; } function install_parse_asterisk_conf($filename) { $file = file($filename); foreach ($file as $line) { if (preg_match("/^\s*([a-zA-Z0-9]+)\s* => \s*(.*)\s*([;#].*)?/",$line,$matches)) { $conf[ $matches[1] ] = $matches[2]; } } // Now set defaults if not set (although asterisk should fail if not set but at least // it will get the setup somewhat right // if (!isset($asterisk_conf['astetcdir'])) { $asterisk_conf['astetcdir'] = "/etc/asterisk"; } if (!isset($asterisk_conf['astmoddir'])) { $asterisk_conf['astmoddir'] = "/usr/lib/asterisk/modules"; } if (!isset($asterisk_conf['astvarlibdir'])) { $asterisk_conf['astvarlibdir'] = "/var/lib/asterisk"; } if (!isset($asterisk_conf['astagidir'])) { $asterisk_conf['astagidir'] = "/var/lib/asterisk/agi-bin"; } if (!isset($asterisk_conf['astspooldir'])) { $asterisk_conf['astspooldir'] = "/var/spool/asterisk"; } if (!isset($asterisk_conf['astrundir'])) { $asterisk_conf['astrundir'] = "/var/run/asterisk"; } if (!isset($asterisk_conf['astlogdir'])) { $asterisk_conf['astlogdir'] = "/var/log/asterisk"; } return $conf; } function write_amportal_conf($filename, $conf) { $file = file($filename); // parse through the file foreach (array_keys($file) as $key) { if (preg_match("/^\s*([a-zA-Z0-9]+)\s*=\s*(.*)\s*([;#].*)?/",$file[$key],$matches)) { // this is an option=value line if (isset($conf[ $matches[1] ])) { // rewrite the line, if we have this in $conf $file[$key] = $matches[1]."=".$conf[ $matches[1] ]."\n"; // unset it so we know what's new unset($conf[ $matches[1] ]); } } } // add new entries foreach ($conf as $key=>$val) { $file[] = $key."=".$val."\n"; } // write the file if (!$fd = fopen($filename, "w")) { fatal("Could not open ".$filename." for writing"); } fwrite($fd, implode("",$file)); fclose($fd); } function ask_overwrite($file1, $file2) { global $check_md5s; do { out($file2." has been changed from the original version."); outn("Overwrite (y=yes/a=all/n=no/d=diff/s=shell/x=exit)? "); $key = fgets(STDIN,1024); switch (strtolower($key[0])) { case "y": return true; case "a": $check_md5s=false; return true; case "n": return false; case "d": out(""); // w = ignore whitespace, u = unified passthru("diff -wu ".escapeshellarg($file2)." ".escapeshellarg($file1)); break; case "s": if (function_exists("pcntl_fork")) { out(""); $shell = (isset($_ENV["SHELL"]) ? $_ENV["SHELL"] : "/bin/bash"); out("Dropping to shell. Type 'exit' to return"); out("-> Original file: ".$file2); out("-> New file: ".$file1); $pid = pcntl_fork(); if ($pid == -1) { out("[ERROR] cannot fork"); } else if ($pid) { // parent pcntl_waitpid($pid, $status); // we wait till the child exits/dies/whatever } else { pcntl_exec($shell, array(), $_ENV); } out("Returned from shell"); } else { out("[ERROR] PHP not built with process control (--enable-pcntl) support: cannot spawn shell"); } break; case "x": out("-> Original file: ".$file2); out("-> New file: ".$file1); out("Exiting install program."); exit(1); break; } out(""); } while(1); } /** Write AMP-generated configuration files */ function generate_configs() { global $amp_conf; global $dryrun; global $debug; global $runas_uid; out("Generating Configurations.conf, (if Asterisk is not running, you will get an error"); out("In case of error, start Asterisk and hit the red bar in the GUI to generate the Configurations.conf files"); if (!$dryrun) // added --run-install to make it work like it has been working since retrieve_conf changed to not run module install scripts by default // // TODO: Should check if Asterisk is running and/or try to start it. // passthru("sudo -u $runas_uid ".trim($amp_conf["AMPBIN"])."/retrieve_conf --run-install --skip-registry-checks ".($debug ? ' --debug' : '')); } /** Collect AMP settings */ function collect_settings($filename, $dbhost = '', $dbuser = '', $dbpass = '', $dbname = 'asterisk') { global $webroot; global $fopwebroot; global $ampsbin_dir; global $ampbin_dir; global $asterisk_user; global $asterisk_pass; global $scripted; global $freepbxip; global $asteriskip; global $runas_uid; global $runas_gid; out("Creating new $filename"); if ($scripted == true) { # Scripted install. Everything should have been set for us, don't ask questions. out("Scripted install. Accepting command line params."); $amp_conf["AMPDBUSER"] = $dbuser; $amp_conf["AMPDBPASS"] = $dbpass; $amp_conf["AMPDBHOST"] = $dbhost; $amp_conf["AMPDBNAME"] = $dbname; $amp_conf["AMPMGRUSER"] = "admin"; $amp_conf["AMPMGRPASS"] = "unset"; $amp_conf["AMPWEBROOT"] = $webroot; $amp_conf["FOPWEBROOT"] = ($fopwebroot ? $fopwebroot : $webroot."/panel"); $amp_conf["AMPWEBADDRESS"] = $freepbxip; $amp_conf["ASTMANAGERHOST"] = $asteriskip; $amp_conf["FOPPASSWORD"] = "passw0rd"; $amp_conf["AMPEXTENSIONS"] = "extensions"; $amp_conf["AMPBIN"] = $ampbin_dir; $amp_conf["AMPSBIN"] = "$ampsbin_dir"; $amp_conf["AMPASTERISKWEBUSER"] = $runas_uid; $amp_conf["AMPASTERISKWEBGROUP"] = $runas_gid; $amp_conf["AMPASTERISKUSER"] = $runas_uid; $amp_conf["AMPASTERISKGROUP"] = $runas_gid; $amp_conf["AMPDEVUSER"] = $runas_uid; $amp_conf["AMPDEVGROUP"] = $runas_gid; write_amportal_conf($filename, $amp_conf); outn(AMP_CONF." written"); return; } outn("Enter your USERNAME to connect to the '$dbname' database:\n [".($dbuser ? $dbuser : $asterisk_user) . "] "); $key = trim(fgets(STDIN,1024)); if (preg_match('/^$/',$key)) $amp_conf["AMPDBUSER"] = ($dbuser ? $dbuser : $asterisk_user); else $amp_conf["AMPDBUSER"] = $key; outn("Enter your PASSWORD to connect to the '$dbname' database:\n [".($dbpass ? $dbpass : $asterisk_pass)."] "); $key = trim(fgets(STDIN,1024)); if (preg_match('/^$/',$key)) $amp_conf["AMPDBPASS"] = ($dbpass ? $dbpass : $asterisk_pass); else $amp_conf["AMPDBPASS"] = $key; outn("Enter the hostname of the '$dbname' database:\n [".($dbhost ? $dbhost : "localhost")."] "); $key = trim(fgets(STDIN,1024)); if (preg_match('/^$/',$key)) $amp_conf["AMPDBHOST"] = ($dbhost ? $dbhost : "localhost"); else $amp_conf["AMPDBHOST"] = $key; outn("Enter a USERNAME to connect to the Asterisk Manager interface:\n [admin] "); $key = trim(fgets(STDIN,1024)); if (preg_match('/^$/',$key)) $amp_conf["AMPMGRUSER"] = "admin"; else $amp_conf["AMPMGRUSER"] = $key; outn("Enter a PASSWORD to connect to the Asterisk Manager interface:\n [amp111] "); $key = trim(fgets(STDIN,1024)); if (preg_match('/^$/',$key)) $amp_conf["AMPMGRPASS"] = "amp111"; else $amp_conf["AMPMGRPASS"] = $key; do { out("Enter the path to use for your AMP web root:\n [$webroot] "); $key = trim(fgets(STDIN,1024)); if (preg_match('/^$/',$key)) $amp_conf["AMPWEBROOT"] = "$webroot"; else $amp_conf["AMPWEBROOT"] = rtrim($key,'/'); if (is_dir($amp_conf["AMPWEBROOT"])) { break; } else if (amp_mkdir($amp_conf["AMPWEBROOT"],"0755",true)){ out("Created ".$amp_conf["AMPWEBROOT"]); break; } else { fatal("Cannot create ".$amp_conf["AMPWEBROOT"]."!"); } } while(1); // Really no need to ask, is there. if (empty($fopwebroot)) $amp_conf["FOPWEBROOT"] = $amp_conf["AMPWEBROOT"]."/panel"; else $amp_conf["FOPWEBROOT"] = $fopwebroot; outn("Enter the IP ADDRESS or hostname used to access the AMP web-admin:\n [$freepbxip] "); $key = trim(fgets(STDIN,1024)); if (preg_match('/^$/',$key)) $amp_conf["AMPWEBADDRESS"] = $freepbxip; else $amp_conf["AMPWEBADDRESS"] = $key; outn("Enter a PASSWORD to perform call transfers with the Flash Operator Panel:\n [passw0rd] "); $key = trim(fgets(STDIN,1024)); if (preg_match('/^$/',$key)) $amp_conf["FOPPASSWORD"] = "passw0rd"; else $amp_conf["FOPPASSWORD"] = $key; outn("Use simple Extensions [extensions] admin or separate Devices and Users [deviceanduser]?\n [extensions] "); $key = trim(fgets(STDIN,1024)); if (preg_match('/^$/',$key)) $amp_conf["AMPEXTENSIONS"] = "extensions"; else $amp_conf["AMPEXTENSIONS"] = $key; do { out("Enter directory in which to store AMP executable scripts:\n [$ampbin_dir] "); $key = trim(fgets(STDIN,1024)); if (preg_match('/^$/',$key)) $amp_conf["AMPBIN"] = $ampbin_dir; else $amp_conf["AMPBIN"] = rtrim($key,'/'); if (is_dir($amp_conf["AMPBIN"])) { break; } else if (amp_mkdir($amp_conf["AMPBIN"],"0755",true)){ out("Created ".$amp_conf["AMPBIN"]); break; } else { fatal("Cannot create ".$amp_conf["AMPBIN"]."!"); } } while(1); do { out("Enter directory in which to store super-user scripts:\n [$ampsbin_dir] "); $key = trim(fgets(STDIN,1024)); if (preg_match('/^$/',$key)) $amp_conf["AMPSBIN"] = "$ampsbin_dir"; else $amp_conf["AMPSBIN"] = rtrim($key,'/'); if (is_dir($amp_conf["AMPSBIN"])) { break; } else if (amp_mkdir($amp_conf["AMPSBIN"],"0755",true)){ out("Created ".$amp_conf["AMPSBIN"]); break; } else { fatal("Cannot create ".$amp_conf["AMPSBIN"]."!"); } } while(1); // write amportal.conf write_amportal_conf($filename, $amp_conf); outn(AMP_CONF." written"); } /** Set base of packaged modules to the versions packaged in the tarball since they are * getting overwritten with the tarball from anything that may have been updated online. * */ function set_base_version() { global $dryrun; // read modules list from MODULE_DIR // $included_modules = array(); $dir = opendir(MODULE_DIR); while ($file = readdir($dir)) { if ($file[0] != "." && $file[0] != "_" && is_dir(MODULE_DIR."/".$file)) { $included_modules[] = $file; } } closedir($dir); foreach ($included_modules as $up_module) { outn("Checking $up_module.. "); if (!$dryrun) { out(set_module_version($up_module)); } else { out("Dry Run Not Updated"); } } } /** Install all modules packaged with the install. We use the force flag because the * the assumption is that the dependencies are met and the package is able to have * the modules installed. */ function install_modules() { global $dryrun; global $amp_conf; // read modules list from MODULE_DIR // $included_modules = array(); $dir = opendir(MODULE_DIR); while ($file = readdir($dir)) { if ($file[0] != "." && $file[0] != "_" && is_dir(MODULE_DIR."/".$file)) { $included_modules[] = $file; } } closedir($dir); $output = array(); $keep_checking = true; $num_modules = false; while ($keep_checking && count($included_modules)) { if ($num_modules === count($included_modules)) { $keep_checking = false; } else { $num_modules = count($included_modules); } foreach ($included_modules as $id => $up_module) { outn("Checking $up_module.. "); if (!$dryrun) { // if $keep_checking then check dependencies first and skip if not met // otherwise we will install anyhow even if some dependencies are not met // since it is included. (TODO: should we not?) // if ($keep_checking) { exec($amp_conf['AMPBIN']."/module_admin --no-warnings checkdepends $up_module",$output,$retval); unset($output); if ($retval) { out("dependencies pending"); continue; } } // Framework modules cannot be enabled, only installed. // switch ($up_module) { case 'framework': case 'fw_ari': case 'fw_fop': system($amp_conf['AMPBIN']."/module_admin --no-warnings -f install $up_module"); out("installed"); break; default: system($amp_conf['AMPBIN']."/module_admin --no-warnings -f install $up_module"); system($amp_conf['AMPBIN']."/module_admin --no-warnings -f enable $up_module"); out("installed"); } unset($included_modules[$id]); } else { out("Dry Run Not Installed"); } } } } /** Set the module version number to the packaged version and enable * module must require not install.php or install.sql script * this is primarily to package core and framework with FreePBX tarballs * */ function set_module_version($module) { global $db; $module_dir = MODULE_DIR; $file_path = $module_dir.$module."/module.xml"; if (file_exists($file_path)) { // TODO: this is bad, there are other version tags (depends on) but this // is equivalnet to what publish.pl does, so it expects this to be // at the top. // $module_xml = file_get_contents($file_path); if (preg_match('/(.+)<\/version>/', $module_xml, $matches)) { $version = $matches[1]; } else { fatal("ERROR: $file_path found but no version information"); } } else { return "not packaged, no updating needed"; } // If we didn't return above, then we found the package as part of the install // tarball and want to update the version info since this might be overwriting // an existing install that has a newer version. // $sql = "SELECT version FROM modules WHERE modulename = '$module'"; $result = $db->getCol($sql); if(DB::IsError($result)) { fatal("error accessing version table: ".$result->getMessage()); } $sql = ""; if (count($result) == 0) { // insert but disable as we have to first run install scripts which come later $sql = "INSERT INTO modules (modulename, version, enabled) VALUES ('$module', '$version', 0)"; } else if ($result[0] != $version) { if (version_compare_freepbx($version, $result[0], "gt")) { // if new version is greater than old, then we disable the module and it will get enabled next when installed // $sql = "UPDATE modules SET version = '$version', enabled = 0 WHERE modulename = '$module'"; } else { // if new version is equal to or less than old, then we leave it in the enable/disable state it was in but just // reset the version number. // $sql = "UPDATE modules SET version = '$version' WHERE modulename = '$module'"; } } if ($sql) { debug($sql); $result = $db->query($sql); if(DB::IsError($result)) { fatal("error writing to version table: ".$result->getMessage()); } return "updated to $version"; } else { return "already at $version"; } } /********************************************************************************************************************/ // // TODO: will this work, basically using bootstrap once installed if using to upgrade, etc? /* $bootstrap_settings['skip_astman']) = true; $bootstrap_settings['freepbx_auth'] = false; $restrict_mods = true; if (@include_once(getenv('FREEPBX_CONF') ? getenv('FREEPBX_CONF') : '/etc/freepbx.conf')) { out(_("FreePBX already installed, bootstrapping")); } else if (@include_once('/etc/asterisk/freepbx.conf')) { out(_("FreePBX already installed, bootstrapping")); } else { // all the initialization here instead } */ // **** Make sure we have STDIN etc // from ben-php dot net at efros dot com at php.net/install.unix.commandline if (version_compare(phpversion(),'4.3.0','<') || !defined("STDIN")) { define('STDIN',fopen("php://stdin","r")); define('STDOUT',fopen("php://stdout","r")); define('STDERR',fopen("php://stderr","r")); register_shutdown_function( create_function( '' , 'fclose(STDIN); fclose(STDOUT); fclose(STDERR); return true;' ) ); } // **** Make sure we have PEAR's DB.php, and include it outn("Checking for PEAR DB.."); if (! @ include('DB.php')) { out("FAILED"); fatal("PEAR must be installed (requires DB.php). Include path: ".ini_get("include_path")); } out("OK"); // **** Make sure we have PEAR's GetOpts.php, and include it outn("Checking for PEAR Console::Getopt.."); if (! @ include("Console/Getopt.php")) { out("FAILED"); fatal("PEAR must be installed (requires Console/Getopt.php). Include path: ".ini_get("include_path")); } out("OK"); // **** Parse out command-line options $shortopts = "h?u:p:"; $longopts = array("help","debug","dry-run","username=","password=","force-version=","dbhost=","no-files","force-overwrite","dbname=","my-svn-is-correct","engine=","webroot=","install-moh","install-fop=","make-links-devel","dev-links","skip-module-install","uid=","gid=","scripted","freepbxip=","asteriskip="); $args = Console_Getopt::getopt(Console_Getopt::readPHPArgv(), $shortopts, $longopts); if (is_object($args)) { // assume it's PEAR_ERROR out($args->message); exit(255); } $debug = false; $dryrun = false; $install_files = true; $override_astvers = false; $scripted = false; $install_moh = false; $install_fop = true; $make_links = false; $module_install = true; //initialize variables to avoid php notices $dbhost = null; $dbname = 'asterisk'; $new_username = null; $new_password = null; $runas_uid = "asterisk"; $runas_gid = "asterisk"; $freepbxip = "192.168.1.1"; $asteriskip = "localhost"; foreach ($args[0] as $arg) { switch ($arg[0]) { case "--help": case "h": case "?": showHelp(); exit(10); break; case "--dry-run": out("Dry-run only, nothing will be changed"); $dryrun = true; break; case "--debug": $debug = true; debug("Debug mode enabled"); break; case "--username": case "u": out("Using username: ".$arg[1]); $new_username = $arg[1]; break; case "--password": case "p": out("Using password: ".str_repeat("*",strlen($arg[1]))); $new_password = $arg[1]; break; case "--force-version": $version = $arg[1]; out("Forcing upgrade from version ".$version); break; case "--dbhost": $dbhost = $arg[1]; out("Using remote database server at ".$dbhost); break; case "--dbname": $dbname = $arg[1]; out("Using database ".$dbname); break; case "--no-files": $install_files = false; out("Running upgrade only, without installing files."); break; case "--force-overwrite": $check_md5s = false; out("Overwriting all files including modified ones."); break; case "--my-svn-is-correct": $override_astvers = true; break; case "--engine": if ($arg[1] != 'asterisk') { fatal('Currently only "asterisk" is supported as a PBX engine'); } $pbx_engine = $arg[1]; break; case "--install-moh": $install_moh = true; break; case "--install-fop": if(strtolower($arg[1]) == "false") { $install_fop = false; out("FOP will be deactivated in the interface. Set FOPDISABLE=false in Advanced Settings to change later."); } else { out("FOP will be installed and activated."); } break; case "--make-links-devel": case "--dev-links": $make_links = true; break; case "--skip-module-install": $module_install = false; break; case "--fopwebroot": $fopwebroot = $arg[1]; out("Using fop at ".$fopwebroot); break; case "--webroot": $webroot = $arg[1]; out("Using Webroot at ".$webroot); break; case "--cgibin": $cgibin = $arg[1]; out("Using CGI-BIN at ".$cgibin); break; case "--bin": $ampbin_dir = $arg[1]; out("Using bin at ".$ampbin_dir); break; case "--sbin": $ampsbin_dir = $arg[1]; out("Using sbin at ".$ampsbin_dir); break; case "--asteriskuser": $asterisk_user = $arg[1]; out("Using Asterisk user ".$asterisk_user); break; case "--asteriskpass": $asterisk_pass = $arg[1]; out("Using asteriskpass ".str_repeat("*",strlen($arg[1]))); break; case "--uid": $runas_uid = $arg[1]; out("Setting ownership (user) to ".$runas_uid); break; case "--gid": $runas_gid = $arg[1]; out("Setting ownership (group) to ".$runas_gid); break; case "--scripted": $scripted = true; out("Unattended installation. No questions will be asked"); break; case "--freepbxip": $freepbxip = $arg[1]; out("Setting IP address of web interface to $freepbxip"); break; case "--asteriskip": $asteriskip = $arg[1]; out("Setting IP address of asterisk to $asteriskip"); break; } } // **** Look for user = root // TODO: if we bootstrap, do this first before even trying. Also, is their a problem boostraping as user root??? // outn("Checking user.."); //$current_user=(isset($_ENV["USER"]) ? $_ENV["USER"] : exec('whoami',$output)); $euid = (posix_getpwuid(posix_geteuid())); $current_user = $euid['name']; if ($current_user != "root"){ out("FAILED"); fatal($argv[0]." must be run as root"); } out("OK"); // TODO: if we bootstrap, do this first before even trying. // outn("Checking if Asterisk is running.."); exec("pidof asterisk", $pid_val, $ret); if ($ret) { out("FAILED"); fatal($argv[0]."\n\tAsterisk must be running. If this is a first time install, you should start\n\tAsterisk by typing './start_asterisk start'\n\tFor upgrading, you should run 'amportal start'"); } out("running with PID: ".$pid_val[0]."..OK"); // **** Check for amportal.conf, create if necessary outn("Checking for ".AMP_CONF.".."); if (!file_exists(AMP_CONF)) { out(AMP_CONF." does not exist, copying default"); copy("amportal.conf", AMP_CONF); // this file contains password and should not be a+r // this addresses http://freepbx.org/trac/ticket/1878 chown(AMP_CONF, $runas_uid); chgrp(AMP_CONF, $runas_gid); chmod(AMP_CONF, 0640); collect_settings(AMP_CONF, $dbhost, $new_username, $new_password, $dbname); out("Assuming new install, --install-moh added to command line"); $install_moh = true; } out("OK"); // **** read amportal.conf // TODO: see comments above, have we already boostraped, if so, skip this? // outn("Reading ".AMP_CONF.".."); $amp_conf = install_parse_amportal_conf(AMP_CONF); if (count($amp_conf) == 0) { fatal("FAILED"); } out("OK"); // TODO: if we boostrapped I think we can count on ALL of these being set but maybe it's // fine to do a sanity check? // // Ensure our "critical" variables are set. We absolutely need these to copy in files. if (!array_key_exists("AMPWEBROOT",$amp_conf)) { out("Adding AMPWEBROOT option to amportal.conf - using AMP default"); $amp_conf["AMPWEBROOT"] = "/var/www/html"; } if (!array_key_exists("FOPWEBROOT",$amp_conf)) { out("Adding FOPWEBROOT option to amportal.conf - using AMP default"); $amp_conf["FOPWEBROOT"] = $amp_conf["AMPWEBROOT"]."/panel"; } if (!array_key_exists("AMPBIN",$amp_conf)) { out("Adding AMPBIN option to amportal.conf - using AMP default"); $amp_conf["AMPBIN"] = "/var/lib/asterisk/bin"; } if (!array_key_exists("AMPSBIN",$amp_conf)) { out("Adding AMPSBIN option to amportal.conf - using AMP default"); $amp_conf["AMPSBIN"] = "/usr/sbin"; } if (!array_key_exists("AMPDBENGINE",$amp_conf)) { out("Adding AMPDBENGINE option to amportal.conf - using AMP default"); $amp_conf["AMPDBENGINE"] = "mysql"; } if (!array_key_exists("AMPDBNAME",$amp_conf)) { out("Adding AMPDBNAME option to amportal.conf - using AMP default"); $amp_conf["AMPDBNAME"] = "asterisk"; } // TODO: if we boostrapped do we ignore these? (Can they even be set?) // if (isset($new_username)) { $amp_conf["AMPDBUSER"] = $new_username; } if (isset($new_password)) { $amp_conf["AMPDBPASS"] = $new_password; } if (isset($dbhost)) { $amp_conf["AMPDBHOST"] = $dbhost; } if (isset($dbname)) { $amp_conf["AMPDBNAME"] = $dbname; } if(!$install_fop) { // Set from --install-fop parameter; Add it to amportal.conf out("Adding FOPDISABLE option to amportal.conf"); $amp_conf["FOPDISABLE"] = "true"; } // If they pre-set this in their amportal.conf or this is an upgrade, we should honor it as well // // TODO: if we boostrap, then this value could be normalized (1/0 I think?) // if (isset($amp_conf['FOPDISABLE']) && (strtolower(trim($amp_conf['FOPDISABLE'])) == 'true' || strtolower(trim($amp_conf['FOPDISABLE'])) == 'yes' || strtolower(trim($amp_conf['FOPDISABLE'])) == 'y') ) { $install_fop = false; } // write amportal.conf // TODO: if we boostrapped we don't want to write amportal.conf, or do we? e.g. if we are running out of the file vs. the // database then we probably want to write, though there should be a freepbx_conf class to use that does that and knows // how to make that decsion as well as what to write? // write_amportal_conf(AMP_CONF, $amp_conf); // **** Check for amportal.conf, create if necessary outn("Checking for ".ASTERISK_CONF.".."); if (!file_exists(ASTERISK_CONF)) { out(ASTERISK_CONF." does not exist, copying default"); copy("asterisk.conf", ASTERISK_CONF); } out("OK"); // **** read asterisk.conf // TODO: if we boostrapped don't do this // outn("Reading ".ASTERISK_CONF.".."); $asterisk_conf = install_parse_asterisk_conf(ASTERISK_CONF); if (count($asterisk_conf) == 0) { fatal("FAILED. Have you installed Asterisk?"); } out("OK"); /* TODO: if we boostrapped this should have been done but doesn't hurt? */ if (isset($asterisk_conf['astetcdir'])) { $amp_conf['ASTETCDIR'] = $asterisk_conf['astetcdir']; } if (isset($asterisk_conf['astmoddir'])) { $amp_conf['ASTMODDIR'] = $asterisk_conf['astmoddir']; } if (isset($asterisk_conf['astvarlibdir'])) { $amp_conf['ASTVARLIBDIR'] = $asterisk_conf['astvarlibdir']; } if (isset($asterisk_conf['astagidir'])) { $amp_conf['ASTAGIDIR'] = $asterisk_conf['astagidir']; } if (isset($asterisk_conf['astspooldir'])) { $amp_conf['ASTSPOOLDIR'] = $asterisk_conf['astspooldir']; } if (isset($asterisk_conf['astrundir'])) { $amp_conf['ASTRUNDIR'] = $asterisk_conf['astrundir']; } if (isset($asterisk_conf['astlogdir'])) { $amp_conf['ASTLOGDIR'] = $asterisk_conf['astlogdir']; } if (!isset($pbx_engine)) { $pbx_engine='asterisk'; } out("Using $pbx_engine as PBX Engine"); $amp_conf["AMPENGINE"]=$pbx_engine; // TODO: I guess we have new variables set, of course see note above if we boostrapped. Probably // this one stays? // write_amportal_conf(AMP_CONF, $amp_conf); // **** Write asterisk version to ASTETCDIR/version // TODO: does anything use this? What's the point? (other than we need the version for below) // $tmpoutput = ''; $tmpout = exec("asterisk -V", $tmpoutput, $exitcode); if ($exitcode != 0) { fatal("Error executing asterisk: be sure Asterisk is installed and in the path"); } if (!$fd = fopen($amp_conf['ASTETCDIR'].'/version','w')) { fatal('Cannot open '.$amp_conf['ASTETCDIR'].'/version for writing'); } fwrite($fd, $tmpout); fclose($fd); // change to read-only chmod($amp_conf['ASTETCDIR'].'/version',0444); // normally this would be the contents of ASTETCDIR/version, but this is for simplicity, as we just read it above $verinfo = $tmpout; // **** Check asterisk version // Set the 'engine' to be 'asterisk14' if using asterisk 1.4, otherwise // 'asterisk' outn("Checking for Asterisk version.."); if ((preg_match('/^Asterisk (\d+(\.\d+)*)(-?(.*))$/', $verinfo, $matches)) || (preg_match('/^Asterisk SVN-(\d+(\.\d+)*)(-?(.*))$/', $verinfo, $matches))) { if ((version_compare($matches[1], "1.2") < 0)) { fatal("Asterisk 1.2, 1.4, 1.6, or 1.8 is required for this version of FreePBX. Detected version is: ".$matches[1]); } if (version_compare($matches[1], "1.9", "ge")) { fatal("Asterisk 1.2, 1.4, 1.6, or 1.8 is required for this version of FreePBX. Detected version is: ".$matches[1]); } out("{$matches[1]}"); $asterisk_version = $matches[1]; } elseif (preg_match('/^Asterisk ([ABC]\.\d+(\.\d+)*)(-?(.*))$/', $verinfo, $matches)) { if (substr($matches[1], 0, 1) == "A") { fatal("Asterisk Business Edition B or C is required for this version of FreePBX. Detected version is: ".$matches[1]); } out("{$matches[1]}"); $asterisk_version = '1.4'; //Not really, but this makes sure that proper execution occurs later on reload commands, etc. } elseif ($asterisk_version = preg_match('/^Asterisk SVN.+/', $verinfo)) { out("FAIL"); out("*** WARNING ***"); out("You are not using a released version of Asterisk. We are unable to verify"); out("that your Asterisk version is compatible with FreePBX. Whilst this probably"); out("won't cause any problems, YOU NEED TO BE CERTAIN that it is compatible"); out("with at least the released Asterisk version 1.2" ); if ($override_astvers==false) { out("If you are SURE that this is compatible, you can re-run ".$argv[0]." with"); out("the parameter --my-svn-is-correct"); exit; } else { out("--my-svn-is-correct specified, continuing"); } } else { fatal("Could not determine asterisk version (got: \"".$verinfo."\" please report this)"); } // **** Make sure selinux isn't enabled outn("Checking for selinux.."); $tmpoutput = array(); $tmpout = exec("getenforce 2>/dev/null", $tmpoutput, $sereturn); if (strtolower($tmpoutput[0]) === "enabled") { // this method seems better because disabled and permissive are the same // if a user installs and realizes selinux is running the other method // requires a reboot to get selinuxenabled to work after editing the selinux config // this will allow you to use setenforce 0 which turns selinux into permissive mode which // doesnt enforce, it just warns. fatal("selinux is ENABLED. This is not supported. Please disable selinux before using FreePBX"); } out("OK"); // **** Connect to database // TODO: if we bootstrapped, we are already connected and this can all be skipped // outn("Connecting to database.."); $db_engine = $amp_conf["AMPDBENGINE"]; if ($db_engine != "sqlite3") { $db_user = $amp_conf["AMPDBUSER"]; $db_pass = $amp_conf["AMPDBPASS"]; $db_host = $amp_conf["AMPDBHOST"]; } $db_name = $amp_conf["AMPDBNAME"]; // we still support older configurations, and fall back // into mysql when no other engine is defined if ($db_engine == "") { $db_engine = "mysql"; } switch ($db_engine) { case "pgsql": case "mysql": // datasource in in this style: dbengine://username:password@host/database if (!function_exists($db_engine.'_connect')) { out("FAILED"); fatal($db_engine." PHP libraries not installed"); } $datasource = $db_engine.'://'.$db_user.':'.$db_pass.'@'.$db_host.'/'.$db_name; $db = DB::connect($datasource); // attempt connection break; case "sqlite": die_freepbx("SQLite2 support is deprecated. Please use sqlite3 only."); break; case "sqlite3": if (!isset($amp_conf["AMPDBFILE"])) die("You must setup properly AMPDBFILE in /etc/amportal.conf"); if (isset($amp_conf["AMPDBFILE"]) == "") die("AMPDBFILE in /etc/amportal.conf cannot be blank"); /* on centos this extension is not loaded by default */ if (! extension_loaded('sqlite3.so') && ! extension_loaded('SQLITE3')) dl('sqlite3.so'); if (! @require_once('DB/sqlite3.php') ) { out("FAILED"); fatal( "Your PHP installation has no PEAR/SQLite3 support. Please install php-sqlite3 and php-pear."); } $datasource = "sqlite3:///" . $amp_conf["AMPDBFILE"] . "?mode=0666"; $db = DB::connect($datasource); break; default: die( "Unknown SQL engine: [$db_engine]"); } if(DB::IsError($db)) { out("FAILED"); debug($db->userinfo); out("Try running ".$argv[0]." --username=user --password=pass (using your own user and pass)"); fatal("Cannot connect to database"); } out("OK"); // **** Read DB for version info if (!isset($version)) { outn("Checking current version of AMP.."); $version = install_getversion(); if (!$version) { out("no version information"); out("Assuming new installation"); } else { out($version); } } // Check if freepbx_settings is there and has been initialized // if it has anything less than about 5 settings in it (and that // is probably quite low) then something is wrong so assume it // is not there. // $sql = "SELECT count(*) FROM freepbx_settings"; $num_settings = $db->getOne($sql); $force_amportal_conf = DB::IsError($num_settings) || $num_settings < 5; // **** Copy files if ($install_files) { outn("Installing new FreePBX files.."); $check_md5s=true; $md5sums = read_md5_file(UPGRADE_DIR."/".$version.".md5"); list($num_files, $num_copied) = recursive_copy("amp_conf", "", $md5sums); if (!is_file("/etc/asterisk/voicemail.conf")) copy("/etc/asterisk/voicemail.conf.template","/etc/asterisk/voicemail.conf"); if (!is_dir("/var/spool/asterisk/voicemail/device")) amp_mkdir("/var/spool/asterisk/voicemail/device", "0755", true); out("OK (".$num_copied." files copied, ".($num_files-$num_copied)." skipped)"); // link the packed js library for ARI, if there the error will indicate that $libfreepbx = $amp_conf['AMPWEBROOT'].'/admin/common/libfreepbx.javascripts.js'; $dest_libfreepbx = $amp_conf['AMPWEBROOT'].'/recordings/theme/js/libfreepbx.javascripts.js'; if (!file_exists($amp_conf['AMPWEBROOT'].'/recordings/theme/js')) { mkdir($amp_conf['AMPWEBROOT'].'/recordings/theme/js',0755, true); } if (file_exists($libfreepbx) && !file_exists($dest_libfreepbx)) { outn(_("linking libfreepbx.javascripts.js to theme/js..")); if (link($libfreepbx, $dest_libfreepbx)) { out(_("ok")); } else { out(_("possible error - check warning message")); } } } // **** Apply amportal.conf configuration to files if (file_exists(dirname(__FILE__)."/apply_conf.sh")) { debug("Running ".dirname(__FILE__)."/apply_conf.sh"); } // Ensure executables are executable chmod($amp_conf["AMPBIN"]."/freepbx_setting", 0755); outn("Configuring install for your environment.."); exec($amp_conf["AMPBIN"]."/freepbx_setting AMPASTERISKWEBGROUP $runas_gid"); exec($amp_conf["AMPBIN"]."/freepbx_setting AMPASTERISKWEBUSER $runas_uid"); exec($amp_conf["AMPBIN"]."/freepbx_setting AMPASTERISKGROUP $runas_gid"); exec($amp_conf["AMPBIN"]."/freepbx_setting AMPASTERISKUSER $runas_uid"); exec($amp_conf["AMPBIN"]."/freepbx_setting AMPDEVGROUP $runas_gid"); exec($amp_conf["AMPBIN"]."/freepbx_setting AMPDEVUSER $runas_uid"); if (!$dryrun) { $asteriskuser = isset($amp_conf['AMPASTERISKUSER']) && $amp_conf['AMPASTERISKUSER'] ? $amp_conf['AMPASTERISKUSER'] : 'asterisk'; if (file_exists($amp_conf["AMPSBIN"]."/amportal")) { exec("chmod 755 ".$amp_conf["AMPSBIN"]."/amportal"); outn("amportal.."); } else { outn("no amportal.."); } if (file_exists($amp_conf["AMPSBIN"]."/fpbx")) { exec("chmod 755 ".$amp_conf["AMPSBIN"]."/fpbx"); outn("fpbx.."); } else { outn("no fpbx.."); } if (file_exists($amp_conf["AMPBIN"]."/freepbx_engine")) { exec("chmod 755 ".$amp_conf["AMPBIN"]."/freepbx_engine"); outn("freepbx_engine.."); } else { outn("no freepbx_engine.."); } if (file_exists($amp_conf["AMPBIN"]."/freepbx_setting")) { exec("chmod 755 ".$amp_conf["AMPBIN"]."/freepbx_setting"); outn("freepbx_setting.."); } else { outn("no freepbx_setting.."); } if (file_exists($amp_conf["AMPBIN"]."/gen_amp_conf.php")) { exec("chmod 755 ".$amp_conf["AMPBIN"]."/gen_amp_conf.php"); outn("gen_amp_conf.php.."); } else { outn("no gen_amp_conf.."); } out("done"); // Note - freepbx_engine must be run to ensure that freepbx.conf exists. exec($amp_conf["AMPBIN"]."/freepbx_engine error > /dev/null"); // Ensure UIDs are set correctly before any chowns happen exec($amp_conf["AMPBIN"]."/freepbx_setting AMPASTERISKWEBGROUP $runas_gid"); exec($amp_conf["AMPBIN"]."/freepbx_setting AMPASTERISKWEBUSER $runas_uid"); exec($amp_conf["AMPBIN"]."/freepbx_setting AMPASTERISKGROUP $runas_gid"); exec($amp_conf["AMPBIN"]."/freepbx_setting AMPASTERISKUSER $runas_uid"); exec($amp_conf["AMPBIN"]."/freepbx_setting AMPDEVGROUP $runas_gid"); exec($amp_conf["AMPBIN"]."/freepbx_setting AMPDEVUSER $runas_uid"); exec($amp_conf["AMPBIN"]."/freepbx_setting ASTMANAGERHOST $asteriskip"); // edit conf file passwords and then // reload manager in asterisk if it is running: // outn("apply username/password changes to conf files.."); if (file_exists(dirname(__FILE__)."/apply_conf.sh")) { if ($force_amportal_conf) { putenv('FORCE_AMPORTAL_CONF=1'); exec(dirname(__FILE__)."/apply_conf.sh ".AMP_CONF); putenv('FORCE_AMPORTAL_CONF='); } else { exec(dirname(__FILE__)."/apply_conf.sh"); } } out("done"); /* As of Asterisk 1.4.16 or there about, a missing #include file will make the reload fail. So we need to make sure that we have such for everything that is in our configs. We will simply look for the #include statements and touch the files vs. trying to inventory everything we may need and then forgetting something. */ outn("creating missing #include files.."); $include_err = false; exec("grep '#include' ".$amp_conf['ASTETCDIR']."/*.conf | sed 's/;.*//; s/#include//'",$output,$retcode); if ($retcode != 0) { out("Error code $retcode: trying to search for missing #include files"); $include_err = true; } foreach($output as $file) { if (trim($file) == '') { continue; } $parse1 = explode(':',$file); $parse2 = explode(';',$parse1[1]); $rawfile = trim($parse2[0]); if ($rawfile == '') { continue; } $target = ($rawfile[0] == '/') ? $rawfile : $amp_conf['ASTETCDIR']."/$rawfile"; if (!file_exists($target)) { exec("sudo -u $asteriskuser touch $target", $output, $retcode); if ($retcode != 0) { out("Error code $retcode: trying to create empty file $target"); $include_err = true; } } } if (! $include_err) { out("OK"); } // reload manager in asterisk if it was running: // if (version_compare($asterisk_version,'1.4','ge')) { system("asterisk -rx 'module reload manager'"); } else { system("asterisk -rx 'reload manager'"); //1.2 syntax } } out("OK"); // **** Create spool directories for monitor and fax if (!is_dir($amp_conf["ASTSPOOLDIR"]."/monitor")) amp_mkdir($amp_conf["ASTSPOOLDIR"]."/monitor","0766",true); if (!is_dir($amp_conf["ASTSPOOLDIR"]."/fax")) amp_mkdir($amp_conf["ASTSPOOLDIR"]."/fax","0766",true); // **** Set permissions all files // tell amportal/freepbx_engine to use amportal.conf and not bootstrap // if freepbx_settings has not been setup yet or you will get an error. // if ($install_files) { outn("Setting permissions on files.."); if (!$dryrun) { if ($force_amportal_conf) { putenv('FORCE_AMPORTAL_CONF=1'); } exec($amp_conf["AMPSBIN"]."/amportal chown"); if ($force_amportal_conf) { putenv('FORCE_AMPORTAL_CONF='); } } out("OK"); } // Run through all the upgrade scripts starting at the specified version // upgrade_all($version); outn("Creating or updating freepbx_conf settings.."); freepbx_settings_init(true); out("..OK"); // **** Generate AMP configs out("Generating AMP configs.."); generate_configs(); out("Generating AMP configs..OK"); $version = install_getversion(); if($install_fop && $amp_conf["FOPRUN"]) { // **** Bounce FOP outn("Restarting Flash Operator Panel.."); exec("sudo -u $asteriskuser ".$amp_conf["AMPBIN"].'/bounce_op.sh'); out("OK"); } // Now force an install for all modules that are packaged with the tarball // directory. // if ($module_install) { install_modules(); } else { out("bypassing packaged module installation because --skip-module-install flag"); } // **** Set reload flag for AMP admin needreload(); if ($amp_conf["AMPWEBADDRESS"]) { out("Please update your modules and reload Asterisk by visiting http://".$amp_conf["AMPWEBADDRESS"]."/admin",false); } else { out("Please update your modules and reload Asterisk by browsing to your server.",false); } out("",false); out("*************************************************************************",false); out("* Note: It's possible that if you click the red 'Update Now' bar BEFORE *",false); out("* updating your modules, your machine will start dropping calls. Ensure *",false); out("* that all modules are up to date BEFORE YOU CLICK THE RED BAR. As long *",false); out("* as this is observed, your machine will be fully functional whilst the *",false); out("* upgrade is in progress. *",false); out("*************************************************************************",false); // vim: set ts=4 sw=4 : // // Ensure you 'set modeline' in your ~/.vimrc to activate this // ?>