Project

General

Profile

Download (10.8 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * gmirror.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8
 * Copyright (c) 2014-2020 Rubicon Communications, LLC (Netgate)
9
 * All rights reserved.
10
 *
11
 * Licensed under the Apache License, Version 2.0 (the "License");
12
 * you may not use this file except in compliance with the License.
13
 * You may obtain a copy of the License at
14
 *
15
 * http://www.apache.org/licenses/LICENSE-2.0
16
 *
17
 * Unless required by applicable law or agreed to in writing, software
18
 * distributed under the License is distributed on an "AS IS" BASIS,
19
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
 * See the License for the specific language governing permissions and
21
 * limitations under the License.
22
 */
23

    
24
global $balance_methods;
25
$balance_methods = array("load", "prefer", "round-robin", "split");
26

    
27
/* Create a status array for each mirror and its disk components. */
28
function gmirror_get_status() {
29
	$status = "";
30
	exec("/sbin/gmirror status -s", $status);
31
	$mirrors = array();
32

    
33
	/* Empty output = no mirrors found */
34
	if (count($status) > 0) {
35
		/* Loop through gmirror status output. */
36
		foreach ($status as $line) {
37
			/* Split the line by whitespace */
38
			$all = preg_split("/[\s\t]+/", trim($line), 3);
39
			if (count($all) == 3) {
40
				/* If there are three items on a line, it is mirror name, status, and component */
41
				$currentmirror = basename($all[0]);
42
				$mirrors[$currentmirror]['name'] = basename($all[0]);
43
				$mirrors[$currentmirror]['status'] = $all[1];
44
				if (!is_array($mirrors[$currentmirror]['components'])) {
45
					$mirrors[$currentmirror]['components'] = array();
46
				}
47
				$mirrors[$currentmirror]['components'][] = $all[2];
48
			}
49
		}
50
	}
51
	/* Return an hash of mirrors and components */
52
	return $mirrors;
53
}
54

    
55
/* Get only status word for a single mirror. */
56
function gmirror_get_status_single($mirror) {
57
	$status = "";
58
	$mirror_status = gmirror_get_status();
59
	return $mirror_status[$mirror]['status'];
60
}
61

    
62
/* Generate an HTML formatted status for mirrors and disks in a small format for the widget */
63
function gmirror_html_status() {
64
	$mirrors = gmirror_get_status();
65
	$output = "";
66
	if (count($mirrors) < 1) {
67
		print_info_box(gettext("No mirrors found."), 'warning', false);
68
		return;
69
	}
70

    
71
?>
72
<table class="table table-striped table-hover">
73
	<thead>
74
		<tr>
75
			<th><?=gettext("Name")?></td>
76
			<th><?=gettext("Status")?></td>
77
			<th><?=gettext("Component")?></td>
78
		</tr>
79
	</thead>
80
	<tbody>
81
<?php foreach ($mirrors as $mirror => $name): ?>
82
		<tr>
83
			<td rowspan="<?=count($name["components"])?>"><?=$name['name']?></td>
84
			<td rowspan="<?=count($name["components"])?>"><?=$name['status']?></td>
85
			<td><?=$name['components'][0]?></td>
86
		</tr>
87
<?php if (count($name["components"]) > 1): ?>
88
		<?php foreach (array_slice($name["components"], 1) as $component): ?>
89
			<tr>
90
				<td><?=$component?></td>
91
			</tr>
92
		<?php endforeach; ?>
93
	<?php endif; ?>
94
<?php endforeach; ?>
95
	</tbody>
96
</table>
97
<?php
98
}
99

    
100
/* List all disks in the system (potential gmirror targets) */
101
function gmirror_get_disks() {
102
	$disklist = "";
103
	/* Get a list of disks in a scriptable way, exclude optical drives */
104
	exec("/sbin/geom disk status -s | /usr/bin/grep -v '[[:blank:]]*cd[[:digit:]]*' | /usr/bin/awk '{print $1;}'", $disklist);
105
	return $disklist;
106
}
107

    
108
/* List all potential gmirror consumers */
109
function gmirror_get_unused_consumers() {
110
	$consumerlist = "";
111
	$disklist = gmirror_get_disks();
112
	/* Get a list of consumers, exclude existing mirrors and diskid entries */
113
	exec("/sbin/geom part status -s | /usr/bin/egrep -v '(mirror|diskid)' | /usr/bin/awk '{print $1, $3;}'", $consumerlist);
114
	$all_consumers = array();
115
	foreach ($consumerlist as $cl) {
116
		$parts = explode(" ", $cl);
117
		foreach ($parts as $part) {
118
			$all_consumers[] = $part;
119
		}
120
	}
121
	foreach ($disklist as $d) {
122
		if (!is_consumer_used($d) && !in_array($d, $all_consumers)) {
123
			$all_consumers[] = $d;
124
		}
125
	}
126
	return $all_consumers;
127
}
128

    
129
/* List all existing geom mirrors */
130
function gmirror_get_mirrors() {
131
	$mirrorlist = "";
132
	exec("/sbin/gmirror list | /usr/bin/grep '^Geom name:' | /usr/bin/awk '{print $3;}'", $mirrorlist);
133
	return $mirrorlist;
134
}
135

    
136

    
137
/* List all consumers for a given mirror */
138
function gmirror_get_consumers_in_mirror($mirror) {
139
	if (!is_valid_mirror($mirror)) {
140
		return array();
141
	}
142

    
143
	$consumers = array();
144
	exec("/sbin/gmirror status -s " . escapeshellarg($mirror) . " | /usr/bin/awk '{print $3;}'", $consumers);
145
	return $consumers;
146
}
147

    
148
/* Test if a given consumer is a member of an existing mirror */
149
function is_consumer_in_mirror($consumer, $mirror) {
150
	if (!is_valid_consumer($consumer) || !is_valid_mirror($mirror)) {
151
		return false;
152
	}
153

    
154
	$mirrorconsumers = gmirror_get_consumers_in_mirror($mirror);
155
	return in_array(basename($consumer), $mirrorconsumers);
156
}
157

    
158
/* Test if a mirror exists */
159
function is_valid_mirror($mirror) {
160
	$mirrors = gmirror_get_mirrors();
161
	return in_array($mirror, $mirrors);
162
}
163

    
164
/* Test if a disk is valid/exists */
165
function is_valid_disk($disk) {
166
	$adisks = gmirror_get_disks();
167
	return in_array(basename($disk), $adisks);
168
}
169

    
170
/* Test if a consumer is valid and in use in a mirror */
171
function is_consumer_used($consumer) {
172
	$found = false;
173
	$mirrors = gmirror_get_mirrors();
174
	foreach ($mirrors as $mirror) {
175
		$consumers = gmirror_get_consumers_in_mirror($mirror);
176
		if (in_array($consumer, $consumers)) {
177
			return true;
178
		}
179
	}
180
	return false;
181
}
182

    
183
/* Test if a consumer is valid and not in use */
184
function is_consumer_unused($consumer) {
185
	$consumers = gmirror_get_unused_consumers();
186
	return in_array($consumer, $consumers);
187
}
188

    
189
/* Test if a consumer is valid (either a disk or partition) */
190
function is_valid_consumer($consumer) {
191
	return (is_consumer_unused($consumer) || is_consumer_used($consumer));
192
}
193

    
194
/* Remove all disconnected drives from a mirror */
195
function gmirror_forget_disconnected($mirror) {
196
	if (!is_valid_mirror($mirror)) {
197
		return false;
198
	}
199
	return mwexec("/sbin/gmirror forget " . escapeshellarg($mirror));
200
}
201

    
202
/* Insert another consumer into a mirror */
203
function gmirror_insert_consumer($mirror, $consumer) {
204
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
205
		return false;
206
	}
207
	return mwexec("/sbin/gmirror insert " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
208
}
209

    
210
/* Remove consumer from a mirror and clear its metadata */
211
function gmirror_remove_consumer($mirror, $consumer) {
212
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
213
		return false;
214
	}
215
	return mwexec("/sbin/gmirror remove " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
216
}
217

    
218
/* Wipe geom info from drive (if mirror is not running) */
219
function gmirror_clear_consumer($consumer) {
220
	if (!is_valid_consumer($consumer)) {
221
		return false;
222
	}
223
	return mwexec("/sbin/gmirror clear " . escapeshellarg($consumer));
224
}
225

    
226
/* Find the balance method used by a given mirror */
227
function gmirror_get_mirror_balance($mirror) {
228
	if (!is_valid_mirror($mirror)) {
229
		return false;
230
	}
231
	$balancemethod = "";
232
	exec("/sbin/gmirror list " . escapeshellarg($mirror) . " | /usr/bin/grep '^Balance:' | /usr/bin/awk '{print $2;}'", $balancemethod);
233
	return $balancemethod[0];
234
}
235

    
236
/* Change balance algorithm of the mirror */
237
function gmirror_configure_balance($mirror, $balancemethod) {
238
	global $balance_methods;
239
	if (!is_valid_mirror($mirror) || !in_array($balancemethod, $balance_methods)) {
240
		return false;
241
	}
242
	return mwexec("/sbin/gmirror configure -b " . escapeshellarg($balancemethod) . " " . escapeshellarg($mirror));
243
}
244

    
245
/* Force a mirror member to rebuild */
246
function gmirror_force_rebuild($mirror, $consumer) {
247
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
248
		return false;
249
	}
250
	return mwexec("/sbin/gmirror rebuild " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
251
}
252

    
253
/* Show all metadata on the physical consumer */
254
function gmirror_get_consumer_metadata($consumer) {
255
	if (!is_valid_consumer($consumer)) {
256
		return array();
257
	}
258
	$output = array();
259
	exec("/sbin/gmirror dump " . escapeshellarg($consumer), $output);
260
	return array_map('trim', $output);
261
}
262

    
263
/* Test if a consumer has metadata, indicating it is a member of a mirror (active or inactive) */
264
function gmirror_consumer_has_metadata($consumer) {
265
	return (count(gmirror_get_consumer_metadata($consumer)) > 0);
266
}
267

    
268
/* Find the mirror to which this consumer belongs */
269
function gmirror_get_consumer_metadata_mirror($consumer) {
270
	if (!is_valid_consumer($consumer)) {
271
		return array();
272
	}
273
	$metadata = gmirror_get_consumer_metadata($consumer);
274
	foreach ($metadata as $line) {
275
		if (substr($line, 0, 5) == "name:") {
276
			list ($key, $value) = explode(":", $line, 2);
277
			return trim($value);
278
		}
279
	}
280
}
281

    
282
/* Deactivate consumer, removing it from service in the mirror, but leave metadata intact */
283
function gmirror_deactivate_consumer($mirror, $consumer) {
284
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
285
		return false;
286
	}
287
	return mwexec("/sbin/gmirror deactivate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
288
}
289

    
290
/* Reactivate a deactivated consumer */
291
function gmirror_activate_consumer($mirror, $consumer) {
292
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
293
		return false;
294
	}
295
	return mwexec("/sbin/gmirror activate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
296
}
297

    
298
/* Find the size of the given mirror */
299
function gmirror_get_mirror_size($mirror) {
300
	if (!is_valid_mirror($mirror)) {
301
		return false;
302
	}
303
	$mirrorsize = "";
304
	exec("/sbin/gmirror list " . escapeshellarg($mirror) . " | /usr/bin/grep 'Mediasize:' | /usr/bin/head -n 1 | /usr/bin/awk '{print $2;}'", $mirrorsize);
305
	return $mirrorsize[0];
306
}
307

    
308
/* Return a list of all potential consumers on a disk with sizes. The geom part
309
	list output is a little odd, we can't get the output for just the disk, if the disk contains
310
	slices those get output also. */
311
function gmirror_get_all_unused_consumer_sizes_on_disk($disk) {
312
	if (!is_valid_disk($disk) || !is_consumer_unused($disk)) {
313
		return array();
314
	}
315
	$output = array();
316
	exec("/sbin/geom part list " . escapeshellarg($disk) . " | /usr/bin/egrep '(Name:|Mediasize:)' | /usr/bin/cut -c4- | /usr/bin/sed -l -e 'N;s/\\nMediasize://;P;D;' | /usr/bin/cut -c7-", $output);
317
	if (empty($output)) {
318
		exec("/sbin/geom disk list " . escapeshellarg($disk) . " | /usr/bin/egrep '(Name:|Mediasize:)' | /usr/bin/cut -c4- | /usr/bin/sed -l -e 'N;s/\\nMediasize://;P;D;' | /usr/bin/cut -c7-", $output);
319
	}
320
	$disk_contents = array();
321
	foreach ($output as $line) {
322
		list($name, $size, $humansize) = explode(" ", $line, 3);
323
		$consumer = array();
324
		$consumer['name'] = $name;
325
		$consumer['size'] = $size;
326
		$consumer['humansize'] = $humansize;
327
		$disk_contents[] = $consumer;
328
	}
329
	return $disk_contents;
330
}
331

    
332
/* Get only the size for one specific potential consumer. */
333
function gmirror_get_unused_consumer_size($consumer) {
334
	$consumersizes = gmirror_get_all_unused_consumer_sizes_on_disk($consumer);
335
	foreach ($consumersizes as $csize) {
336
		if ($csize['name'] == $consumer) {
337
			return $csize['size'];
338
		}
339
	}
340
	return -1;
341
}
342
?>
(20-20/60)