1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include "libbb.h"
17#include <netinet/tcp.h>
18#include <linux/fs.h>
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45int nbdclient_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
46int nbdclient_main(int argc UNUSED_PARAM, 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;
55 uint64_t magic2;
56 uint64_t devsize;
57 uint32_t flags;
58 char data[124];
59 } nbd_header;
60
61 BUILD_BUG_ON(offsetof(struct nbd_header_t, data) != 8+8+8+4);
62
63
64 if (!argv[1] || !argv[2] || !argv[3] || argv[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
76 for (;;) {
77 int sock, nbd;
78 int ro;
79
80
81 nbd = xopen(device, O_RDWR);
82
83
84 sock = create_and_connect_stream_or_die(host, xatou16(port));
85 setsockopt_1(sock, IPPROTO_TCP, TCP_NODELAY);
86
87
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
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
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
109
110#if BB_MMU
111
112
113
114 if (fork() == 0) {
115 char *s = strrchr(device, '/');
116 sprintf(nbd_header.data, "/sys/block/%.32s/pid", s ? s + 1 : device);
117
118 for (;;) {
119 int fd = open(nbd_header.data, O_RDONLY);
120 if (fd >= 0) {
121
122 break;
123 }
124 sleep(1);
125 }
126 open(device, O_RDONLY);
127 return 0;
128 }
129
130
131 if (!nofork) {
132 daemon(0, 0);
133 nofork = 1;
134 }
135#endif
136
137
138
139
140
141
142 if (ioctl(nbd, NBD_DO_IT) >= 0 || errno == EBADR) {
143
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}
155