Project

General

Profile

Download (12.3 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	gmirror.inc
4

    
5
	part of pfSense (https://www.pfsense.org)
6
	Copyright (c) 2009-2016 Electric Sheep Fencing, LLC. All rights reserved.
7

    
8
	Redistribution and use in source and binary forms, with or without
9
	modification, are permitted provided that the following conditions are met:
10

    
11
	1. Redistributions of source code must retain the above copyright notice,
12
	   this list of conditions and the following disclaimer.
13

    
14
	2. Redistributions in binary form must reproduce the above copyright
15
	   notice, this list of conditions and the following disclaimer in
16
	   the documentation and/or other materials provided with the
17
	   distribution.
18

    
19
	3. All advertising materials mentioning features or use of this software
20
	   must display the following acknowledgment:
21
	   "This product includes software developed by the pfSense Project
22
	   for use in the pfSense® software distribution. (http://www.pfsense.org/).
23

    
24
	4. The names "pfSense" and "pfSense Project" must not be used to
25
	   endorse or promote products derived from this software without
26
	   prior written permission. For written permission, please contact
27
	   coreteam@pfsense.org.
28

    
29
	5. Products derived from this software may not be called "pfSense"
30
	   nor may "pfSense" appear in their names without prior written
31
	   permission of the Electric Sheep Fencing, LLC.
32

    
33
	6. Redistributions of any form whatsoever must retain the following
34
	   acknowledgment:
35

    
36
	"This product includes software developed by the pfSense Project
37
	for use in the pfSense software distribution (http://www.pfsense.org/).
38

    
39
	THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
40
	EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42
	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
43
	ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44
	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46
	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47
	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48
	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50
	OF THE POSSIBILITY OF SUCH DAMAGE.
51
*/
52

    
53
global $balance_methods;
54
$balance_methods = array("load", "prefer", "round-robin", "split");
55

    
56
/* Create a status array for each mirror and its disk components. */
57
function gmirror_get_status() {
58
	$status = "";
59
	exec("/sbin/gmirror status -s", $status);
60
	$mirrors = array();
61

    
62
	/* Empty output = no mirrors found */
63
	if (count($status) > 0) {
64
		/* Loop through gmirror status output. */
65
		foreach ($status as $line) {
66
			/* Split the line by whitespace */
67
			$all = preg_split("/[\s\t]+/", trim($line), 3);
68
			if (count($all) == 3) {
69
				/* If there are three items on a line, it is mirror name, status, and component */
70
				$currentmirror = basename($all[0]);
71
				$mirrors[$currentmirror]['name'] = basename($all[0]);
72
				$mirrors[$currentmirror]['status'] = $all[1];
73
				if (!is_array($mirrors[$currentmirror]['components'])) {
74
					$mirrors[$currentmirror]['components'] = array();
75
				}
76
				$mirrors[$currentmirror]['components'][] = $all[2];
77
			}
78
		}
79
	}
80
	/* Return an hash of mirrors and components */
81
	return $mirrors;
82
}
83

    
84
/* Get only status word for a single mirror. */
85
function gmirror_get_status_single($mirror) {
86
	$status = "";
87
	$mirror_status = gmirror_get_status();
88
	return $mirror_status[$mirror]['status'];
89
}
90

    
91
/* Generate an HTML formatted status for mirrors and disks in a small format for the widget */
92
function gmirror_html_status() {
93
	$mirrors = gmirror_get_status();
94
	$output = "";
95
	if (count($mirrors) < 1) {
96
		print_info_box(gettext("No mirrors found."), 'warning', false);
97
		return;
98
	}
99

    
100
?>
101
<table class="table table-striped table-hover">
102
	<thead>
103
		<tr>
104
			<th><?=gettext("Name")?></td>
105
			<th><?=gettext("Status")?></td>
106
			<th><?=gettext("Component")?></td>
107
		</tr>
108
	</thead>
109
	<tbody>
110
<?php foreach ($mirrors as $mirror => $name): ?>
111
		<tr>
112
			<td rowspan="<?=count($name["components"])?>"><?=$name['name']?></td>
113
			<td rowspan="<?=count($name["components"])?>"><?=$name['status']?></td>
114
			<td><?=$name['components'][0]?></td>
115
		</tr>
116
<?php if (count($name["components"]) > 1): ?>
117
		<?php foreach (array_slice($name["components"], 1) as $component): ?>
118
			<tr>
119
				<td><?=$component?></td>
120
			</tr>
121
		<?php endforeach; ?>
122
	<?php endif; ?>
123
<?php endforeach; ?>
124
	</tbody>
125
</table>
126
<?php
127
}
128

    
129
/* List all disks in the system (potential gmirror targets) */
130
function gmirror_get_disks() {
131
	$disklist = "";
132
	/* Get a list of disks in a scriptable way, exclude optical drives */
133
	exec("/sbin/geom disk status -s | /usr/bin/grep -v '[[:blank:]]*cd[[:digit:]]*' | /usr/bin/awk '{print $1;}'", $disklist);
134
	return $disklist;
135
}
136

    
137
/* List all potential gmirror consumers */
138
function gmirror_get_unused_consumers() {
139
	$consumerlist = "";
140
	$disklist = gmirror_get_disks();
141
	/* Get a list of consumers, exclude existing mirrors and diskid entries */
142
	exec("/sbin/geom part status -s | /usr/bin/egrep -v '(mirror|diskid)' | /usr/bin/awk '{print $1, $3;}'", $consumerlist);
143
	$all_consumers = array();
144
	foreach ($consumerlist as $cl) {
145
		$parts = explode(" ", $cl);
146
		foreach ($parts as $part) {
147
			$all_consumers[] = $part;
148
		}
149
	}
150
	foreach ($disklist as $d) {
151
		if (!is_consumer_used($d) && !in_array($d, $all_consumers)) {
152
			$all_consumers[] = $d;
153
		}
154
	}
155
	return $all_consumers;
156
}
157

    
158
/* List all existing geom mirrors */
159
function gmirror_get_mirrors() {
160
	$mirrorlist = "";
161
	exec("/sbin/gmirror list | /usr/bin/grep '^Geom name:' | /usr/bin/awk '{print $3;}'", $mirrorlist);
162
	return $mirrorlist;
163
}
164

    
165

    
166
/* List all consumers for a given mirror */
167
function gmirror_get_consumers_in_mirror($mirror) {
168
	if (!is_valid_mirror($mirror)) {
169
		return array();
170
	}
171

    
172
	$consumers = array();
173
	exec("/sbin/gmirror status -s " . escapeshellarg($mirror) . " | /usr/bin/awk '{print $3;}'", $consumers);
174
	return $consumers;
175
}
176

    
177
/* Test if a given consumer is a member of an existing mirror */
178
function is_consumer_in_mirror($consumer, $mirror) {
179
	if (!is_valid_consumer($consumer) || !is_valid_mirror($mirror)) {
180
		return false;
181
	}
182

    
183
	$mirrorconsumers = gmirror_get_consumers_in_mirror($mirror);
184
	return in_array(basename($consumer), $mirrorconsumers);
185
}
186

    
187
/* Test if a mirror exists */
188
function is_valid_mirror($mirror) {
189
	$mirrors = gmirror_get_mirrors();
190
	return in_array($mirror, $mirrors);
191
}
192

    
193
/* Test if a disk is valid/exists */
194
function is_valid_disk($disk) {
195
	$adisks = gmirror_get_disks();
196
	return in_array(basename($disk), $adisks);
197
}
198

    
199
/* Test if a consumer is valid and in use in a mirror */
200
function is_consumer_used($consumer) {
201
	$found = false;
202
	$mirrors = gmirror_get_mirrors();
203
	foreach ($mirrors as $mirror) {
204
		$consumers = gmirror_get_consumers_in_mirror($mirror);
205
		if (in_array($consumer, $consumers)) {
206
			return true;
207
		}
208
	}
209
	return false;
210
}
211

    
212
/* Test if a consumer is valid and not in use */
213
function is_consumer_unused($consumer) {
214
	$consumers = gmirror_get_unused_consumers();
215
	return in_array($consumer, $consumers);
216
}
217

    
218
/* Test if a consumer is valid (either a disk or partition) */
219
function is_valid_consumer($consumer) {
220
	return (is_consumer_unused($consumer) || is_consumer_used($consumer));
221
}
222

    
223
/* Remove all disconnected drives from a mirror */
224
function gmirror_forget_disconnected($mirror) {
225
	if (!is_valid_mirror($mirror)) {
226
		return false;
227
	}
228
	return mwexec("/sbin/gmirror forget " . escapeshellarg($mirror));
229
}
230

    
231
/* Insert another consumer into a mirror */
232
function gmirror_insert_consumer($mirror, $consumer) {
233
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
234
		return false;
235
	}
236
	return mwexec("/sbin/gmirror insert " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
237
}
238

    
239
/* Remove consumer from a mirror and clear its metadata */
240
function gmirror_remove_consumer($mirror, $consumer) {
241
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
242
		return false;
243
	}
244
	return mwexec("/sbin/gmirror remove " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
245
}
246

    
247
/* Wipe geom info from drive (if mirror is not running) */
248
function gmirror_clear_consumer($consumer) {
249
	if (!is_valid_consumer($consumer)) {
250
		return false;
251
	}
252
	return mwexec("/sbin/gmirror clear " . escapeshellarg($consumer));
253
}
254

    
255
/* Find the balance method used by a given mirror */
256
function gmirror_get_mirror_balance($mirror) {
257
	if (!is_valid_mirror($mirror)) {
258
		return false;
259
	}
260
	$balancemethod = "";
261
	exec("/sbin/gmirror list " . escapeshellarg($mirror) . " | /usr/bin/grep '^Balance:' | /usr/bin/awk '{print $2;}'", $balancemethod);
262
	return $balancemethod[0];
263
}
264

    
265
/* Change balance algorithm of the mirror */
266
function gmirror_configure_balance($mirror, $balancemethod) {
267
	global $balance_methods;
268
	if (!is_valid_mirror($mirror) || !in_array($balancemethod, $balance_methods)) {
269
		return false;
270
	}
271
	return mwexec("/sbin/gmirror configure -b " . escapeshellarg($balancemethod) . " " . escapeshellarg($mirror));
272
}
273

    
274
/* Force a mirror member to rebuild */
275
function gmirror_force_rebuild($mirror, $consumer) {
276
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
277
		return false;
278
	}
279
	return mwexec("/sbin/gmirror rebuild " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
280
}
281

    
282
/* Show all metadata on the physical consumer */
283
function gmirror_get_consumer_metadata($consumer) {
284
	if (!is_valid_consumer($consumer)) {
285
		return array();
286
	}
287
	$output = array();
288
	exec("/sbin/gmirror dump " . escapeshellarg($consumer), $output);
289
	return array_map('trim', $output);
290
}
291

    
292
/* Test if a consumer has metadata, indicating it is a member of a mirror (active or inactive) */
293
function gmirror_consumer_has_metadata($consumer) {
294
	return (count(gmirror_get_consumer_metadata($consumer)) > 0);
295
}
296

    
297
/* Find the mirror to which this consumer belongs */
298
function gmirror_get_consumer_metadata_mirror($consumer) {
299
	if (!is_valid_consumer($consumer)) {
300
		return array();
301
	}
302
	$metadata = gmirror_get_consumer_metadata($consumer);
303
	foreach ($metadata as $line) {
304
		if (substr($line, 0, 5) == "name:") {
305
			list ($key, $value) = explode(":", $line, 2);
306
			return trim($value);
307
		}
308
	}
309
}
310

    
311
/* Deactivate consumer, removing it from service in the mirror, but leave metadata intact */
312
function gmirror_deactivate_consumer($mirror, $consumer) {
313
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
314
		return false;
315
	}
316
	return mwexec("/sbin/gmirror deactivate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
317
}
318

    
319
/* Reactivate a deactivated consumer */
320
function gmirror_activate_consumer($mirror, $consumer) {
321
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
322
		return false;
323
	}
324
	return mwexec("/sbin/gmirror activate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
325
}
326

    
327
/* Find the size of the given mirror */
328
function gmirror_get_mirror_size($mirror) {
329
	if (!is_valid_mirror($mirror)) {
330
		return false;
331
	}
332
	$mirrorsize = "";
333
	exec("/sbin/gmirror list " . escapeshellarg($mirror) . " | /usr/bin/grep 'Mediasize:' | /usr/bin/head -n 1 | /usr/bin/awk '{print $2;}'", $mirrorsize);
334
	return $mirrorsize[0];
335
}
336

    
337
/* Return a list of all potential consumers on a disk with sizes. The geom part
338
	list output is a little odd, we can't get the output for just the disk, if the disk contains
339
	slices those get output also. */
340
function gmirror_get_all_unused_consumer_sizes_on_disk($disk) {
341
	if (!is_valid_disk($disk) || !is_consumer_unused($disk)) {
342
		return array();
343
	}
344
	$output = array();
345
	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);
346
	if (empty($output)) {
347
		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);
348
	}
349
	$disk_contents = array();
350
	foreach ($output as $line) {
351
		list($name, $size, $humansize) = explode(" ", $line, 3);
352
		$consumer = array();
353
		$consumer['name'] = $name;
354
		$consumer['size'] = $size;
355
		$consumer['humansize'] = $humansize;
356
		$disk_contents[] = $consumer;
357
	}
358
	return $disk_contents;
359
}
360

    
361
/* Get only the size for one specific potential consumer. */
362
function gmirror_get_unused_consumer_size($consumer) {
363
	$consumersizes = gmirror_get_all_unused_consumer_sizes_on_disk($consumer);
364
	foreach ($consumersizes as $csize) {
365
		if ($csize['name'] == $consumer) {
366
			return $csize['size'];
367
		}
368
	}
369
	return -1;
370
}
371
?>
(22-22/65)