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