xref: /netbsd-src/external/gpl2/lvm2/dist/lib/filters/filter_netbsd.c (revision 2c13773a38a639ca645e02a351aa04bbe1cef727)
1 /*      $NetBSD: filter_netbsd.c,v 1.4 2012/01/04 16:37:45 mhitch Exp $        */
2 
3 /*
4  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6  * Copyright (C) 2008 Adam Hamsik. All rights reserved.
7  *
8  * This file is part of LVM2.
9  *
10  * This copyrighted material is made available to anyone wishing to use,
11  * modify, copy, or redistribute it subject to the terms and conditions
12  * of the GNU Lesser General Public License v.2.1.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 
19 #include "lib.h"
20 #include "dev-cache.h"
21 #include "filter.h"
22 #include "lvm-string.h"
23 #include "config.h"
24 #include "metadata.h"
25 #include "activate.h"
26 
27 #include <sys/sysctl.h>
28 
29 #include <ctype.h>
30 #include <dirent.h>
31 #include <fcntl.h>
32 #include <limits.h>
33 #include <unistd.h>
34 
35 #define NUMBER_OF_MAJORS 4096
36 
37 #define LVM_SUCCESS 1
38 #define LVM_FAILURE 0
39 
40 /* -1 means LVM won't use this major number. */
41 static int _char_device_major[NUMBER_OF_MAJORS];
42 static int _block_device_major[NUMBER_OF_MAJORS];
43 
44 typedef struct {
45 	const char *name;
46 	const int max_partitions;
47 } device_info_t;
48 
49 static int _md_major = -1;
50 static int _device_mapper_major = -1;
51 
md_major(void)52 int md_major(void)
53 {
54 	return _md_major;
55 }
56 
dev_subsystem_part_major(const struct device * dev)57 int dev_subsystem_part_major(const struct device *dev)
58 {
59 	return 0;
60 }
61 
dev_subsystem_name(const struct device * dev)62 const char *dev_subsystem_name(const struct device *dev)
63 {
64 	return "";
65 }
66 
67 /*
68  * Devices are only checked for partition tables if their minor number
69  * is a multiple of the number corresponding to their type below
70  * i.e. this gives the granularity of whole-device minor numbers.
71  * Use 1 if the device is not partitionable.
72  *
73  * The list can be supplemented with devices/types in the config file.
74  */
75 static const device_info_t device_info[] = {
76 	{"wd", 64},
77 	{"sd", 64},
78 	{"dk", 1},
79 	{"wd", 64},
80 	{"vnd", 1},
81 	{"raid", 64},
82 	{"cgd", 1},
83 	{"ccd", 1},
84 	{"xbd", 64},
85 	{"ld", 64},
86 	{NULL, -1}
87 };
88 
89 /*
90  * Test if device passes filter tests and can be inserted in to cache.
91  */
_passes_lvm_type_device_filter(struct dev_filter * f __attribute ((unused)),struct device * dev)92 static int _passes_lvm_type_device_filter(struct dev_filter *f __attribute((unused)),
93 					  struct device *dev)
94 {
95 	const char *name = dev_name(dev);
96 	int ret = 0;
97 	uint64_t size;
98 
99 	/* Is this a recognised device type? */
100 	if (_char_device_major[MAJOR(dev->dev)] == -1 ){
101 		log_debug("%s: Skipping: Unrecognised LVM device type %"
102 				  PRIu64, name, (uint64_t) MAJOR(dev->dev));
103 		return LVM_FAILURE;
104 	}
105 
106 	/* Skip suspended devices */
107 	if (MAJOR(dev->dev) == _device_mapper_major &&
108 	    ignore_suspended_devices() && !device_is_usable(dev->dev)) {
109 		log_debug("%s: Skipping: Suspended dm device", name);
110 		return LVM_FAILURE;
111 	}
112 
113 	/* Check it's accessible */
114 	if (!dev_open_flags(dev, O_RDONLY, 0, 1)) {
115 		log_debug("%s: Skipping: open failed", name);
116 		return LVM_FAILURE;
117 	}
118 
119 	/* Check it's not too small */
120 	if (!dev_get_size(dev, &size)) {
121 	       	log_debug("%s: Skipping: dev_get_size failed", name);
122 		goto out;
123 	}
124 
125 	if (size < PV_MIN_SIZE) {
126 		log_debug("%s: Skipping: Too small to hold a PV", name);
127 		goto out;
128 	}
129 
130 	if (is_partitioned_dev(dev)) {
131 		log_debug("%s: Skipping: Partition table signature found",
132 			  name);
133 		goto out;
134 	}
135 
136 	ret = LVM_SUCCESS;
137 
138       out:
139 	dev_close(dev);
140 
141 	return ret;
142 }
143 
_scan_dev(const struct config_node * cn)144 static int _scan_dev(const struct config_node *cn)
145 {
146 	size_t val_len,i,j;
147 	char *name;
148 
149 	struct kinfo_drivers *kd;
150 	struct config_value *cv;
151 
152 	/* All types unrecognised initially */
153 	memset(_char_device_major, -1, sizeof(int) * NUMBER_OF_MAJORS);
154 	memset(_block_device_major, -1, sizeof(int) * NUMBER_OF_MAJORS);
155 
156 	/* get size kernel drivers array from kernel*/
157 	if (sysctlbyname("kern.drivers", NULL, &val_len, NULL, 0) < 0) {
158 		printf("sysctlbyname failed");
159 		return LVM_FAILURE;
160 	}
161 
162 	if ((kd = malloc(val_len)) == NULL){
163 		printf("malloc kd info error\n");
164 		return LVM_FAILURE;
165 	}
166 
167 	/* get array from kernel */
168 	if (sysctlbyname("kern.drivers", kd, &val_len, NULL, 0) < 0) {
169 		printf("sysctlbyname failed kd");
170 		return LVM_FAILURE;
171 	}
172 
173 	for (i = 0, val_len /= sizeof(*kd); i < val_len; i++) {
174 
175 		if (!strncmp("device-mapper", kd[i].d_name, 13) ||
176 		    !strncmp("dm", kd[i].d_name, 2))
177 			_device_mapper_major = kd[i].d_bmajor;
178 
179 		/* We select only devices with correct char/block major number. */
180 		if (kd[i].d_cmajor != -1 && kd[i].d_bmajor != -1) {
181 			/* Go through the valid device names and if there is a
182 			   match store max number of partitions */
183 			for (j = 0; device_info[j].name != NULL; j++){
184 				if (!strcmp(device_info[j].name, kd[i].d_name)){
185 					_char_device_major[kd[i].d_cmajor] =
186 					    device_info[j].max_partitions;
187 					_block_device_major[kd[i].d_bmajor] =
188 					    device_info[j].max_partitions;
189 					break;
190 				}
191 			}
192 		}
193 
194 		if (!cn)
195 			continue;
196 
197 		/* Check devices/types for local variations */
198 		for (cv = cn->v; cv; cv = cv->next) {
199 			if (cv->type != CFG_STRING) {
200 				log_error("Expecting string in devices/types "
201 					  "in config file");
202 				free(kd);
203 				return LVM_FAILURE;
204 			}
205 
206 			name = cv->v.str;
207 			cv = cv->next;
208 			if (!cv || cv->type != CFG_INT) {
209 				log_error("Max partition count missing for %s "
210 					  "in devices/types in config file",
211 					  name);
212 				free(kd);
213 				return LVM_FAILURE;
214 			}
215 			if (!cv->v.i) {
216 				log_error("Zero partition count invalid for "
217 					  "%s in devices/types in config file",
218 					  name);
219 				free(kd);
220 				return LVM_FAILURE;
221 			}
222 
223 			if (!strncmp(name, kd[i].d_name, strlen(name))){
224 					_char_device_major[kd[i].d_cmajor] =
225 					    cv->v.i;
226 					_block_device_major[kd[i].d_bmajor] =
227 					    cv->v.i;
228 					break;
229 			}
230 		}
231 	}
232 
233 	free(kd);
234 
235 	return LVM_SUCCESS;
236 }
237 
max_partitions(int major)238 int max_partitions(int major)
239 {
240 	return _char_device_major[major];
241 }
242 
lvm_type_filter_create(const char * proc,const struct config_node * cn)243 struct dev_filter *lvm_type_filter_create(const char *proc,
244 					  const struct config_node *cn)
245 {
246 	struct dev_filter *f;
247 
248 	if (!(f = dm_malloc(sizeof(struct dev_filter)))) {
249 		log_error("LVM type filter allocation failed");
250 		return NULL;
251 	}
252 
253 	f->passes_filter = _passes_lvm_type_device_filter;
254 	f->destroy = lvm_type_filter_destroy;
255 	f->private = NULL;
256 
257 	if (!_scan_dev(cn)) {
258 		dm_free(f);
259 		return_NULL;
260 	}
261 
262 	return f;
263 }
264 
lvm_type_filter_destroy(struct dev_filter * f)265 void lvm_type_filter_destroy(struct dev_filter *f)
266 {
267 	dm_free(f);
268 	return;
269 }
270