xref: /aosp_15_r20/external/toybox/toys/other/nbd_server.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1*cf5a6c84SAndroid Build Coastguard Worker /* nbd-server.c - network block device server
2*cf5a6c84SAndroid Build Coastguard Worker  *
3*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2022 Rob Landley <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker  *
5*cf5a6c84SAndroid Build Coastguard Worker  * Not in SUSv4.
6*cf5a6c84SAndroid Build Coastguard Worker  *
7*cf5a6c84SAndroid Build Coastguard Worker  * See https://github.com/NetworkBlockDevice/nbd/blob/master/doc/proto.md
8*cf5a6c84SAndroid Build Coastguard Worker 
9*cf5a6c84SAndroid Build Coastguard Worker // Work around dash in name trying to put - in function name.
10*cf5a6c84SAndroid Build Coastguard Worker USE_NBD_SERVER(NEWTOY(nbd_server, "<1>1r", 0))
11*cf5a6c84SAndroid Build Coastguard Worker USE_NBD_SERVER(OLDTOY(nbd-server, nbd_server, TOYFLAG_USR|TOYFLAG_BIN))
12*cf5a6c84SAndroid Build Coastguard Worker 
13*cf5a6c84SAndroid Build Coastguard Worker config NBD_SERVER
14*cf5a6c84SAndroid Build Coastguard Worker   bool "nbd-server"
15*cf5a6c84SAndroid Build Coastguard Worker   default y
16*cf5a6c84SAndroid Build Coastguard Worker   help
17*cf5a6c84SAndroid Build Coastguard Worker     usage: nbd-server [-r] FILE
18*cf5a6c84SAndroid Build Coastguard Worker 
19*cf5a6c84SAndroid Build Coastguard Worker     Serve a Network Block Device from FILE on stdin/out (ala inetd).
20*cf5a6c84SAndroid Build Coastguard Worker 
21*cf5a6c84SAndroid Build Coastguard Worker     -r	Read only export
22*cf5a6c84SAndroid Build Coastguard Worker */
23*cf5a6c84SAndroid Build Coastguard Worker 
24*cf5a6c84SAndroid Build Coastguard Worker // TODO: -r, block size, exit signal?
25*cf5a6c84SAndroid Build Coastguard Worker 
26*cf5a6c84SAndroid Build Coastguard Worker #define FOR_nbd_server
27*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
28*cf5a6c84SAndroid Build Coastguard Worker 
copy_loop(int from,int to,unsigned len)29*cf5a6c84SAndroid Build Coastguard Worker static int copy_loop(int from, int to, unsigned len)
30*cf5a6c84SAndroid Build Coastguard Worker {
31*cf5a6c84SAndroid Build Coastguard Worker   int try, rc = 0;
32*cf5a6c84SAndroid Build Coastguard Worker 
33*cf5a6c84SAndroid Build Coastguard Worker   errno = 0;
34*cf5a6c84SAndroid Build Coastguard Worker   while (len) {
35*cf5a6c84SAndroid Build Coastguard Worker     xreadall(from, toybuf, try = len>4096 ? 4096 : len);
36*cf5a6c84SAndroid Build Coastguard Worker     if (!rc && try != writeall(to, toybuf, try)) rc = errno;
37*cf5a6c84SAndroid Build Coastguard Worker     len -= try;
38*cf5a6c84SAndroid Build Coastguard Worker   }
39*cf5a6c84SAndroid Build Coastguard Worker 
40*cf5a6c84SAndroid Build Coastguard Worker   return rc;
41*cf5a6c84SAndroid Build Coastguard Worker }
42*cf5a6c84SAndroid Build Coastguard Worker 
nbd_server_main(void)43*cf5a6c84SAndroid Build Coastguard Worker void nbd_server_main(void)
44*cf5a6c84SAndroid Build Coastguard Worker {
45*cf5a6c84SAndroid Build Coastguard Worker   unsigned long long *ll = (void *)toybuf, offset, handle;
46*cf5a6c84SAndroid Build Coastguard Worker   unsigned short *ss = (void *)toybuf;
47*cf5a6c84SAndroid Build Coastguard Worker   unsigned *uu = (void *)toybuf, type, length;
48*cf5a6c84SAndroid Build Coastguard Worker   int fd = xopen(*toys.optargs, O_RDWR*!FLAG(r));
49*cf5a6c84SAndroid Build Coastguard Worker 
50*cf5a6c84SAndroid Build Coastguard Worker   type = 1;
51*cf5a6c84SAndroid Build Coastguard Worker   setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &type, sizeof(int));
52*cf5a6c84SAndroid Build Coastguard Worker 
53*cf5a6c84SAndroid Build Coastguard Worker   // Send original recipe negotiation, with device length and flags
54*cf5a6c84SAndroid Build Coastguard Worker   memcpy(toybuf, "NBDMAGIC\x00\x00\x42\x02\x81\x86\x12\x53", 16);
55*cf5a6c84SAndroid Build Coastguard Worker   ll[2] = SWAP_BE64(fdlength(fd));
56*cf5a6c84SAndroid Build Coastguard Worker   uu[6] = SWAP_BE32(5+2*FLAG(r)); // has flags, can flush, maybe read only
57*cf5a6c84SAndroid Build Coastguard Worker   xwrite(1, toybuf, 152);
58*cf5a6c84SAndroid Build Coastguard Worker 
59*cf5a6c84SAndroid Build Coastguard Worker   // Simple loop, handles one request at a time with "simple" reply.
60*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
61*cf5a6c84SAndroid Build Coastguard Worker     // Fetch request into toybuf
62*cf5a6c84SAndroid Build Coastguard Worker     xreadall(0, toybuf, 28);
63*cf5a6c84SAndroid Build Coastguard Worker     if (SWAP_BE32(*uu) != 0x25609513) break;
64*cf5a6c84SAndroid Build Coastguard Worker     type = SWAP_BE16(ss[3]);
65*cf5a6c84SAndroid Build Coastguard Worker     handle = SWAP_BE64(ll[1]);
66*cf5a6c84SAndroid Build Coastguard Worker     offset = SWAP_BE64(ll[2]);
67*cf5a6c84SAndroid Build Coastguard Worker     length = SWAP_BE32(uu[6]);
68*cf5a6c84SAndroid Build Coastguard Worker 
69*cf5a6c84SAndroid Build Coastguard Worker     // type 0 = read, 1 = write, 2 = disconnect, 3 = flush
70*cf5a6c84SAndroid Build Coastguard Worker     if (type==2 || type>3) break;  // disconnect
71*cf5a6c84SAndroid Build Coastguard Worker     if (type==3) { // flush
72*cf5a6c84SAndroid Build Coastguard Worker       if (fdatasync(fd)) uu[1] = SWAP_BE32(errno);
73*cf5a6c84SAndroid Build Coastguard Worker     } else {
74*cf5a6c84SAndroid Build Coastguard Worker       xlseek(fd, offset, SEEK_SET);
75*cf5a6c84SAndroid Build Coastguard Worker       if (type==1) { // write
76*cf5a6c84SAndroid Build Coastguard Worker         uu[1] = copy_loop(0, fd, length);
77*cf5a6c84SAndroid Build Coastguard Worker         ll[1] = SWAP_BE64(handle);
78*cf5a6c84SAndroid Build Coastguard Worker       } else uu[1] = 0; // read never reports errors because send header first
79*cf5a6c84SAndroid Build Coastguard Worker     }
80*cf5a6c84SAndroid Build Coastguard Worker 
81*cf5a6c84SAndroid Build Coastguard Worker     // Simple reply in toybuf (handle stays put)
82*cf5a6c84SAndroid Build Coastguard Worker     *uu = SWAP_BE32(0x67446698);
83*cf5a6c84SAndroid Build Coastguard Worker     xwrite(1, toybuf, 16);
84*cf5a6c84SAndroid Build Coastguard Worker 
85*cf5a6c84SAndroid Build Coastguard Worker     // Append read payload
86*cf5a6c84SAndroid Build Coastguard Worker     if (!type) if (copy_loop(fd, 1, length)) break;
87*cf5a6c84SAndroid Build Coastguard Worker   }
88*cf5a6c84SAndroid Build Coastguard Worker }
89