comparison toys/pending/nbd_client.c @ 893:6f5fed66c722

Some work I did over the weekend on nbd_client, not sure where I left off...
author Rob Landley <rob@landley.net>
date Tue, 07 May 2013 22:03:31 -0500
parents 84959a5529e8
children e11684e3bbc5
comparison
equal deleted inserted replaced
892:f2a8f8981c83 893:6f5fed66c722
4 * 4 *
5 * Copyright 2010 Rob Landley <rob@landley.net> 5 * Copyright 2010 Rob Landley <rob@landley.net>
6 * 6 *
7 * Not in SUSv4. 7 * Not in SUSv4.
8 8
9 USE_NBD_CLIENT(NEWTOY(nbd_client, "<3>3", TOYFLAG_USR|TOYFLAG_BIN)) 9 USE_NBD_CLIENT(NEWTOY(nbd_client, "<3>3ns", TOYFLAG_USR|TOYFLAG_BIN))
10 10
11 config NBD_CLIENT 11 config NBD_CLIENT
12 bool "nbd-client" 12 bool "nbd-client"
13 default n 13 default n
14 help 14 help
15 usage: nbd-client [-ns] HOST PORT DEVICE
16
17 -n Do not fork into background
18 -s nbd swap support (lock server into memory)
19 */
20
21 /*
15 Usage: nbd-client [-sSpn] [-b BLKSZ] [-t SECS] [-N name] HOST PORT DEVICE 22 Usage: nbd-client [-sSpn] [-b BLKSZ] [-t SECS] [-N name] HOST PORT DEVICE
16 23
17 -b block size 24 -b block size
18 -t timeout in seconds 25 -t timeout in seconds
19 -s swap
20 -S sdp 26 -S sdp
21 -p persist 27 -p persist
22 -n nofork 28 -n nofork
23 -d DEVICE 29 -d DEVICE
24 -c DEVICE 30 -c DEVICE
25 */ 31 */
26 32
27 #define FOR_nbd_client 33 #define FOR_nbd_client
28 #include "toys.h" 34 #include "toys.h"
29 35 #include "toynet.h"
30 //#include <errno.h>
31 //#include <fcntl.h>
32 //#include <limits.h>
33 #include <netdb.h>
34 //#include <stdint.h>
35 //#include <stdio.h>
36 //#include <stdlib.h>
37 //#include <string.h>
38 //#include <unistd.h>
39 #include <netinet/tcp.h>
40 //#include <sys/ioctl.h>
41 //#include <sys/mount.h>
42 //#include <sys/types.h>
43 //#include <sys/socket.h>
44 //#include <sys/stat.h>
45 36
46 #define NBD_SET_SOCK _IO(0xab, 0) 37 #define NBD_SET_SOCK _IO(0xab, 0)
47 #define NBD_SET_BLKSIZE _IO(0xab, 1) 38 #define NBD_SET_BLKSIZE _IO(0xab, 1)
48 #define NBD_SET_SIZE _IO(0xab, 2) 39 #define NBD_SET_SIZE _IO(0xab, 2)
49 #define NBD_DO_IT _IO(0xab, 3) 40 #define NBD_DO_IT _IO(0xab, 3)
59 int sock = -1, nbd, flags; 50 int sock = -1, nbd, flags;
60 unsigned long timeout = 0; 51 unsigned long timeout = 0;
61 struct addrinfo *addr, *p; 52 struct addrinfo *addr, *p;
62 char *host=toys.optargs[0], *port=toys.optargs[1], *device=toys.optargs[2]; 53 char *host=toys.optargs[0], *port=toys.optargs[1], *device=toys.optargs[2];
63 uint64_t devsize; 54 uint64_t devsize;
64 char data[124];
65
66 // Parse command line stuff (just a stub now)
67
68 // Make sure the /dev/nbd exists.
69
70 if (0>(nbd = open(device, O_RDWR))) {
71 fprintf(stderr, "Can't open '%s'\n", device);
72 exit(1);
73 }
74 55
75 // Repeat until spanked 56 // Repeat until spanked
76 57
58 nbd = xopen(device, O_RDWR);
77 for (;;) { 59 for (;;) {
78 int temp; 60 int temp;
79 struct addrinfo hints; 61 struct addrinfo hints;
80 62
81 // Find and connect to server 63 // Find and connect to server
85 hints.ai_socktype = SOCK_STREAM; 67 hints.ai_socktype = SOCK_STREAM;
86 if (getaddrinfo(host, port, &hints, &addr)) addr = 0; 68 if (getaddrinfo(host, port, &hints, &addr)) addr = 0;
87 for (p = addr; p; p = p->ai_next) { 69 for (p = addr; p; p = p->ai_next) {
88 sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol); 70 sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
89 if (-1 != connect(sock, p->ai_addr, p->ai_addrlen)) break; 71 if (-1 != connect(sock, p->ai_addr, p->ai_addrlen)) break;
72 close(sock);
90 } 73 }
91 freeaddrinfo(addr); 74 freeaddrinfo(addr);
92 75
93 if (!p) { 76 if (!p) perror_exit("%s:%s", host, port);
94 fprintf(stderr, "Can't connect '%s' port '%s'\n", host, port);
95 exit(1);
96 }
97 77
98 temp = 1; 78 temp = 1;
99 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &temp, sizeof(int)); 79 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &temp, sizeof(int));
100 80
101 // Log on to the server. (Todo: one big 8+8+8+4+124=152 read) 81 // Read login data
102 82
103 if (read(sock, data, 8) != 8 || memcmp(data, "NBDMAGIC", 8) 83 xreadall(sock, toybuf, 152);
104 || read(sock, &devsize, 8) != 8 84 if (memcmp(toybuf, "NBDMAGIC\x00\x00\x42\x02\x81\x86\x12\x53", 16))
105 || SWAP_BE64(devsize) != 0x420281861253LL 85 error_exit("bad login %s:%s", host, port);
106 || read(sock, &devsize, 8) != 8 || read(sock, &flags, 4) != 4 86 devsize = SWAP_BE64(*(uint64_t *)(toybuf+16));
107 || read(sock, data, 124) != 124) 87 flags = SWAP_BE32(*(int *)(toybuf+24));
108 {
109 fprintf(stderr, "Login fail\n");
110 exit(1);
111 }
112 devsize = SWAP_BE64(devsize);
113 flags = SWAP_BE32(flags);
114 88
115 // Set 4k block size. Everything uses that these days. 89 // Set 4k block size. Everything uses that these days.
116 ioctl(nbd, NBD_SET_BLKSIZE, 4096); 90 ioctl(nbd, NBD_SET_BLKSIZE, 4096);
117 ioctl(nbd, NBD_SET_SIZE_BLOCKS, devsize/4096); 91 ioctl(nbd, NBD_SET_SIZE_BLOCKS, devsize/4096);
118 ioctl(nbd, NBD_CLEAR_SOCK); 92 ioctl(nbd, NBD_CLEAR_SOCK);
119 93
120 // If the sucker was exported read only, respect that locally. 94 // If the sucker was exported read only, respect that locally.
121 temp = (flags & 2) ? 1 : 0; 95 temp = (flags & 2) ? 1 : 0;
122 if (ioctl(nbd, BLKROSET, &temp)<0) { 96 xioctl(nbd, BLKROSET, &temp);
123 fprintf(stderr, "Login fail\n");
124 exit(1);
125 }
126 97
127 if (timeout && ioctl(nbd, NBD_SET_TIMEOUT, timeout)<0) break; 98 if (timeout && ioctl(nbd, NBD_SET_TIMEOUT, timeout)<0) break;
128 if (ioctl(nbd, NBD_SET_SOCK, sock) < 0) break; 99 if (ioctl(nbd, NBD_SET_SOCK, sock) < 0) break;
129 100
130 // if (swap) mlockall(MCL_CURRENT|MCL_FUTURE); 101 if (toys.optflags & FLAG_s) mlockall(MCL_CURRENT|MCL_FUTURE);
131 102
132 // Open the device to force reread of the partition table. 103 // Open the device to force reread of the partition table.
133 if (!fork()) { 104 if ((toys.optflags & FLAG_n) || !fork()) {
134 char *s = strrchr(device, '/'); 105 char *s = strrchr(device, '/');
135 sprintf(data, "/sys/block/%.32s/pid", s ? s+1 : device); 106 int i;
136 // Is it up yet? 107
137 for (;;) { 108 sprintf(toybuf, "/sys/block/%.32s/pid", s ? s+1 : device);
138 temp = open(data, O_RDONLY); 109 // Is it up yet? (Give it 10 seconds.)
139 if (temp == -1) sleep(1); 110 for (i=0; i<100; i++) {
111 temp = open(toybuf, O_RDONLY);
112 if (temp == -1) msleep(100);
140 else { 113 else {
141 close(temp); 114 close(temp);
142 break; 115 break;
143 } 116 }
144 } 117 }
145 close(open(device, O_RDONLY)); 118 close(open(device, O_RDONLY));
146 exit(0); 119 if (!(toys.optflags & FLAG_n)) exit(0);
147 } 120 }
148 121
149 // Daemonize here. 122 // Daemonize here.
150 123
151 daemon(0,0); 124 daemon(0,0);
152 125
153 // Process NBD requests until further notice. 126 // Process NBD requests until further notice.
154 127
155 if (ioctl(nbd, NBD_DO_IT)>=0 || errno==EBADR) break; 128 if (ioctl(nbd, NBD_DO_IT)>=0 || errno==EBADR) break;
156 close(sock); 129 close(sock);
157 close(nbd);
158 } 130 }
131 close(nbd);
159 132
160 // Flush queue and exit. 133 // Flush queue and exit.
161 134
162 ioctl(nbd, NBD_CLEAR_QUEUE); 135 ioctl(nbd, NBD_CLEAR_QUEUE);
163 ioctl(nbd, NBD_CLEAR_SOCK); 136 ioctl(nbd, NBD_CLEAR_SOCK);
164
165 exit(0);
166 } 137 }