Revision a517e88b qemu-nbd.c
b/qemu-nbd.c | ||
---|---|---|
31 | 31 |
#include <arpa/inet.h> |
32 | 32 |
#include <signal.h> |
33 | 33 |
#include <libgen.h> |
34 |
#include <pthread.h> |
|
34 | 35 |
|
35 | 36 |
#define SOCKET_PATH "/var/lock/qemu-nbd-%s" |
36 | 37 |
|
... | ... | |
38 | 39 |
|
39 | 40 |
static int sigterm_wfd; |
40 | 41 |
static int verbose; |
42 |
static char *device; |
|
43 |
static char *srcpath; |
|
44 |
static char *sockpath; |
|
41 | 45 |
|
42 | 46 |
static void usage(const char *name) |
43 | 47 |
{ |
... | ... | |
172 | 176 |
} |
173 | 177 |
} |
174 | 178 |
|
175 |
static void show_parts(const char *device)
|
|
179 |
static void *show_parts(void *arg)
|
|
176 | 180 |
{ |
177 |
if (fork() == 0) { |
|
178 |
int nbd; |
|
181 |
int nbd; |
|
182 |
|
|
183 |
/* linux just needs an open() to trigger |
|
184 |
* the partition table update |
|
185 |
* but remember to load the module with max_part != 0 : |
|
186 |
* modprobe nbd max_part=63 |
|
187 |
*/ |
|
188 |
nbd = open(device, O_RDWR); |
|
189 |
if (nbd != -1) { |
|
190 |
close(nbd); |
|
191 |
} |
|
192 |
return NULL; |
|
193 |
} |
|
179 | 194 |
|
180 |
/* linux just needs an open() to trigger |
|
181 |
* the partition table update |
|
182 |
* but remember to load the module with max_part != 0 : |
|
183 |
* modprobe nbd max_part=63 |
|
184 |
*/ |
|
185 |
nbd = open(device, O_RDWR); |
|
186 |
if (nbd != -1) |
|
187 |
close(nbd); |
|
188 |
exit(0); |
|
195 |
static void *nbd_client_thread(void *arg) |
|
196 |
{ |
|
197 |
int fd = *(int *)arg; |
|
198 |
off_t size; |
|
199 |
size_t blocksize; |
|
200 |
uint32_t nbdflags; |
|
201 |
int sock; |
|
202 |
int ret; |
|
203 |
pthread_t show_parts_thread; |
|
204 |
|
|
205 |
do { |
|
206 |
sock = unix_socket_outgoing(sockpath); |
|
207 |
if (sock == -1) { |
|
208 |
if (errno != ENOENT && errno != ECONNREFUSED) { |
|
209 |
goto out; |
|
210 |
} |
|
211 |
sleep(1); /* wait parent */ |
|
212 |
} |
|
213 |
} while (sock == -1); |
|
214 |
|
|
215 |
ret = nbd_receive_negotiate(sock, NULL, &nbdflags, |
|
216 |
&size, &blocksize); |
|
217 |
if (ret == -1) { |
|
218 |
goto out; |
|
219 |
} |
|
220 |
|
|
221 |
ret = nbd_init(fd, sock, nbdflags, size, blocksize); |
|
222 |
if (ret == -1) { |
|
223 |
goto out; |
|
224 |
} |
|
225 |
|
|
226 |
/* update partition table */ |
|
227 |
pthread_create(&show_parts_thread, NULL, show_parts, NULL); |
|
228 |
|
|
229 |
fprintf(stderr, "NBD device %s is now connected to %s\n", |
|
230 |
device, srcpath); |
|
231 |
|
|
232 |
ret = nbd_client(fd); |
|
233 |
if (ret) { |
|
234 |
goto out; |
|
189 | 235 |
} |
236 |
close(fd); |
|
237 |
kill(getpid(), SIGTERM); |
|
238 |
return (void *) EXIT_SUCCESS; |
|
239 |
|
|
240 |
out: |
|
241 |
kill(getpid(), SIGTERM); |
|
242 |
return (void *) EXIT_FAILURE; |
|
190 | 243 |
} |
191 | 244 |
|
192 | 245 |
int main(int argc, char **argv) |
... | ... | |
201 | 254 |
struct sockaddr_in addr; |
202 | 255 |
socklen_t addr_len = sizeof(addr); |
203 | 256 |
off_t fd_size; |
204 |
char *device = NULL; |
|
205 |
char *sockpath = NULL; |
|
206 | 257 |
const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t"; |
207 | 258 |
struct option lopt[] = { |
208 | 259 |
{ "help", 0, NULL, 'h' }, |
... | ... | |
238 | 289 |
int nb_fds = 0; |
239 | 290 |
int max_fd; |
240 | 291 |
int persistent = 0; |
292 |
pthread_t client_thread; |
|
241 | 293 |
|
242 |
/* Set up a SIGTERM handler so that we exit with a nice status code. */ |
|
294 |
/* The client thread uses SIGTERM to interrupt the server. A signal |
|
295 |
* handler ensures that "qemu-nbd -v -c" exits with a nice status code. |
|
296 |
*/ |
|
243 | 297 |
struct sigaction sa_sigterm; |
244 | 298 |
int sigterm_fd[2]; |
245 | 299 |
if (qemu_pipe(sigterm_fd) == -1) { |
... | ... | |
356 | 410 |
|
357 | 411 |
bs = bdrv_new("hda"); |
358 | 412 |
|
359 |
if ((ret = bdrv_open(bs, argv[optind], flags, NULL)) < 0) { |
|
413 |
srcpath = argv[optind]; |
|
414 |
if ((ret = bdrv_open(bs, srcpath, flags, NULL)) < 0) { |
|
360 | 415 |
errno = -ret; |
361 |
err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
|
|
416 |
err(EXIT_FAILURE, "Failed to bdrv_open '%s'", srcpath);
|
|
362 | 417 |
} |
363 | 418 |
|
364 | 419 |
fd_size = bs->total_sectors * 512; |
... | ... | |
368 | 423 |
err(EXIT_FAILURE, "Could not find partition %d", partition); |
369 | 424 |
|
370 | 425 |
if (device) { |
371 |
pid_t pid; |
|
372 |
int sock; |
|
426 |
int ret; |
|
373 | 427 |
|
374 |
/* want to fail before daemonizing */ |
|
375 |
if (access(device, R_OK|W_OK) == -1) { |
|
376 |
err(EXIT_FAILURE, "Could not access '%s'", device); |
|
428 |
/* Open before spawning new threads. In the future, we may |
|
429 |
* drop privileges after opening. |
|
430 |
*/ |
|
431 |
fd = open(device, O_RDWR); |
|
432 |
if (fd == -1) { |
|
433 |
err(EXIT_FAILURE, "Failed to open %s", device); |
|
377 | 434 |
} |
378 | 435 |
|
379 | 436 |
if (!verbose) { |
... | ... | |
388 | 445 |
snprintf(sockpath, 128, SOCKET_PATH, basename(device)); |
389 | 446 |
} |
390 | 447 |
|
391 |
pid = fork(); |
|
392 |
if (pid < 0) |
|
393 |
return 1; |
|
394 |
if (pid != 0) { |
|
395 |
off_t size; |
|
396 |
size_t blocksize; |
|
397 |
|
|
398 |
ret = 0; |
|
399 |
bdrv_close(bs); |
|
400 |
|
|
401 |
do { |
|
402 |
sock = unix_socket_outgoing(sockpath); |
|
403 |
if (sock == -1) { |
|
404 |
if (errno != ENOENT && errno != ECONNREFUSED) { |
|
405 |
ret = 1; |
|
406 |
goto out; |
|
407 |
} |
|
408 |
sleep(1); /* wait children */ |
|
409 |
} |
|
410 |
} while (sock == -1); |
|
411 |
|
|
412 |
fd = open(device, O_RDWR); |
|
413 |
if (fd == -1) { |
|
414 |
ret = 1; |
|
415 |
goto out; |
|
416 |
} |
|
417 |
|
|
418 |
ret = nbd_receive_negotiate(sock, NULL, &nbdflags, |
|
419 |
&size, &blocksize); |
|
420 |
if (ret == -1) { |
|
421 |
ret = 1; |
|
422 |
goto out; |
|
423 |
} |
|
424 |
|
|
425 |
ret = nbd_init(fd, sock, nbdflags, size, blocksize); |
|
426 |
if (ret == -1) { |
|
427 |
ret = 1; |
|
428 |
goto out; |
|
429 |
} |
|
430 |
|
|
431 |
printf("NBD device %s is now connected to file %s\n", |
|
432 |
device, argv[optind]); |
|
433 |
|
|
434 |
/* update partition table */ |
|
435 |
|
|
436 |
show_parts(device); |
|
437 |
|
|
438 |
ret = nbd_client(fd); |
|
439 |
if (ret) { |
|
440 |
ret = 1; |
|
441 |
} |
|
442 |
close(fd); |
|
443 |
out: |
|
444 |
kill(pid, SIGTERM); |
|
445 |
|
|
446 |
return ret; |
|
448 |
ret = pthread_create(&client_thread, NULL, nbd_client_thread, &fd); |
|
449 |
if (ret != 0) { |
|
450 |
errx(EXIT_FAILURE, "Failed to create client thread: %s", |
|
451 |
strerror(ret)); |
|
447 | 452 |
} |
448 |
/* children */ |
|
453 |
} else { |
|
454 |
/* Shut up GCC warnings. */ |
|
455 |
memset(&client_thread, 0, sizeof(client_thread)); |
|
449 | 456 |
} |
450 | 457 |
|
451 | 458 |
sharing_fds = g_malloc((shared + 1) * sizeof(int)); |
... | ... | |
517 | 524 |
unlink(sockpath); |
518 | 525 |
} |
519 | 526 |
|
520 |
return 0; |
|
527 |
if (device) { |
|
528 |
void *ret; |
|
529 |
pthread_join(client_thread, &ret); |
|
530 |
exit(ret != NULL); |
|
531 |
} else { |
|
532 |
exit(EXIT_SUCCESS); |
|
533 |
} |
|
521 | 534 |
} |
Also available in: Unified diff