Project

General

Profile

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

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

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

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

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

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

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

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

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

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

    
134

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
306
/* Return a list of all potential consumers on a disk with sizes. The geom part
307
	list output is a little odd, we can't get the output for just the disk, if the disk contains
308
	slices those get output also. */
309
function gmirror_get_all_unused_consumer_sizes_on_disk($disk) {
310
	if (!is_valid_disk($disk) || !is_consumer_unused($disk)) {
311
		return array();
312
	}
313
	$output = array();
314
	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);
315
	if (empty($output)) {
316
		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);
317
	}
318
	$disk_contents = array();
319
	foreach ($output as $line) {
320
		list($name, $size, $humansize) = explode(" ", $line, 3);
321
		$consumer = array();
322
		$consumer['name'] = $name;
323
		$consumer['size'] = $size;
324
		$consumer['humansize'] = $humansize;
325
		$disk_contents[] = $consumer;
326
	}
327
	return $disk_contents;
328
}
329

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