Issues (2553)

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Artem Sidorenko <[email protected]>
6
 * @author Christopher Schäpers <[email protected]>
7
 * @author Christoph Wurst <[email protected]>
8
 * @author Daniel Kesselberg <[email protected]>
9
 * @author hoellen <[email protected]>
10
 * @author J0WI <[email protected]>
11
 * @author Jakob Sack <[email protected]>
12
 * @author Joas Schilling <[email protected]>
13
 * @author Jörn Friedrich Dreyer <[email protected]>
14
 * @author Ko- <[email protected]>
15
 * @author Michael Kuhn <[email protected]>
16
 * @author Morris Jobke <[email protected]>
17
 * @author Oliver Kohl D.Sc. <[email protected]>
18
 * @author Robin Appelman <[email protected]>
19
 * @author Roeland Jago Douma <[email protected]>
20
 * @author Steffen Lindner <[email protected]>
21
 * @author Thomas Müller <[email protected]>
22
 * @author Vincent Petry <[email protected]>
23
 * @author Stephen Michel <[email protected]>
24
 *
25
 * @license AGPL-3.0
26
 *
27
 * This code is free software: you can redistribute it and/or modify
28
 * it under the terms of the GNU Affero General Public License, version 3,
29
 * as published by the Free Software Foundation.
30
 *
31
 * This program is distributed in the hope that it will be useful,
32
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34
 * GNU Affero General Public License for more details.
35
 *
36
 * You should have received a copy of the GNU Affero General Public License, version 3,
37
 * along with this program. If not, see <http://www.gnu.org/licenses/>
38
 *
39
 */
40
require_once __DIR__ . '/lib/versioncheck.php';
41
42
try {
43
	require_once __DIR__ . '/lib/base.php';
44
45
	if (\OCP\Util::needUpgrade()) {
46
		\OC::$server->getLogger()->debug('Update required, skipping cron', ['app' => 'cron']);
47
		exit;
48
	}
49
	if ((bool) \OC::$server->getSystemConfig()->getValue('maintenance', false)) {
50
		\OC::$server->getLogger()->debug('We are in maintenance mode, skipping cron', ['app' => 'cron']);
51
		exit;
52
	}
53
54
	// load all apps to get all api routes properly setup
55
	OC_App::loadApps();
56
57
	\OC::$server->getSession()->close();
58
59
	// initialize a dummy memory session
60
	$session = new \OC\Session\Memory('');
61
	$cryptoWrapper = \OC::$server->getSessionCryptoWrapper();
62
	$session = $cryptoWrapper->wrapSession($session);
63
	\OC::$server->setSession($session);
64
65
	$logger = \OC::$server->getLogger();
66
	$config = \OC::$server->getConfig();
67
	$tempManager = \OC::$server->getTempManager();
68
69
	// Don't do anything if Nextcloud has not been installed
70
	if (!$config->getSystemValue('installed', false)) {
71
		exit(0);
72
	}
73
74
	$tempManager->cleanOld();
75
76
	// Exit if background jobs are disabled!
77
	$appMode = $config->getAppValue('core', 'backgroundjobs_mode', 'ajax');
78
	if ($appMode === 'none') {
79
		if (OC::$CLI) {
80
			echo 'Background Jobs are disabled!' . PHP_EOL;
81
		} else {
82
			OC_JSON::error(['data' => ['message' => 'Background jobs disabled!']]);
83
		}
84
		exit(1);
85
	}
86
87
	if (OC::$CLI) {
88
		// set to run indefinitely if needed
89
		if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
90
			@set_time_limit(0);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for set_time_limit(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

90
			/** @scrutinizer ignore-unhandled */ @set_time_limit(0);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
91
		}
92
93
		// the cron job must be executed with the right user
94
		if (!function_exists('posix_getuid')) {
95
			echo "The posix extensions are required - see https://www.php.net/manual/en/book.posix.php" . PHP_EOL;
96
			exit(1);
97
		}
98
99
		$user = posix_getuid();
100
		$configUser = fileowner(OC::$configDir . 'config.php');
101
		if ($user !== $configUser) {
102
			echo "Console has to be executed with the user that owns the file config/config.php" . PHP_EOL;
103
			echo "Current user id: " . $user . PHP_EOL;
104
			echo "Owner id of config.php: " . $configUser . PHP_EOL;
105
			exit(1);
106
		}
107
108
109
		// We call Nextcloud from the CLI (aka cron)
110
		if ($appMode !== 'cron') {
111
			$config->setAppValue('core', 'backgroundjobs_mode', 'cron');
112
		}
113
114
		// Low-load hours
115
		$onlyTimeSensitive = false;
116
		$startHour = $config->getSystemValueInt('maintenance_window_start', 100);
117
		if ($startHour <= 23) {
118
			$date = new \DateTime('now', new \DateTimeZone('UTC'));
119
			$currentHour = (int) $date->format('G');
120
			$endHour = $startHour + 4;
121
122
			if ($startHour <= 20) {
123
				// Start time: 01:00
124
				// End time: 05:00
125
				// Only run sensitive tasks when it's before the start or after the end
126
				$onlyTimeSensitive = $currentHour < $startHour || $currentHour > $endHour;
127
			} else {
128
				// Start time: 23:00
129
				// End time: 03:00
130
				$endHour -= 24; // Correct the end time from 27:00 to 03:00
131
				// Only run sensitive tasks when it's after the end and before the start
132
				$onlyTimeSensitive = $currentHour > $endHour && $currentHour < $startHour;
133
			}
134
		}
135
136
		// Work
137
		$jobList = \OC::$server->getJobList();
138
139
		// We only ask for jobs for 14 minutes, because after 5 minutes the next
140
		// system cron task should spawn and we want to have at most three
141
		// cron jobs running in parallel.
142
		$endTime = time() + 14 * 60;
143
144
		$executedJobs = [];
145
		while ($job = $jobList->getNext($onlyTimeSensitive)) {
146
			if (isset($executedJobs[$job->getId()])) {
147
				$jobList->unlockJob($job);
148
				break;
149
			}
150
151
			$logger->debug('CLI cron call has selected job with ID ' . strval($job->getId()), ['app' => 'cron']);
152
			$job->execute($jobList, $logger);
153
154
			// clean up after unclean jobs
155
			\OC_Util::tearDownFS();
156
			$tempManager->clean();
157
158
			$jobList->setLastJob($job);
159
			$executedJobs[$job->getId()] = true;
160
			unset($job);
161
162
			if (time() > $endTime) {
163
				break;
164
			}
165
		}
166
	} else {
167
		// We call cron.php from some website
168
		if ($appMode === 'cron') {
169
			// Cron is cron :-P
170
			OC_JSON::error(['data' => ['message' => 'Backgroundjobs are using system cron!']]);
171
		} else {
172
			// Work and success :-)
173
			$jobList = \OC::$server->getJobList();
174
			$job = $jobList->getNext();
175
			if ($job != null) {
176
				$logger->debug('WebCron call has selected job with ID ' . strval($job->getId()), ['app' => 'cron']);
177
				$job->execute($jobList, $logger);
178
				$jobList->setLastJob($job);
179
			}
180
			OC_JSON::success();
181
		}
182
	}
183
184
	// Log the successful cron execution
185
	$config->setAppValue('core', 'lastcron', time());
186
	exit();
187
} catch (Exception $ex) {
188
	\OC::$server->getLogger()->logException($ex, ['app' => 'cron']);
189
	echo $ex . PHP_EOL;
190
	exit(1);
191
} catch (Error $ex) {
192
	\OC::$server->getLogger()->logException($ex, ['app' => 'cron']);
193
	echo $ex . PHP_EOL;
194
	exit(1);
195
}
196