4 * Small and fast system tasks trigger
6 * Copyright (C) 2014, 2015 Inria (Sylvain Beucler)
8 * This file is part of FusionForge. FusionForge is free software;
9 * you can redistribute it and/or modify it under the terms of the
10 * GNU General Public License as published by the Free Software
11 * Foundation; either version 2 of the Licence, or (at your option)
14 * FusionForge is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 //putenv('FUSIONFORGE_NO_PLUGINS=true');
25 //putenv('FUSIONFORGE_NO_DB=true');
27 require (dirname(__FILE__).'/../common/include/env.inc.php');
29 require_once $gfcommon.'include/pre.php';
30 } catch (DBException $e) {
31 print "Cannot connect to DB: $e\nWaiting for DB...\n";
33 require_once $gfcommon.'include/cron_utils.php';
35 // Invalidate users/groups cache e.g. when a user is added to a group
36 // Special-case in 'publish-subscribe' mode
37 function usergroups_sync() {
38 global $usergroups_lastsync;
39 $res = db_query_params("SELECT MAX(last_modified_date) AS lastmodified FROM nss_usergroups");
40 $row = db_fetch_array($res);
41 if ($row['lastmodified'] >= $usergroups_lastsync) {
42 $usergroups_lastsync = time();
44 cron_regen_apache_auth();
46 $hook_params = array();
47 plugin_hook("usergroups_sync", $hook_params);
51 function systask_get_script($plugin_id, $systask_type) {
53 if ($plugin_id == null) {
54 if (isset($cron_arr[$systask_type]))
55 return forge_get_config('source_path')
56 .'/cronjobs/'.$cron_arr[$systask_type];
59 $plugins = $pm->GetPlugins(); // reload in case a new plugin was installed
60 if (isset($plugins[$plugin_id])) {
61 $plugin = $pm->GetPluginObject($plugins[$plugin_id]);
62 if ($plugin == null) {
63 $pm->LoadPlugin($plugins[$plugin_id]);
64 $plugin = $pm->GetPluginObject($plugins[$plugin_id]);
66 if (isset($plugin->systask_types[$systask_type]))
67 return forge_get_config('plugins_path')."/".$plugin->GetName()
68 ."/cronjobs/".$plugin->systask_types[$systask_type];
74 function is_group_active_nocache($group_id) {
75 $res = db_query_params("SELECT group_id FROM nss_groups WHERE group_id=$1", array($group_id));
76 return (db_numrows($res) > 0);
80 $shortopts = 'v'; // enable verbose mode
81 $longopts = array('verbose');
82 $options = getopt($shortopts, $longopts);
83 if (count($options) != (count($argv)-1)) { // PHP just strips invalid options
84 print "Usage: {$argv[0]} [-v|--verbose]\n";
88 if (isset($options['v']) or isset($options['verbose'])) {
89 print "verbose mode ON\n";
96 //umask(0); // programmers usually expect umask=0022, and this would default mkdir to 0777
98 $log_path = forge_get_config('log_path');
100 // Hack to reopen stdin/stdout/stderr, order is important
101 // https://andytson.com/blog/2010/05/daemonising-a-php-cli-script-on-a-posix-system/
102 // (prevents PHP from exiting when printing anything)
106 $ff_stdin = fopen('/dev/null', 'r');
107 //$ff_stdout = fopen('/dev/null', 'w');
108 //$ff_stderr = fopen('php://stdout', 'w');
109 $ff_stdout = fopen("$log_path/systasksd.stdout", 'w');
110 $ff_stderr = fopen("$log_path/systasksd.stderr", 'w');
112 // We could fork & continue in the background too, but then we'd have
113 // to manage the PID file as well - best leave this to the init script
116 $pm = plugin_manager_get_object();
120 // Deal with pending requests
121 $res = db_query_params("SELECT * FROM systasks WHERE status=$1"
122 . " ORDER BY systask_id", array('TODO'));
123 if (!$res && !db_connection_status())
125 while ($arr = db_fetch_array($res)) {
126 $script = systask_get_script($arr['plugin_id'], $arr['systask_type']);
127 if (!file_exists($script))
128 // Not installed on this node, skipping
130 if (!is_executable($script)) {
131 db_query_params("UPDATE systasks SET status=$1, error_message=$2"
132 . " WHERE systask_id=$3",
134 "Cron job {$arr['plugin_id']}/{$arr['systask_type']}"
135 . " '$script' not executable.\n",
136 $arr['systask_id']));
140 // Concurrency: ensure groups are activated in the system before starting task
141 if (!empty($arr['group_id']) && !is_group_active_nocache($arr['group_id'])) {
142 continue; // wait until project is approved
146 db_query_params("UPDATE systasks SET status=$1, started=now() WHERE systask_id=$2",
147 array('WIP', $arr['systask_id']));
148 cron_acquire_lock($script);
150 if ($verbose) print "Running: $script... ";
151 system("$script\n", $ret);
152 cron_release_lock($script);
154 if ($verbose) print "DONE\n";
155 db_query_params("UPDATE systasks SET status=$1, stopped=now() WHERE systask_id=$2",
156 array('DONE', $arr['systask_id']));
158 if ($verbose) print "ERROR\n";
159 db_query_params("UPDATE systasks SET status=$1, stopped=now() WHERE systask_id=$2",
160 array('ERROR', $arr['systask_id']));
171 // c-file-style: "bsd"