1fc01f7e7Sbellard /* 2fc01f7e7Sbellard * QEMU System Emulator block driver 3fc01f7e7Sbellard * 4fc01f7e7Sbellard * Copyright (c) 2003 Fabrice Bellard 5fc01f7e7Sbellard * 6fc01f7e7Sbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 7fc01f7e7Sbellard * of this software and associated documentation files (the "Software"), to deal 8fc01f7e7Sbellard * in the Software without restriction, including without limitation the rights 9fc01f7e7Sbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10fc01f7e7Sbellard * copies of the Software, and to permit persons to whom the Software is 11fc01f7e7Sbellard * furnished to do so, subject to the following conditions: 12fc01f7e7Sbellard * 13fc01f7e7Sbellard * The above copyright notice and this permission notice shall be included in 14fc01f7e7Sbellard * all copies or substantial portions of the Software. 15fc01f7e7Sbellard * 16fc01f7e7Sbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17fc01f7e7Sbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18fc01f7e7Sbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19fc01f7e7Sbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20fc01f7e7Sbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21fc01f7e7Sbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22fc01f7e7Sbellard * THE SOFTWARE. 23fc01f7e7Sbellard */ 24fc01f7e7Sbellard #include "vl.h" 25fc01f7e7Sbellard 26*67b915a5Sbellard #ifndef _WIN32 27*67b915a5Sbellard #include <sys/mman.h> 28*67b915a5Sbellard #endif 2933e3963eSbellard 3000af2b26Sbellard #include "cow.h" 3100af2b26Sbellard 32fc01f7e7Sbellard struct BlockDriverState { 3333e3963eSbellard int fd; /* if -1, only COW mappings */ 34fc01f7e7Sbellard int64_t total_sectors; 35b338082bSbellard int read_only; /* if true, the media is read only */ 36b338082bSbellard int inserted; /* if true, the media is present */ 37b338082bSbellard int removable; /* if true, the media can be removed */ 38b338082bSbellard int locked; /* if true, the media cannot temporarily be ejected */ 39b338082bSbellard /* event callback when inserting/removing */ 40b338082bSbellard void (*change_cb)(void *opaque); 41b338082bSbellard void *change_opaque; 4233e3963eSbellard 4333e3963eSbellard uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */ 4433e3963eSbellard uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */ 4533e3963eSbellard int cow_bitmap_size; 4633e3963eSbellard int cow_fd; 4733e3963eSbellard int64_t cow_sectors_offset; 48cf98951bSbellard int boot_sector_enabled; 49cf98951bSbellard uint8_t boot_sector_data[512]; 50cf98951bSbellard 5133e3963eSbellard char filename[1024]; 52b338082bSbellard 53b338082bSbellard /* NOTE: the following infos are only hints for real hardware 54b338082bSbellard drivers. They are not used by the block driver */ 55b338082bSbellard int cyls, heads, secs; 56b338082bSbellard int type; 57b338082bSbellard char device_name[32]; 58b338082bSbellard BlockDriverState *next; 59fc01f7e7Sbellard }; 60fc01f7e7Sbellard 61b338082bSbellard static BlockDriverState *bdrv_first; 62b338082bSbellard 63b338082bSbellard /* create a new block device (by default it is empty) */ 64b338082bSbellard BlockDriverState *bdrv_new(const char *device_name) 65fc01f7e7Sbellard { 66b338082bSbellard BlockDriverState **pbs, *bs; 67b338082bSbellard 68b338082bSbellard bs = qemu_mallocz(sizeof(BlockDriverState)); 69b338082bSbellard if(!bs) 70b338082bSbellard return NULL; 71b338082bSbellard pstrcpy(bs->device_name, sizeof(bs->device_name), device_name); 72b338082bSbellard /* insert at the end */ 73b338082bSbellard pbs = &bdrv_first; 74b338082bSbellard while (*pbs != NULL) 75b338082bSbellard pbs = &(*pbs)->next; 76b338082bSbellard *pbs = bs; 77b338082bSbellard return bs; 78b338082bSbellard } 79b338082bSbellard 80b338082bSbellard int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) 81b338082bSbellard { 82*67b915a5Sbellard int fd; 83fc01f7e7Sbellard int64_t size; 8433e3963eSbellard struct cow_header_v2 cow_header; 85*67b915a5Sbellard #ifndef _WIN32 86*67b915a5Sbellard char template[] = "/tmp/vl.XXXXXX"; 87*67b915a5Sbellard int cow_fd; 8833e3963eSbellard struct stat st; 89*67b915a5Sbellard #endif 90fc01f7e7Sbellard 910849bf08Sbellard bs->read_only = 0; 9233e3963eSbellard bs->fd = -1; 9333e3963eSbellard bs->cow_fd = -1; 9433e3963eSbellard bs->cow_bitmap = NULL; 9533e3963eSbellard strcpy(bs->filename, filename); 9633e3963eSbellard 9733e3963eSbellard /* open standard HD image */ 98*67b915a5Sbellard #ifdef _WIN32 99*67b915a5Sbellard fd = open(filename, O_RDWR | O_BINARY); 100*67b915a5Sbellard #else 10133e3963eSbellard fd = open(filename, O_RDWR | O_LARGEFILE); 102*67b915a5Sbellard #endif 103fc01f7e7Sbellard if (fd < 0) { 10433e3963eSbellard /* read only image on disk */ 105*67b915a5Sbellard #ifdef _WIN32 106*67b915a5Sbellard fd = open(filename, O_RDONLY | O_BINARY); 107*67b915a5Sbellard #else 10833e3963eSbellard fd = open(filename, O_RDONLY | O_LARGEFILE); 109*67b915a5Sbellard #endif 1100849bf08Sbellard if (fd < 0) { 11133e3963eSbellard perror(filename); 11233e3963eSbellard goto fail; 113fc01f7e7Sbellard } 11433e3963eSbellard if (!snapshot) 1150849bf08Sbellard bs->read_only = 1; 1160849bf08Sbellard } 11733e3963eSbellard bs->fd = fd; 11833e3963eSbellard 11933e3963eSbellard /* see if it is a cow image */ 12033e3963eSbellard if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) { 12133e3963eSbellard fprintf(stderr, "%s: could not read header\n", filename); 12233e3963eSbellard goto fail; 12333e3963eSbellard } 124*67b915a5Sbellard #ifndef _WIN32 125*67b915a5Sbellard if (be32_to_cpu(cow_header.magic) == COW_MAGIC && 126*67b915a5Sbellard be32_to_cpu(cow_header.version) == COW_VERSION) { 12733e3963eSbellard /* cow image found */ 12833e3963eSbellard size = cow_header.size; 12933e3963eSbellard #ifndef WORDS_BIGENDIAN 13033e3963eSbellard size = bswap64(size); 13133e3963eSbellard #endif 13233e3963eSbellard bs->total_sectors = size / 512; 13333e3963eSbellard 13433e3963eSbellard bs->cow_fd = fd; 13533e3963eSbellard bs->fd = -1; 13633e3963eSbellard if (cow_header.backing_file[0] != '\0') { 13733e3963eSbellard if (stat(cow_header.backing_file, &st) != 0) { 13833e3963eSbellard fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file); 13933e3963eSbellard goto fail; 14033e3963eSbellard } 141*67b915a5Sbellard if (st.st_mtime != be32_to_cpu(cow_header.mtime)) { 14233e3963eSbellard fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file); 14333e3963eSbellard goto fail; 14433e3963eSbellard } 14533e3963eSbellard fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE); 14633e3963eSbellard if (fd < 0) 14733e3963eSbellard goto fail; 14833e3963eSbellard bs->fd = fd; 14933e3963eSbellard } 15033e3963eSbellard /* mmap the bitmap */ 15133e3963eSbellard bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); 15233e3963eSbellard bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), 15333e3963eSbellard bs->cow_bitmap_size, 15433e3963eSbellard PROT_READ | PROT_WRITE, 15533e3963eSbellard MAP_SHARED, bs->cow_fd, 0); 15633e3963eSbellard if (bs->cow_bitmap_addr == MAP_FAILED) 15733e3963eSbellard goto fail; 15833e3963eSbellard bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header); 15933e3963eSbellard bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511; 16033e3963eSbellard snapshot = 0; 161*67b915a5Sbellard } else 162*67b915a5Sbellard #endif 163*67b915a5Sbellard { 16433e3963eSbellard /* standard raw image */ 165fc01f7e7Sbellard size = lseek64(fd, 0, SEEK_END); 166fc01f7e7Sbellard bs->total_sectors = size / 512; 167fc01f7e7Sbellard bs->fd = fd; 16833e3963eSbellard } 16933e3963eSbellard 170*67b915a5Sbellard #ifndef _WIN32 17133e3963eSbellard if (snapshot) { 17233e3963eSbellard /* create a temporary COW file */ 17333e3963eSbellard cow_fd = mkstemp(template); 17433e3963eSbellard if (cow_fd < 0) 17533e3963eSbellard goto fail; 17633e3963eSbellard bs->cow_fd = cow_fd; 17733e3963eSbellard unlink(template); 17833e3963eSbellard 17933e3963eSbellard /* just need to allocate bitmap */ 18033e3963eSbellard bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3; 18133e3963eSbellard bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), 18233e3963eSbellard bs->cow_bitmap_size, 18333e3963eSbellard PROT_READ | PROT_WRITE, 18433e3963eSbellard MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 18533e3963eSbellard if (bs->cow_bitmap_addr == MAP_FAILED) 18633e3963eSbellard goto fail; 18733e3963eSbellard bs->cow_bitmap = bs->cow_bitmap_addr; 18833e3963eSbellard bs->cow_sectors_offset = 0; 18933e3963eSbellard } 190*67b915a5Sbellard #endif 19133e3963eSbellard 192b338082bSbellard bs->inserted = 1; 193b338082bSbellard 194b338082bSbellard /* call the change callback */ 195b338082bSbellard if (bs->change_cb) 196b338082bSbellard bs->change_cb(bs->change_opaque); 197b338082bSbellard 198b338082bSbellard return 0; 19933e3963eSbellard fail: 20033e3963eSbellard bdrv_close(bs); 201b338082bSbellard return -1; 202fc01f7e7Sbellard } 203fc01f7e7Sbellard 204fc01f7e7Sbellard void bdrv_close(BlockDriverState *bs) 205fc01f7e7Sbellard { 206b338082bSbellard if (bs->inserted) { 207*67b915a5Sbellard #ifndef _WIN32 20833e3963eSbellard /* we unmap the mapping so that it is written to the COW file */ 20933e3963eSbellard if (bs->cow_bitmap_addr) 21033e3963eSbellard munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size); 211*67b915a5Sbellard #endif 21233e3963eSbellard if (bs->cow_fd >= 0) 21333e3963eSbellard close(bs->cow_fd); 21433e3963eSbellard if (bs->fd >= 0) 215fc01f7e7Sbellard close(bs->fd); 216b338082bSbellard bs->inserted = 0; 217b338082bSbellard 218b338082bSbellard /* call the change callback */ 219b338082bSbellard if (bs->change_cb) 220b338082bSbellard bs->change_cb(bs->change_opaque); 221b338082bSbellard } 222b338082bSbellard } 223b338082bSbellard 224b338082bSbellard void bdrv_delete(BlockDriverState *bs) 225b338082bSbellard { 226b338082bSbellard bdrv_close(bs); 227b338082bSbellard qemu_free(bs); 228fc01f7e7Sbellard } 229fc01f7e7Sbellard 23033e3963eSbellard static inline void set_bit(uint8_t *bitmap, int64_t bitnum) 23133e3963eSbellard { 23233e3963eSbellard bitmap[bitnum / 8] |= (1 << (bitnum%8)); 23333e3963eSbellard } 23433e3963eSbellard 23533e3963eSbellard static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum) 23633e3963eSbellard { 23733e3963eSbellard return !!(bitmap[bitnum / 8] & (1 << (bitnum%8))); 23833e3963eSbellard } 23933e3963eSbellard 24033e3963eSbellard 24133e3963eSbellard /* Return true if first block has been changed (ie. current version is 24233e3963eSbellard * in COW file). Set the number of continuous blocks for which that 24333e3963eSbellard * is true. */ 24433e3963eSbellard static int is_changed(uint8_t *bitmap, 24533e3963eSbellard int64_t sector_num, int nb_sectors, 24633e3963eSbellard int *num_same) 24733e3963eSbellard { 24833e3963eSbellard int changed; 24933e3963eSbellard 25033e3963eSbellard if (!bitmap || nb_sectors == 0) { 25133e3963eSbellard *num_same = nb_sectors; 25233e3963eSbellard return 0; 25333e3963eSbellard } 25433e3963eSbellard 25533e3963eSbellard changed = is_bit_set(bitmap, sector_num); 25633e3963eSbellard for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) { 25733e3963eSbellard if (is_bit_set(bitmap, sector_num + *num_same) != changed) 25833e3963eSbellard break; 25933e3963eSbellard } 26033e3963eSbellard 26133e3963eSbellard return changed; 26233e3963eSbellard } 26333e3963eSbellard 26433e3963eSbellard /* commit COW file into the raw image */ 26533e3963eSbellard int bdrv_commit(BlockDriverState *bs) 26633e3963eSbellard { 26733e3963eSbellard int64_t i; 26833e3963eSbellard uint8_t *cow_bitmap; 26933e3963eSbellard 270b338082bSbellard if (!bs->inserted) 271b338082bSbellard return -1; 272b338082bSbellard 27333e3963eSbellard if (!bs->cow_bitmap) { 27433e3963eSbellard fprintf(stderr, "Already committed to %s\n", bs->filename); 27533e3963eSbellard return 0; 27633e3963eSbellard } 27733e3963eSbellard 27833e3963eSbellard if (bs->read_only) { 27933e3963eSbellard fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename); 28033e3963eSbellard return -1; 28133e3963eSbellard } 28233e3963eSbellard 28333e3963eSbellard cow_bitmap = bs->cow_bitmap; 28433e3963eSbellard for (i = 0; i < bs->total_sectors; i++) { 28533e3963eSbellard if (is_bit_set(cow_bitmap, i)) { 28633e3963eSbellard unsigned char sector[512]; 28733e3963eSbellard if (bdrv_read(bs, i, sector, 1) != 0) { 28833e3963eSbellard fprintf(stderr, "Error reading sector %lli: aborting commit\n", 28933e3963eSbellard (long long)i); 29033e3963eSbellard return -1; 29133e3963eSbellard } 29233e3963eSbellard 29333e3963eSbellard /* Make bdrv_write write to real file for a moment. */ 29433e3963eSbellard bs->cow_bitmap = NULL; 29533e3963eSbellard if (bdrv_write(bs, i, sector, 1) != 0) { 29633e3963eSbellard fprintf(stderr, "Error writing sector %lli: aborting commit\n", 29733e3963eSbellard (long long)i); 29833e3963eSbellard bs->cow_bitmap = cow_bitmap; 29933e3963eSbellard return -1; 30033e3963eSbellard } 30133e3963eSbellard bs->cow_bitmap = cow_bitmap; 30233e3963eSbellard } 30333e3963eSbellard } 30433e3963eSbellard fprintf(stderr, "Committed snapshot to %s\n", bs->filename); 30533e3963eSbellard return 0; 30633e3963eSbellard } 30733e3963eSbellard 308fc01f7e7Sbellard /* return -1 if error */ 309fc01f7e7Sbellard int bdrv_read(BlockDriverState *bs, int64_t sector_num, 310fc01f7e7Sbellard uint8_t *buf, int nb_sectors) 311fc01f7e7Sbellard { 31233e3963eSbellard int ret, n, fd; 31333e3963eSbellard int64_t offset; 314fc01f7e7Sbellard 315b338082bSbellard if (!bs->inserted) 316b338082bSbellard return -1; 317b338082bSbellard 31833e3963eSbellard while (nb_sectors > 0) { 31933e3963eSbellard if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) { 32033e3963eSbellard fd = bs->cow_fd; 32133e3963eSbellard offset = bs->cow_sectors_offset; 322cf98951bSbellard } else if (sector_num == 0 && bs->boot_sector_enabled) { 323cf98951bSbellard memcpy(buf, bs->boot_sector_data, 512); 324cf98951bSbellard n = 1; 325cf98951bSbellard goto next; 32633e3963eSbellard } else { 32733e3963eSbellard fd = bs->fd; 32833e3963eSbellard offset = 0; 32933e3963eSbellard } 33033e3963eSbellard 33133e3963eSbellard if (fd < 0) { 33233e3963eSbellard /* no file, just return empty sectors */ 33333e3963eSbellard memset(buf, 0, n * 512); 33433e3963eSbellard } else { 33533e3963eSbellard offset += sector_num * 512; 33633e3963eSbellard lseek64(fd, offset, SEEK_SET); 33733e3963eSbellard ret = read(fd, buf, n * 512); 33833e3963eSbellard if (ret != n * 512) { 339fc01f7e7Sbellard return -1; 34033e3963eSbellard } 34133e3963eSbellard } 342cf98951bSbellard next: 34333e3963eSbellard nb_sectors -= n; 34433e3963eSbellard sector_num += n; 34533e3963eSbellard buf += n * 512; 34633e3963eSbellard } 347fc01f7e7Sbellard return 0; 348fc01f7e7Sbellard } 349fc01f7e7Sbellard 350fc01f7e7Sbellard /* return -1 if error */ 351fc01f7e7Sbellard int bdrv_write(BlockDriverState *bs, int64_t sector_num, 352fc01f7e7Sbellard const uint8_t *buf, int nb_sectors) 353fc01f7e7Sbellard { 35433e3963eSbellard int ret, fd, i; 35533e3963eSbellard int64_t offset, retl; 356fc01f7e7Sbellard 357b338082bSbellard if (!bs->inserted) 358b338082bSbellard return -1; 3590849bf08Sbellard if (bs->read_only) 3600849bf08Sbellard return -1; 3610849bf08Sbellard 36233e3963eSbellard if (bs->cow_bitmap) { 36333e3963eSbellard fd = bs->cow_fd; 36433e3963eSbellard offset = bs->cow_sectors_offset; 36533e3963eSbellard } else { 36633e3963eSbellard fd = bs->fd; 36733e3963eSbellard offset = 0; 36833e3963eSbellard } 36933e3963eSbellard 37033e3963eSbellard offset += sector_num * 512; 37133e3963eSbellard retl = lseek64(fd, offset, SEEK_SET); 37233e3963eSbellard if (retl == -1) { 373fc01f7e7Sbellard return -1; 37433e3963eSbellard } 37533e3963eSbellard ret = write(fd, buf, nb_sectors * 512); 37633e3963eSbellard if (ret != nb_sectors * 512) { 37733e3963eSbellard return -1; 37833e3963eSbellard } 37933e3963eSbellard 38033e3963eSbellard if (bs->cow_bitmap) { 38133e3963eSbellard for (i = 0; i < nb_sectors; i++) 38233e3963eSbellard set_bit(bs->cow_bitmap, sector_num + i); 38333e3963eSbellard } 384fc01f7e7Sbellard return 0; 385fc01f7e7Sbellard } 386fc01f7e7Sbellard 387fc01f7e7Sbellard void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) 388fc01f7e7Sbellard { 389fc01f7e7Sbellard *nb_sectors_ptr = bs->total_sectors; 390fc01f7e7Sbellard } 391cf98951bSbellard 392cf98951bSbellard /* force a given boot sector. */ 393cf98951bSbellard void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size) 394cf98951bSbellard { 395cf98951bSbellard bs->boot_sector_enabled = 1; 396cf98951bSbellard if (size > 512) 397cf98951bSbellard size = 512; 398cf98951bSbellard memcpy(bs->boot_sector_data, data, size); 399cf98951bSbellard memset(bs->boot_sector_data + size, 0, 512 - size); 400cf98951bSbellard } 401b338082bSbellard 402b338082bSbellard void bdrv_set_geometry_hint(BlockDriverState *bs, 403b338082bSbellard int cyls, int heads, int secs) 404b338082bSbellard { 405b338082bSbellard bs->cyls = cyls; 406b338082bSbellard bs->heads = heads; 407b338082bSbellard bs->secs = secs; 408b338082bSbellard } 409b338082bSbellard 410b338082bSbellard void bdrv_set_type_hint(BlockDriverState *bs, int type) 411b338082bSbellard { 412b338082bSbellard bs->type = type; 413b338082bSbellard bs->removable = ((type == BDRV_TYPE_CDROM || 414b338082bSbellard type == BDRV_TYPE_FLOPPY)); 415b338082bSbellard } 416b338082bSbellard 417b338082bSbellard void bdrv_get_geometry_hint(BlockDriverState *bs, 418b338082bSbellard int *pcyls, int *pheads, int *psecs) 419b338082bSbellard { 420b338082bSbellard *pcyls = bs->cyls; 421b338082bSbellard *pheads = bs->heads; 422b338082bSbellard *psecs = bs->secs; 423b338082bSbellard } 424b338082bSbellard 425b338082bSbellard int bdrv_get_type_hint(BlockDriverState *bs) 426b338082bSbellard { 427b338082bSbellard return bs->type; 428b338082bSbellard } 429b338082bSbellard 430b338082bSbellard int bdrv_is_removable(BlockDriverState *bs) 431b338082bSbellard { 432b338082bSbellard return bs->removable; 433b338082bSbellard } 434b338082bSbellard 435b338082bSbellard int bdrv_is_read_only(BlockDriverState *bs) 436b338082bSbellard { 437b338082bSbellard return bs->read_only; 438b338082bSbellard } 439b338082bSbellard 440b338082bSbellard int bdrv_is_inserted(BlockDriverState *bs) 441b338082bSbellard { 442b338082bSbellard return bs->inserted; 443b338082bSbellard } 444b338082bSbellard 445b338082bSbellard int bdrv_is_locked(BlockDriverState *bs) 446b338082bSbellard { 447b338082bSbellard return bs->locked; 448b338082bSbellard } 449b338082bSbellard 450b338082bSbellard void bdrv_set_locked(BlockDriverState *bs, int locked) 451b338082bSbellard { 452b338082bSbellard bs->locked = locked; 453b338082bSbellard } 454b338082bSbellard 455b338082bSbellard void bdrv_set_change_cb(BlockDriverState *bs, 456b338082bSbellard void (*change_cb)(void *opaque), void *opaque) 457b338082bSbellard { 458b338082bSbellard bs->change_cb = change_cb; 459b338082bSbellard bs->change_opaque = opaque; 460b338082bSbellard } 461b338082bSbellard 462b338082bSbellard BlockDriverState *bdrv_find(const char *name) 463b338082bSbellard { 464b338082bSbellard BlockDriverState *bs; 465b338082bSbellard 466b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 467b338082bSbellard if (!strcmp(name, bs->device_name)) 468b338082bSbellard return bs; 469b338082bSbellard } 470b338082bSbellard return NULL; 471b338082bSbellard } 472b338082bSbellard 473b338082bSbellard void bdrv_info(void) 474b338082bSbellard { 475b338082bSbellard BlockDriverState *bs; 476b338082bSbellard 477b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 478b338082bSbellard term_printf("%s:", bs->device_name); 479b338082bSbellard term_printf(" type="); 480b338082bSbellard switch(bs->type) { 481b338082bSbellard case BDRV_TYPE_HD: 482b338082bSbellard term_printf("hd"); 483b338082bSbellard break; 484b338082bSbellard case BDRV_TYPE_CDROM: 485b338082bSbellard term_printf("cdrom"); 486b338082bSbellard break; 487b338082bSbellard case BDRV_TYPE_FLOPPY: 488b338082bSbellard term_printf("floppy"); 489b338082bSbellard break; 490b338082bSbellard } 491b338082bSbellard term_printf(" removable=%d", bs->removable); 492b338082bSbellard if (bs->removable) { 493b338082bSbellard term_printf(" locked=%d", bs->locked); 494b338082bSbellard } 495b338082bSbellard if (bs->inserted) { 496b338082bSbellard term_printf(" file=%s", bs->filename); 497b338082bSbellard term_printf(" ro=%d", bs->read_only); 498b338082bSbellard } else { 499b338082bSbellard term_printf(" [not inserted]"); 500b338082bSbellard } 501b338082bSbellard term_printf("\n"); 502b338082bSbellard } 503b338082bSbellard } 504