Statistics
| Branch: | Revision:

root / control / tap-ctl-allocate.c @ abdb293f

History | View | Annotate | Download (5.2 kB)

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

    
29
#ifdef HAVE_CONFIG_H
30
#include "config.h"
31
#endif
32

    
33
#include <stdio.h>
34
#include <errno.h>
35
#include <fcntl.h>
36
#include <stdlib.h>
37
#include <unistd.h>
38
#include <string.h>
39
#include <getopt.h>
40
#include <libgen.h>
41
#include <sys/stat.h>
42
#include <sys/types.h>
43
#include <sys/ioctl.h>
44
#include <linux/major.h>
45

    
46
#include "tap-ctl.h"
47
#include "blktap2.h"
48

    
49
static int
50
tap_ctl_prepare_directory(const char *dir)
51
{
52
        int err;
53
        char *ptr, *name, *start;
54

    
55
        err = access(dir, W_OK | R_OK);
56
        if (!err)
57
                return 0;
58

    
59
        name = strdup(dir);
60
        if (!name)
61
                return ENOMEM;
62

    
63
        start = name;
64

    
65
        for (;;) {
66
                ptr = strchr(start + 1, '/');
67
                if (ptr)
68
                        *ptr = '\0';
69

    
70
                err = mkdir(name, 0755);
71
                if (err && errno != EEXIST) {
72
                        PERROR("mkdir %s", name);
73
                        err = errno;
74
                        break;
75
                }
76

    
77
                if (!ptr)
78
                        break;
79
                else {
80
                        *ptr = '/';
81
                        start = ptr + 1;
82
                }
83
        }
84

    
85
        free(name);
86
        return err;
87
}
88

    
89
static int
90
tap_ctl_make_device(const char *devname, const int major,
91
                    const int minor, const int perm)
92
{
93
        int err;
94
        char *copy, *dir;
95

    
96
        copy = strdup(devname);
97
        if (!copy)
98
                return ENOMEM;
99

    
100
        dir = dirname(copy);
101

    
102
        err = tap_ctl_prepare_directory(dir);
103
        free(copy);
104

    
105
        if (err)
106
                return err;
107

    
108
        if (!access(devname, F_OK))
109
                if (unlink(devname)) {
110
                        PERROR("unlink %s", devname);
111
                        return errno;
112
                }
113

    
114
        err = mknod(devname, perm, makedev(major, minor));
115
        if (err) {
116
                PERROR("mknod %s", devname);
117
                return errno;
118
        }
119

    
120
        return 0;
121
}
122

    
123
static int
124
tap_ctl_check_environment(void)
125
{
126
        FILE *f;
127
        int err, minor;
128
        char name[256];
129

    
130
        err = tap_ctl_prepare_directory(BLKTAP2_CONTROL_DIR);
131
        if (err)
132
                return err;
133

    
134
        if (!access(BLKTAP2_CONTROL_DEVICE, R_OK | W_OK))
135
                return 0;
136

    
137
        memset(name, 0, sizeof(name));
138

    
139
        f = fopen("/proc/misc", "r");
140
        if (!f) {
141
                EPRINTF("failed to open /proc/misc: %d\n", errno);
142
                return errno;
143
        }
144

    
145
        while (fscanf(f, "%d %256s", &minor, name) == 2)
146
                if (!strcmp(name, BLKTAP2_CONTROL_NAME)) {
147
                        err = tap_ctl_make_device(BLKTAP2_CONTROL_DEVICE,
148
                                                  MISC_MAJOR,
149
                                                  minor, S_IFCHR | 0600);
150
                        goto out;
151
                }
152

    
153
        err = ENOSYS;
154
        EPRINTF("didn't find %s in /proc/misc\n", BLKTAP2_CONTROL_NAME);
155

    
156
out:
157
        fclose(f);
158
        return err;
159
}
160

    
161
static int
162
tap_ctl_allocate_device(int *minor, char **devname)
163
{
164
        char *name;
165
        int fd, err;
166
        struct blktap2_handle handle;
167

    
168
        *minor = -1;
169
        if (!devname)
170
                return EINVAL;
171

    
172
        fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY);
173
        if (fd == -1) {
174
                EPRINTF("failed to open control device: %d\n", errno);
175
                return errno;
176
        }
177

    
178
        err = ioctl(fd, BLKTAP2_IOCTL_ALLOC_TAP, &handle);
179
        close(fd);
180
        if (err == -1) {
181
                EPRINTF("failed to allocate new device: %d\n", errno);
182
                return errno;
183
        }
184

    
185
        err = asprintf(&name, "%s%d", BLKTAP2_RING_DEVICE, handle.minor);
186
        if (err == -1) {
187
                err = ENOMEM;
188
                goto fail;
189
        }
190

    
191
        err = tap_ctl_make_device(name, handle.ring,
192
                                  handle.minor, S_IFCHR | 0600);
193
        free(name);
194
        if (err) {
195
                EPRINTF("creating ring device for %d failed: %d\n",
196
                        handle.minor, err);
197
                goto fail;
198
        }
199

    
200
        if (*devname)
201
                name = *devname;
202
        else {
203
                err = asprintf(&name, "%s%d",
204
                               BLKTAP2_IO_DEVICE, handle.minor);
205
                if (err == -1) {
206
                        err = ENOMEM;
207
                        goto fail;
208
                }
209
                *devname = name;
210
        }
211

    
212
        err = tap_ctl_make_device(name, handle.device,
213
                                  handle.minor, S_IFBLK | 0600);
214
        if (err) {
215
                EPRINTF("creating IO device for %d failed: %d\n",
216
                        handle.minor, err);
217
                goto fail;
218
        }
219

    
220
        DBG("new interface: ring: %u, device: %u, minor: %u\n",
221
            handle.ring, handle.device, handle.minor);
222

    
223
        *minor = handle.minor;
224
        return 0;
225

    
226
fail:
227
        tap_ctl_free(handle.minor);
228
        return err;
229
}
230

    
231
int
232
tap_ctl_allocate(int *minor, char **devname)
233
{
234
        int err;
235

    
236
        *minor = -1;
237

    
238
        err = tap_ctl_check_environment();
239
        if (err)
240
                return err;
241

    
242
        err = tap_ctl_allocate_device(minor, devname);
243
        if (err)
244
                return err;
245

    
246
        return 0;
247
}