source: MondoRescue/branches/3.3/mindi-busybox/networking/nbd-client.c@ 3734

Last change on this file since 3734 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 4.3 KB
RevLine 
[2725]1/*
2 * Copyright 2010 Rob Landley <rob@landley.net>
3 *
4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */
6#include "libbb.h"
7#include <netinet/tcp.h>
8#include <linux/fs.h>
9
[3232]10//applet:IF_NBDCLIENT(APPLET_ODDNAME(nbd-client, nbdclient, BB_DIR_USR_SBIN, BB_SUID_DROP, nbdclient))
[2725]11
12//kbuild:lib-$(CONFIG_NBDCLIENT) += nbd-client.o
13
14//config:config NBDCLIENT
15//config: bool "nbd-client"
16//config: default y
17//config: help
18//config: Network block device client
19
20#define NBD_SET_SOCK _IO(0xab, 0)
21#define NBD_SET_BLKSIZE _IO(0xab, 1)
22#define NBD_SET_SIZE _IO(0xab, 2)
23#define NBD_DO_IT _IO(0xab, 3)
24#define NBD_CLEAR_SOCK _IO(0xab, 4)
25#define NBD_CLEAR_QUEUE _IO(0xab, 5)
26#define NBD_PRINT_DEBUG _IO(0xab, 6)
27#define NBD_SET_SIZE_BLOCKS _IO(0xab, 7)
28#define NBD_DISCONNECT _IO(0xab, 8)
29#define NBD_SET_TIMEOUT _IO(0xab, 9)
30
31//usage:#define nbdclient_trivial_usage
32//usage: "HOST PORT BLOCKDEV"
33//usage:#define nbdclient_full_usage "\n\n"
34//usage: "Connect to HOST and provide a network block device on BLOCKDEV"
35
36//TODO: more compat with nbd-client version 2.9.13 -
37//Usage: nbd-client [bs=blocksize] [timeout=sec] host port nbd_device [-swap] [-persist] [-nofork]
38//Or : nbd-client -d nbd_device
39//Or : nbd-client -c nbd_device
40//Default value for blocksize is 1024 (recommended for ethernet)
41//Allowed values for blocksize are 512,1024,2048,4096
42//Note, that kernel 2.4.2 and older ones do not work correctly with
43//blocksizes other than 1024 without patches
44
45int nbdclient_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
46int nbdclient_main(int argc, char **argv)
47{
48 unsigned long timeout = 0;
49#if BB_MMU
50 int nofork = 0;
51#endif
52 char *host, *port, *device;
53 struct nbd_header_t {
54 uint64_t magic1; // "NBDMAGIC"
55 uint64_t magic2; // 0x420281861253 big endian
56 uint64_t devsize;
57 uint32_t flags;
58 char data[124];
59 } nbd_header;
60
[3621]61 BUILD_BUG_ON(offsetof(struct nbd_header_t, data) != 8+8+8+4);
62
[2725]63 // Parse command line stuff (just a stub now)
64 if (argc != 4)
65 bb_show_usage();
66
67#if !BB_MMU
68 bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
69#endif
70
71 host = argv[1];
72 port = argv[2];
73 device = argv[3];
74
75 // Repeat until spanked (-persist behavior)
76 for (;;) {
77 int sock, nbd;
78 int ro;
79
80 // Make sure the /dev/nbd exists
81 nbd = xopen(device, O_RDWR);
82
83 // Find and connect to server
84 sock = create_and_connect_stream_or_die(host, xatou16(port));
[3621]85 setsockopt_1(sock, IPPROTO_TCP, TCP_NODELAY);
[2725]86
87 // Log on to the server
88 xread(sock, &nbd_header, 8+8+8+4 + 124);
89 if (memcmp(&nbd_header.magic1, "NBDMAGIC""\x00\x00\x42\x02\x81\x86\x12\x53", 16) != 0)
90 bb_error_msg_and_die("login failed");
91
92 // Set 4k block size. Everything uses that these days
93 ioctl(nbd, NBD_SET_BLKSIZE, 4096);
94 ioctl(nbd, NBD_SET_SIZE_BLOCKS, SWAP_BE64(nbd_header.devsize) / 4096);
95 ioctl(nbd, NBD_CLEAR_SOCK);
96
97 // If the sucker was exported read only, respect that locally
98 ro = (nbd_header.flags & SWAP_BE32(2)) / SWAP_BE32(2);
99 if (ioctl(nbd, BLKROSET, &ro) < 0)
100 bb_perror_msg_and_die("BLKROSET");
101
102 if (timeout)
103 if (ioctl(nbd, NBD_SET_TIMEOUT, timeout))
104 bb_perror_msg_and_die("NBD_SET_TIMEOUT");
105 if (ioctl(nbd, NBD_SET_SOCK, sock))
106 bb_perror_msg_and_die("NBD_SET_SOCK");
107
108 // if (swap) mlockall(MCL_CURRENT|MCL_FUTURE);
109
110#if BB_MMU
111 // Open the device to force reread of the partition table.
112 // Need to do it in a separate process, since open(device)
113 // needs some other process to sit in ioctl(nbd, NBD_DO_IT).
114 if (fork() == 0) {
115 char *s = strrchr(device, '/');
116 sprintf(nbd_header.data, "/sys/block/%.32s/pid", s ? s + 1 : device);
117 // Is it up yet?
118 for (;;) {
119 int fd = open(nbd_header.data, O_RDONLY);
120 if (fd >= 0) {
121 //close(fd);
122 break;
123 }
124 sleep(1);
125 }
126 open(device, O_RDONLY);
127 return 0;
128 }
129
130 // Daemonize here
131 if (!nofork) {
132 daemon(0, 0);
133 nofork = 1;
134 }
135#endif
136
137 // This turns us (the process that calls this ioctl)
138 // into a dedicated NBD request handler.
139 // We block here for a long time.
140 // When exactly ioctl returns? On a signal,
141 // or if someone does ioctl(NBD_DISCONNECT) [nbd-client -d].
142 if (ioctl(nbd, NBD_DO_IT) >= 0 || errno == EBADR) {
143 // Flush queue and exit
144 ioctl(nbd, NBD_CLEAR_QUEUE);
145 ioctl(nbd, NBD_CLEAR_SOCK);
146 break;
147 }
148
149 close(sock);
150 close(nbd);
151 }
152
153 return 0;
154}
Note: See TracBrowser for help on using the repository browser.