Revision cd831bd7 qemu-nbd.c
b/qemu-nbd.c | ||
---|---|---|
1 |
/*\
|
|
1 |
/* |
|
2 | 2 |
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws> |
3 | 3 |
* |
4 | 4 |
* Network Block Device |
... | ... | |
25 | 25 |
#include <stdio.h> |
26 | 26 |
#include <getopt.h> |
27 | 27 |
#include <err.h> |
28 |
#include <sys/types.h> |
|
28 | 29 |
#include <sys/socket.h> |
29 | 30 |
#include <netinet/in.h> |
30 | 31 |
#include <netinet/tcp.h> |
31 | 32 |
#include <arpa/inet.h> |
33 |
#include <signal.h> |
|
34 |
|
|
35 |
#define SOCKET_PATH "/var/lock/qemu-nbd-%s" |
|
32 | 36 |
|
33 | 37 |
int verbose; |
34 | 38 |
|
... | ... | |
41 | 45 |
" -p, --port=PORT port to listen on (default `1024')\n" |
42 | 46 |
" -o, --offset=OFFSET offset into the image\n" |
43 | 47 |
" -b, --bind=IFACE interface to bind to (default `0.0.0.0')\n" |
48 |
" -k, --socket=PATH path to the unix socket\n" |
|
49 |
" (default '"SOCKET_PATH"')\n" |
|
44 | 50 |
" -r, --read-only export read-only\n" |
45 | 51 |
" -P, --partition=NUM only expose partition NUM\n" |
52 |
" -c, --connect=DEV connect FILE to the local NBD device DEV\n" |
|
53 |
" -d, --disconnect disconnect the specified device\n" |
|
46 | 54 |
" -v, --verbose display extra debugging information\n" |
47 | 55 |
" -h, --help display this help and exit\n" |
48 | 56 |
" -V, --version output version information and exit\n" |
49 | 57 |
"\n" |
50 | 58 |
"Report bugs to <anthony@codemonkey.ws>\n" |
51 |
, name); |
|
59 |
, name, "DEVICE");
|
|
52 | 60 |
} |
53 | 61 |
|
54 | 62 |
static void version(const char *name) |
... | ... | |
144 | 152 |
return -1; |
145 | 153 |
} |
146 | 154 |
|
155 |
static void show_parts(const char *device) |
|
156 |
{ |
|
157 |
if (fork() == 0) { |
|
158 |
int nbd; |
|
159 |
|
|
160 |
/* linux just needs an open() to trigger |
|
161 |
* the partition table update |
|
162 |
* but remember to load the module with max_part != 0 : |
|
163 |
* modprobe nbd max_part=63 |
|
164 |
*/ |
|
165 |
nbd = open(device, O_RDWR); |
|
166 |
if (nbd != -1) |
|
167 |
close(nbd); |
|
168 |
exit(0); |
|
169 |
} |
|
170 |
} |
|
171 |
|
|
147 | 172 |
int main(int argc, char **argv) |
148 | 173 |
{ |
149 | 174 |
BlockDriverState *bs; |
150 | 175 |
off_t dev_offset = 0; |
151 | 176 |
off_t offset = 0; |
152 | 177 |
bool readonly = false; |
178 |
bool disconnect = false; |
|
153 | 179 |
const char *bindto = "0.0.0.0"; |
154 | 180 |
int port = 1024; |
155 | 181 |
int sock, csock; |
156 | 182 |
struct sockaddr_in addr; |
157 | 183 |
socklen_t addr_len = sizeof(addr); |
158 | 184 |
off_t fd_size; |
159 |
const char *sopt = "hVbo:p:rsP:v"; |
|
185 |
char *device = NULL; |
|
186 |
char *socket = NULL; |
|
187 |
char sockpath[128]; |
|
188 |
const char *sopt = "hVbo:p:rsP:c:dvk:"; |
|
160 | 189 |
struct option lopt[] = { |
161 | 190 |
{ "help", 0, 0, 'h' }, |
162 | 191 |
{ "version", 0, 0, 'V' }, |
163 | 192 |
{ "bind", 1, 0, 'b' }, |
164 | 193 |
{ "port", 1, 0, 'p' }, |
194 |
{ "socket", 1, 0, 'k' }, |
|
165 | 195 |
{ "offset", 1, 0, 'o' }, |
166 | 196 |
{ "read-only", 0, 0, 'r' }, |
167 | 197 |
{ "partition", 1, 0, 'P' }, |
198 |
{ "connect", 1, 0, 'c' }, |
|
199 |
{ "disconnect", 0, 0, 'd' }, |
|
168 | 200 |
{ "snapshot", 0, 0, 's' }, |
169 | 201 |
{ "verbose", 0, 0, 'v' }, |
170 | 202 |
{ NULL, 0, 0, 0 } |
... | ... | |
175 | 207 |
char *end; |
176 | 208 |
bool snapshot = false; |
177 | 209 |
int partition = -1; |
210 |
int fd; |
|
211 |
int ret; |
|
178 | 212 |
|
179 | 213 |
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { |
180 | 214 |
switch (ch) { |
... | ... | |
213 | 247 |
if (partition < 1 || partition > 8) |
214 | 248 |
errx(EINVAL, "Invalid partition %d", partition); |
215 | 249 |
break; |
250 |
case 'k': |
|
251 |
socket = optarg; |
|
252 |
if (socket[0] != '/') |
|
253 |
errx(EINVAL, "socket path must be absolute\n"); |
|
254 |
break; |
|
255 |
case 'd': |
|
256 |
disconnect = true; |
|
257 |
break; |
|
258 |
case 'c': |
|
259 |
device = optarg; |
|
260 |
break; |
|
216 | 261 |
case 'v': |
217 | 262 |
verbose = 1; |
218 | 263 |
break; |
... | ... | |
236 | 281 |
argv[0]); |
237 | 282 |
} |
238 | 283 |
|
284 |
if (disconnect) { |
|
285 |
fd = open(argv[optind], O_RDWR); |
|
286 |
if (fd == -1) |
|
287 |
errx(errno, "Cannot open %s", argv[optind]); |
|
288 |
|
|
289 |
nbd_disconnect(fd); |
|
290 |
|
|
291 |
close(fd); |
|
292 |
|
|
293 |
printf("%s disconnected\n", argv[optind]); |
|
294 |
|
|
295 |
return 0; |
|
296 |
} |
|
297 |
|
|
239 | 298 |
bdrv_init(); |
240 | 299 |
|
241 | 300 |
bs = bdrv_new("hda"); |
... | ... | |
251 | 310 |
find_partition(bs, partition, &dev_offset, &fd_size)) |
252 | 311 |
errx(errno, "Could not find partition %d", partition); |
253 | 312 |
|
254 |
sock = tcp_socket_incoming(bindto, port); |
|
313 |
if (device) { |
|
314 |
pid_t pid; |
|
315 |
if (!verbose) |
|
316 |
daemon(0, 0); /* detach client and server */ |
|
317 |
|
|
318 |
if (socket == NULL) { |
|
319 |
sprintf(sockpath, SOCKET_PATH, basename(device)); |
|
320 |
socket = sockpath; |
|
321 |
} |
|
322 |
|
|
323 |
pid = fork(); |
|
324 |
if (pid < 0) |
|
325 |
return 1; |
|
326 |
if (pid != 0) { |
|
327 |
off_t size; |
|
328 |
size_t blocksize; |
|
329 |
|
|
330 |
ret = 0; |
|
331 |
bdrv_close(bs); |
|
332 |
|
|
333 |
do { |
|
334 |
sock = unix_socket_outgoing(socket); |
|
335 |
if (sock == -1) { |
|
336 |
if (errno != ENOENT && errno != ECONNREFUSED) |
|
337 |
goto out; |
|
338 |
sleep(1); /* wait children */ |
|
339 |
} |
|
340 |
} while (sock == -1); |
|
341 |
|
|
342 |
fd = open(device, O_RDWR); |
|
343 |
if (fd == -1) { |
|
344 |
ret = 1; |
|
345 |
goto out; |
|
346 |
} |
|
347 |
|
|
348 |
ret = nbd_receive_negotiate(sock, &size, &blocksize); |
|
349 |
if (ret == -1) { |
|
350 |
ret = 1; |
|
351 |
goto out; |
|
352 |
} |
|
353 |
|
|
354 |
ret = nbd_init(fd, sock, size, blocksize); |
|
355 |
if (ret == -1) { |
|
356 |
ret = 1; |
|
357 |
goto out; |
|
358 |
} |
|
359 |
|
|
360 |
printf("NBD device %s is now connected to file %s\n", |
|
361 |
device, argv[optind]); |
|
362 |
|
|
363 |
/* update partition table */ |
|
364 |
|
|
365 |
show_parts(device); |
|
366 |
|
|
367 |
nbd_client(fd, sock); |
|
368 |
close(fd); |
|
369 |
out: |
|
370 |
kill(pid, SIGTERM); |
|
371 |
unlink(socket); |
|
372 |
|
|
373 |
return ret; |
|
374 |
} |
|
375 |
/* children */ |
|
376 |
} |
|
377 |
|
|
378 |
if (socket) { |
|
379 |
sock = unix_socket_incoming(socket); |
|
380 |
} else { |
|
381 |
sock = tcp_socket_incoming(bindto, port); |
|
382 |
} |
|
383 |
|
|
255 | 384 |
if (sock == -1) |
256 | 385 |
return 1; |
257 | 386 |
|
... | ... | |
270 | 399 |
close(csock); |
271 | 400 |
close(sock); |
272 | 401 |
bdrv_close(bs); |
402 |
if (socket) |
|
403 |
unlink(socket); |
|
273 | 404 |
|
274 | 405 |
return 0; |
275 | 406 |
} |
Also available in: Unified diff