1
2
3
4
5
6#include "libbb.h"
7#include <netinet/tcp.h>
8#include <linux/fs.h>
9
10
11
12
13
14
15
16
17
18
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, 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 struct bug_check {
61 char c[offsetof(struct nbd_header_t, data) == 8+8+8+4 ? 1 : -1];
62 };
63
64
65 if (argc != 4)
66 bb_show_usage();
67
68#if !BB_MMU
69 bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
70#endif
71
72 host = argv[1];
73 port = argv[2];
74 device = argv[3];
75
76
77 for (;;) {
78 int sock, nbd;
79 int ro;
80
81
82 nbd = xopen(device, O_RDWR);
83
84
85 sock = create_and_connect_stream_or_die(host, xatou16(port));
86 setsockopt_1(sock, IPPROTO_TCP, TCP_NODELAY);
87
88
89 xread(sock, &nbd_header, 8+8+8+4 + 124);
90 if (memcmp(&nbd_header.magic1, "NBDMAGIC""\x00\x00\x42\x02\x81\x86\x12\x53", 16) != 0)
91 bb_error_msg_and_die("login failed");
92
93
94 ioctl(nbd, NBD_SET_BLKSIZE, 4096);
95 ioctl(nbd, NBD_SET_SIZE_BLOCKS, SWAP_BE64(nbd_header.devsize) / 4096);
96 ioctl(nbd, NBD_CLEAR_SOCK);
97
98
99 ro = (nbd_header.flags & SWAP_BE32(2)) / SWAP_BE32(2);
100 if (ioctl(nbd, BLKROSET, &ro) < 0)
101 bb_perror_msg_and_die("BLKROSET");
102
103 if (timeout)
104 if (ioctl(nbd, NBD_SET_TIMEOUT, timeout))
105 bb_perror_msg_and_die("NBD_SET_TIMEOUT");
106 if (ioctl(nbd, NBD_SET_SOCK, sock))
107 bb_perror_msg_and_die("NBD_SET_SOCK");
108
109
110
111#if BB_MMU
112
113
114
115 if (fork() == 0) {
116 char *s = strrchr(device, '/');
117 sprintf(nbd_header.data, "/sys/block/%.32s/pid", s ? s + 1 : device);
118
119 for (;;) {
120 int fd = open(nbd_header.data, O_RDONLY);
121 if (fd >= 0) {
122
123 break;
124 }
125 sleep(1);
126 }
127 open(device, O_RDONLY);
128 return 0;
129 }
130
131
132 if (!nofork) {
133 daemon(0, 0);
134 nofork = 1;
135 }
136#endif
137
138
139
140
141
142
143 if (ioctl(nbd, NBD_DO_IT) >= 0 || errno == EBADR) {
144
145 ioctl(nbd, NBD_CLEAR_QUEUE);
146 ioctl(nbd, NBD_CLEAR_SOCK);
147 break;
148 }
149
150 close(sock);
151 close(nbd);
152 }
153
154 return 0;
155}
156