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