55 |
55 |
" -n, --nocache disable host cache\n"
|
56 |
56 |
" -c, --connect=DEV connect FILE to the local NBD device DEV\n"
|
57 |
57 |
" -d, --disconnect disconnect the specified device\n"
|
|
58 |
" -e, --shared=NUM device can be shared by NUM clients (default '1')\n"
|
58 |
59 |
" -v, --verbose display extra debugging information\n"
|
59 |
60 |
" -h, --help display this help and exit\n"
|
60 |
61 |
" -V, --version output version information and exit\n"
|
... | ... | |
182 |
183 |
bool disconnect = false;
|
183 |
184 |
const char *bindto = "0.0.0.0";
|
184 |
185 |
int port = 1024;
|
185 |
|
int sock, csock;
|
186 |
186 |
struct sockaddr_in addr;
|
187 |
187 |
socklen_t addr_len = sizeof(addr);
|
188 |
188 |
off_t fd_size;
|
189 |
189 |
char *device = NULL;
|
190 |
190 |
char *socket = NULL;
|
191 |
191 |
char sockpath[128];
|
192 |
|
const char *sopt = "hVbo:p:rsnP:c:dvk:";
|
|
192 |
const char *sopt = "hVbo:p:rsnP:c:dvk:e:";
|
193 |
193 |
struct option lopt[] = {
|
194 |
194 |
{ "help", 0, 0, 'h' },
|
195 |
195 |
{ "version", 0, 0, 'V' },
|
... | ... | |
203 |
203 |
{ "disconnect", 0, 0, 'd' },
|
204 |
204 |
{ "snapshot", 0, 0, 's' },
|
205 |
205 |
{ "nocache", 0, 0, 'n' },
|
|
206 |
{ "shared", 1, 0, 'e' },
|
206 |
207 |
{ "verbose", 0, 0, 'v' },
|
207 |
208 |
{ NULL, 0, 0, 0 }
|
208 |
209 |
};
|
... | ... | |
212 |
213 |
char *end;
|
213 |
214 |
int flags = 0;
|
214 |
215 |
int partition = -1;
|
215 |
|
int fd;
|
216 |
216 |
int ret;
|
|
217 |
int shared = 1;
|
217 |
218 |
uint8_t *data;
|
|
219 |
fd_set fds;
|
|
220 |
int *sharing_fds;
|
|
221 |
int fd;
|
|
222 |
int i;
|
|
223 |
int nb_fds = 0;
|
|
224 |
int max_fd;
|
218 |
225 |
|
219 |
226 |
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
|
220 |
227 |
switch (ch) {
|
... | ... | |
267 |
274 |
case 'c':
|
268 |
275 |
device = optarg;
|
269 |
276 |
break;
|
|
277 |
case 'e':
|
|
278 |
shared = strtol(optarg, &end, 0);
|
|
279 |
if (*end) {
|
|
280 |
errx(EINVAL, "Invalid shared device number '%s'", optarg);
|
|
281 |
}
|
|
282 |
if (shared < 1) {
|
|
283 |
errx(EINVAL, "Shared device number must be greater than 0\n");
|
|
284 |
}
|
|
285 |
break;
|
270 |
286 |
case 'v':
|
271 |
287 |
verbose = 1;
|
272 |
288 |
break;
|
... | ... | |
320 |
336 |
errx(errno, "Could not find partition %d", partition);
|
321 |
337 |
|
322 |
338 |
if (device) {
|
323 |
|
pid_t pid;
|
324 |
|
if (!verbose)
|
|
339 |
pid_t pid;
|
|
340 |
int sock;
|
|
341 |
|
|
342 |
if (!verbose)
|
325 |
343 |
daemon(0, 0); /* detach client and server */
|
326 |
344 |
|
327 |
345 |
if (socket == NULL) {
|
... | ... | |
384 |
402 |
/* children */
|
385 |
403 |
}
|
386 |
404 |
|
|
405 |
sharing_fds = qemu_malloc((shared + 1) * sizeof(int));
|
|
406 |
if (sharing_fds == NULL)
|
|
407 |
errx(ENOMEM, "Cannot allocate sharing fds");
|
|
408 |
|
387 |
409 |
if (socket) {
|
388 |
|
sock = unix_socket_incoming(socket);
|
|
410 |
sharing_fds[0] = unix_socket_incoming(socket);
|
389 |
411 |
} else {
|
390 |
|
sock = tcp_socket_incoming(bindto, port);
|
|
412 |
sharing_fds[0] = tcp_socket_incoming(bindto, port);
|
391 |
413 |
}
|
392 |
414 |
|
393 |
|
if (sock == -1)
|
|
415 |
if (sharing_fds[0] == -1)
|
394 |
416 |
return 1;
|
|
417 |
max_fd = sharing_fds[0];
|
|
418 |
nb_fds++;
|
395 |
419 |
|
396 |
|
csock = accept(sock,
|
397 |
|
(struct sockaddr *)&addr,
|
398 |
|
&addr_len);
|
399 |
|
if (csock == -1)
|
400 |
|
return 1;
|
|
420 |
data = qemu_memalign(512, NBD_BUFFER_SIZE);
|
|
421 |
if (data == NULL)
|
|
422 |
errx(ENOMEM, "Cannot allocate data buffer");
|
401 |
423 |
|
402 |
|
/* new fd_size is calculated by find_partition */
|
403 |
|
if (nbd_negotiate(bs, csock, fd_size) == -1)
|
404 |
|
return 1;
|
|
424 |
do {
|
405 |
425 |
|
406 |
|
data = qemu_memalign(512, NBD_BUFFER_SIZE);
|
407 |
|
while (nbd_trip(bs, csock, fd_size, dev_offset, &offset, readonly,
|
408 |
|
data, NBD_BUFFER_SIZE) == 0);
|
|
426 |
FD_ZERO(&fds);
|
|
427 |
for (i = 0; i < nb_fds; i++)
|
|
428 |
FD_SET(sharing_fds[i], &fds);
|
|
429 |
|
|
430 |
ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
|
|
431 |
if (ret == -1)
|
|
432 |
break;
|
|
433 |
|
|
434 |
if (FD_ISSET(sharing_fds[0], &fds))
|
|
435 |
ret--;
|
|
436 |
for (i = 1; i < nb_fds && ret; i++) {
|
|
437 |
if (FD_ISSET(sharing_fds[i], &fds)) {
|
|
438 |
if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset,
|
|
439 |
&offset, readonly, data, NBD_BUFFER_SIZE) != 0) {
|
|
440 |
close(sharing_fds[i]);
|
|
441 |
nb_fds--;
|
|
442 |
sharing_fds[i] = sharing_fds[nb_fds];
|
|
443 |
i--;
|
|
444 |
}
|
|
445 |
ret--;
|
|
446 |
}
|
|
447 |
}
|
|
448 |
/* new connection ? */
|
|
449 |
if (FD_ISSET(sharing_fds[0], &fds)) {
|
|
450 |
if (nb_fds < shared + 1) {
|
|
451 |
sharing_fds[nb_fds] = accept(sharing_fds[0],
|
|
452 |
(struct sockaddr *)&addr,
|
|
453 |
&addr_len);
|
|
454 |
if (sharing_fds[nb_fds] != -1 &&
|
|
455 |
nbd_negotiate(bs, sharing_fds[nb_fds], fd_size) != -1) {
|
|
456 |
if (sharing_fds[nb_fds] > max_fd)
|
|
457 |
max_fd = sharing_fds[nb_fds];
|
|
458 |
nb_fds++;
|
|
459 |
}
|
|
460 |
}
|
|
461 |
}
|
|
462 |
} while (nb_fds > 1);
|
409 |
463 |
qemu_free(data);
|
410 |
464 |
|
411 |
|
close(csock);
|
412 |
|
close(sock);
|
|
465 |
close(sharing_fds[0]);
|
413 |
466 |
bdrv_close(bs);
|
|
467 |
qemu_free(sharing_fds);
|
414 |
468 |
if (socket)
|
415 |
469 |
unlink(socket);
|
416 |
470 |
|