1 /*\ 2 * Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws> 3 * 4 * Network Block Device 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; under version 2 of the License. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 */ 19 20 #include <qemu-common.h> 21 #include "block_int.h" 22 #include "nbd.h" 23 24 #include <stdarg.h> 25 #include <stdio.h> 26 #include <getopt.h> 27 #include <err.h> 28 #include <sys/socket.h> 29 #include <netinet/in.h> 30 #include <netinet/tcp.h> 31 #include <arpa/inet.h> 32 33 int verbose; 34 35 static void usage(const char *name) 36 { 37 printf( 38 "Usage: %s [OPTIONS] FILE\n" 39 "QEMU Disk Network Block Device Server\n" 40 "\n" 41 " -p, --port=PORT port to listen on (default `1024')\n" 42 " -o, --offset=OFFSET offset into the image\n" 43 " -b, --bind=IFACE interface to bind to (default `0.0.0.0')\n" 44 " -r, --read-only export read-only\n" 45 " -P, --partition=NUM only expose partition NUM\n" 46 " -v, --verbose display extra debugging information\n" 47 " -h, --help display this help and exit\n" 48 " -V, --version output version information and exit\n" 49 "\n" 50 "Report bugs to <anthony@codemonkey.ws>\n" 51 , name); 52 } 53 54 static void version(const char *name) 55 { 56 printf( 57 "qemu-nbd version 0.0.1\n" 58 "Written by Anthony Liguori.\n" 59 "\n" 60 "Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>.\n" 61 "This is free software; see the source for copying conditions. There is NO\n" 62 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" 63 ); 64 } 65 66 struct partition_record 67 { 68 uint8_t bootable; 69 uint8_t start_head; 70 uint32_t start_cylinder; 71 uint8_t start_sector; 72 uint8_t system; 73 uint8_t end_head; 74 uint8_t end_cylinder; 75 uint8_t end_sector; 76 uint32_t start_sector_abs; 77 uint32_t nb_sectors_abs; 78 }; 79 80 static void read_partition(uint8_t *p, struct partition_record *r) 81 { 82 r->bootable = p[0]; 83 r->start_head = p[1]; 84 r->start_cylinder = p[3] | ((p[2] << 2) & 0x0300); 85 r->start_sector = p[2] & 0x3f; 86 r->system = p[4]; 87 r->end_head = p[5]; 88 r->end_cylinder = p[7] | ((p[6] << 2) & 0x300); 89 r->end_sector = p[6] & 0x3f; 90 r->start_sector_abs = p[8] | p[9] << 8 | p[10] << 16 | p[11] << 24; 91 r->nb_sectors_abs = p[12] | p[13] << 8 | p[14] << 16 | p[15] << 24; 92 } 93 94 static int find_partition(BlockDriverState *bs, int partition, 95 off_t *offset, off_t *size) 96 { 97 struct partition_record mbr[4]; 98 uint8_t data[512]; 99 int i; 100 int ext_partnum = 4; 101 102 if (bdrv_read(bs, 0, data, 1)) 103 errx(EINVAL, "error while reading"); 104 105 if (data[510] != 0x55 || data[511] != 0xaa) { 106 errno = -EINVAL; 107 return -1; 108 } 109 110 for (i = 0; i < 4; i++) { 111 read_partition(&data[446 + 16 * i], &mbr[i]); 112 113 if (!mbr[i].nb_sectors_abs) 114 continue; 115 116 if (mbr[i].system == 0xF || mbr[i].system == 0x5) { 117 struct partition_record ext[4]; 118 uint8_t data1[512]; 119 int j; 120 121 if (bdrv_read(bs, mbr[i].start_sector_abs, data1, 1)) 122 errx(EINVAL, "error while reading"); 123 124 for (j = 0; j < 4; j++) { 125 read_partition(&data1[446 + 16 * j], &ext[j]); 126 if (!ext[j].nb_sectors_abs) 127 continue; 128 129 if ((ext_partnum + j + 1) == partition) { 130 *offset = (uint64_t)ext[j].start_sector_abs << 9; 131 *size = (uint64_t)ext[j].nb_sectors_abs << 9; 132 return 0; 133 } 134 } 135 ext_partnum += 4; 136 } else if ((i + 1) == partition) { 137 *offset = (uint64_t)mbr[i].start_sector_abs << 9; 138 *size = (uint64_t)mbr[i].nb_sectors_abs << 9; 139 return 0; 140 } 141 } 142 143 errno = -ENOENT; 144 return -1; 145 } 146 147 int main(int argc, char **argv) 148 { 149 BlockDriverState *bs; 150 off_t dev_offset = 0; 151 off_t offset = 0; 152 bool readonly = false; 153 const char *bindto = "0.0.0.0"; 154 int port = 1024; 155 int sock, csock; 156 struct sockaddr_in addr; 157 socklen_t addr_len = sizeof(addr); 158 off_t fd_size; 159 const char *sopt = "hVbo:p:rsP:v"; 160 struct option lopt[] = { 161 { "help", 0, 0, 'h' }, 162 { "version", 0, 0, 'V' }, 163 { "bind", 1, 0, 'b' }, 164 { "port", 1, 0, 'p' }, 165 { "offset", 1, 0, 'o' }, 166 { "read-only", 0, 0, 'r' }, 167 { "partition", 1, 0, 'P' }, 168 { "snapshot", 0, 0, 's' }, 169 { "verbose", 0, 0, 'v' }, 170 { NULL, 0, 0, 0 } 171 }; 172 int ch; 173 int opt_ind = 0; 174 int li; 175 char *end; 176 bool snapshot = false; 177 int partition = -1; 178 179 while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { 180 switch (ch) { 181 case 's': 182 snapshot = true; 183 break; 184 case 'b': 185 bindto = optarg; 186 break; 187 case 'p': 188 li = strtol(optarg, &end, 0); 189 if (*end) { 190 errx(EINVAL, "Invalid port `%s'", optarg); 191 } 192 if (li < 1 || li > 65535) { 193 errx(EINVAL, "Port out of range `%s'", optarg); 194 } 195 port = (uint16_t)li; 196 break; 197 case 'o': 198 dev_offset = strtoll (optarg, &end, 0); 199 if (*end) { 200 errx(EINVAL, "Invalid offset `%s'", optarg); 201 } 202 if (dev_offset < 0) { 203 errx(EINVAL, "Offset must be positive `%s'", optarg); 204 } 205 break; 206 case 'r': 207 readonly = true; 208 break; 209 case 'P': 210 partition = strtol(optarg, &end, 0); 211 if (*end) 212 errx(EINVAL, "Invalid partition `%s'", optarg); 213 if (partition < 1 || partition > 8) 214 errx(EINVAL, "Invalid partition %d", partition); 215 break; 216 case 'v': 217 verbose = 1; 218 break; 219 case 'V': 220 version(argv[0]); 221 exit(0); 222 break; 223 case 'h': 224 usage(argv[0]); 225 exit(0); 226 break; 227 case '?': 228 errx(EINVAL, "Try `%s --help' for more information.", 229 argv[0]); 230 } 231 } 232 233 if ((argc - optind) != 1) { 234 errx(EINVAL, "Invalid number of argument.\n" 235 "Try `%s --help' for more information.", 236 argv[0]); 237 } 238 239 bdrv_init(); 240 241 bs = bdrv_new("hda"); 242 if (bs == NULL) 243 return 1; 244 245 if (bdrv_open(bs, argv[optind], snapshot) == -1) 246 return 1; 247 248 fd_size = bs->total_sectors * 512; 249 250 if (partition != -1 && 251 find_partition(bs, partition, &dev_offset, &fd_size)) 252 errx(errno, "Could not find partition %d", partition); 253 254 sock = tcp_socket_incoming(bindto, port); 255 if (sock == -1) 256 return 1; 257 258 csock = accept(sock, 259 (struct sockaddr *)&addr, 260 &addr_len); 261 if (csock == -1) 262 return 1; 263 264 /* new fd_size is calculated by find_partition */ 265 if (nbd_negotiate(bs, csock, fd_size) == -1) 266 return 1; 267 268 while (nbd_trip(bs, csock, fd_size, dev_offset, &offset, readonly) == 0); 269 270 close(csock); 271 close(sock); 272 bdrv_close(bs); 273 274 return 0; 275 } 276