Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : #ifdef HAVE_CONFIG_H
32 : : #include "config.h"
33 : : #endif
34 : :
35 : : #include <stdio.h>
36 : : #include <errno.h>
37 : : #include <fcntl.h>
38 : : #include <stdlib.h>
39 : : #include <unistd.h>
40 : : #include <string.h>
41 : : #include <getopt.h>
42 : : #include <libgen.h>
43 : : #include <sys/file.h>
44 : : #include <sys/stat.h>
45 : : #include <sys/sysmacros.h>
46 : : #include <sys/types.h>
47 : : #include <sys/ioctl.h>
48 : : #include <linux/major.h>
49 : :
50 : : #include "tap-ctl.h"
51 : : #include "blktap2.h"
52 : :
53 : : static int
54 : 15 : tap_ctl_prepare_directory(const char *dir)
55 : : {
56 : : int err;
57 : : char *ptr, *name, *start;
58 : :
59 : 15 : err = access(dir, W_OK | R_OK);
60 [ + + ]: 15 : if (!err)
61 : : return 0;
62 : :
63 : 7 : name = strdup(dir);
64 [ + - ]: 7 : if (!name)
65 : : return ENOMEM;
66 : :
67 : : start = name;
68 : :
69 : : for (;;) {
70 : 21 : ptr = strchr(start + 1, '/');
71 [ + + ]: 21 : if (ptr)
72 : 14 : *ptr = '\0';
73 : :
74 : 21 : err = mkdir(name, 0755);
75 [ + + ][ + + ]: 21 : if (err && errno != EEXIST) {
76 : 1 : PERROR("mkdir %s", name);
77 : 1 : err = errno;
78 : : EPRINTF("mkdir failed with %d\n", err);
79 : : break;
80 : : }
81 : :
82 : 20 : err = 0;
83 : :
84 [ + + ]: 20 : if (!ptr)
85 : : break;
86 : : else {
87 : 14 : *ptr = '/';
88 : 14 : start = ptr + 1;
89 : : }
90 : 14 : }
91 : :
92 : 7 : free(name);
93 : 7 : return err;
94 : : }
95 : :
96 : : static int
97 : 9 : tap_ctl_make_device(const char *devname, const int major,
98 : : const int minor, const int perm)
99 : : {
100 : : int err;
101 : : char *copy, *dir;
102 : :
103 : 9 : copy = strdup(devname);
104 [ + - ]: 9 : if (!copy)
105 : : return ENOMEM;
106 : :
107 : 9 : dir = dirname(copy);
108 : :
109 : 9 : err = tap_ctl_prepare_directory(dir);
110 : 9 : free(copy);
111 : :
112 [ + - ]: 9 : if (err)
113 : : return err;
114 : :
115 [ - + ]: 9 : if (unlink(devname)) {
116 : 0 : err = errno;
117 [ # # ]: 0 : if (err != ENOENT) {
118 : 0 : PERROR("unlink %s", devname);
119 : : EPRINTF("Unlink failed with %d\n", err);
120 : 0 : return err;
121 : : }
122 : : }
123 : :
124 : 27 : err = mknod(devname, perm, makedev(major, minor));
125 [ + + ]: 9 : if (err) {
126 : 3 : err = errno;
127 : 3 : PERROR("mknod %s", devname);
128 : : EPRINTF("Mknod failed with %d\n", err);
129 : 3 : return err;
130 : : }
131 : :
132 : : return 0;
133 : : }
134 : :
135 : : static int
136 : 6 : tap_ctl_check_environment(void)
137 : : {
138 : : FILE *f;
139 : : int err, minor;
140 : : char name[257];
141 : :
142 : 6 : err = tap_ctl_prepare_directory(BLKTAP2_CONTROL_DIR);
143 [ + + ]: 6 : if (err) {
144 : : EPRINTF("Prepare directory failed %d", err);
145 : 6 : return err;
146 : : }
147 : :
148 : 5 : f = fopen("/proc/misc", "r");
149 [ - + ]: 5 : if (!f) {
150 : 0 : EPRINTF("failed to open /proc/misc: %d\n", errno);
151 : 0 : return errno;
152 : : }
153 : : /* There is not a lot we can do about an error returned
154 : : * from flock() so don't check */
155 : 5 : flock(fileno(f), LOCK_EX);
156 : :
157 : : /* Note err is 0 owing to tap_ctl_prepare_directory() above */
158 [ + - ]: 5 : if (!access(BLKTAP2_CONTROL_DEVICE, R_OK | W_OK))
159 : : goto out;
160 : :
161 : : memset(name, 0, sizeof(name));
162 : :
163 [ + + ]: 135 : while (fscanf(f, "%d %256s", &minor, name) == 2)
164 [ + + ]: 134 : if (!strcmp(name, BLKTAP2_CONTROL_NAME)) {
165 : 4 : err = tap_ctl_make_device(BLKTAP2_CONTROL_DEVICE,
166 : : MISC_MAJOR,
167 : : minor, S_IFCHR | 0600);
168 [ + + ]: 4 : if (err)
169 : : EPRINTF("tap_ctl_make_device failed\n");
170 : : goto out;
171 : : }
172 : :
173 : 1 : err = ENOSYS;
174 : : EPRINTF("didn't find %s in /proc/misc\n", BLKTAP2_CONTROL_NAME);
175 : :
176 : : out:
177 : 5 : flock(fileno(f), LOCK_UN);
178 : 5 : fclose(f);
179 : : return err;
180 : : }
181 : :
182 : : static int
183 : 3 : tap_ctl_allocate_device(int *minor, char **devname)
184 : : {
185 : : char *name;
186 : : int fd, err;
187 : : struct blktap2_handle handle;
188 : 3 : char free_devname = 0;
189 : :
190 : 3 : *minor = -1;
191 [ + - ]: 3 : if (!devname)
192 : 3 : return EINVAL;
193 : :
194 : 3 : fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY);
195 [ - + ]: 3 : if (fd == -1) {
196 : 0 : EPRINTF("failed to open control device: %d\n", errno);
197 : 0 : return errno;
198 : : }
199 : :
200 : 3 : err = ioctl(fd, BLKTAP2_IOCTL_ALLOC_TAP, &handle);
201 : 3 : close(fd);
202 [ - + ]: 3 : if (err == -1) {
203 : 0 : EPRINTF("failed to allocate new device: %d\n", errno);
204 : 0 : return errno;
205 : : }
206 : :
207 : 6 : err = asprintf(&name, "%s%d", BLKTAP2_RING_DEVICE, handle.minor);
208 [ + - ]: 3 : if (err == -1) {
209 : : err = ENOMEM;
210 : : goto fail;
211 : : }
212 : :
213 : 3 : err = tap_ctl_make_device(name, handle.ring,
214 : 3 : handle.minor, S_IFCHR | 0600);
215 : 3 : free(name);
216 [ + + ]: 3 : if (err) {
217 : 1 : EPRINTF("creating ring device for %d failed: %d\n",
218 : : handle.minor, err);
219 : : goto fail;
220 : : }
221 : :
222 [ - + ]: 2 : if (*devname)
223 : 0 : name = *devname;
224 : : else {
225 : 4 : err = asprintf(&name, "%s%d",
226 : : BLKTAP2_IO_DEVICE, handle.minor);
227 [ + - ]: 2 : if (err == -1) {
228 : : err = ENOMEM;
229 : : goto fail;
230 : : }
231 : 2 : *devname = name;
232 : 2 : free_devname = 1;
233 : : }
234 : :
235 : 2 : err = tap_ctl_make_device(name, handle.device,
236 : 2 : handle.minor, S_IFBLK | 0600);
237 [ + + ]: 2 : if (err) {
238 : 1 : EPRINTF("creating IO device for %d failed: %d\n",
239 : : handle.minor, err);
240 : : goto fail;
241 : : }
242 : :
243 [ - + ]: 1 : DBG("new interface: ring: %u, device: %u, minor: %u\n",
244 : : handle.ring, handle.device, handle.minor);
245 : :
246 : 1 : *minor = handle.minor;
247 : 1 : return 0;
248 : :
249 : : fail:
250 [ + + ]: 2 : if (free_devname) {
251 : 1 : free(*devname);
252 : 1 : *devname = 0;
253 : : }
254 : 2 : tap_ctl_free(handle.minor);
255 : : return err;
256 : : }
257 : :
258 : : int
259 : 6 : tap_ctl_allocate(int *minor, char **devname)
260 : : {
261 : : int err;
262 : :
263 : 6 : *minor = -1;
264 : :
265 : 6 : err = tap_ctl_check_environment();
266 [ + + ]: 6 : if (err) {
267 : : EPRINTF("tap-ctl allocate failed check environment");
268 : 3 : return err;
269 : : }
270 : :
271 : 3 : err = tap_ctl_allocate_device(minor, devname);
272 [ + + ]: 3 : if (err) {
273 : : EPRINTF("tap-ctl allocate failed to allocate device");
274 : 2 : return err;
275 : : }
276 : :
277 : : return 0;
278 : : }
|