source: mainline/uspace/srv/bd/file_bd/file_bd.c@ f3d47c97

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f3d47c97 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/*
2 * Copyright (c) 2009 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup bd
30 * @{
31 */
32
33/**
34 * @file
35 * @brief File-backed block device driver
36 *
37 * Allows accessing a file as a block device. Useful for, e.g., mounting
38 * a disk image.
39 */
40
41#include <stdio.h>
42#include <async.h>
43#include <as.h>
44#include <bd_srv.h>
45#include <fibril_synch.h>
46#include <loc.h>
47#include <stddef.h>
48#include <stdint.h>
49#include <errno.h>
50#include <str_error.h>
51#include <stdbool.h>
52#include <task.h>
53#include <macros.h>
54#include <str.h>
55
56#define NAME "file_bd"
57
58#define DEFAULT_BLOCK_SIZE 512
59
60static size_t block_size;
61static aoff64_t num_blocks;
62static FILE *img;
63
64static service_id_t service_id;
65static bd_srvs_t bd_srvs;
66static fibril_mutex_t dev_lock;
67
68static void print_usage(void);
69static errno_t file_bd_init(const char *fname);
70static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *);
71
72static errno_t file_bd_open(bd_srvs_t *, bd_srv_t *);
73static errno_t file_bd_close(bd_srv_t *);
74static errno_t file_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
75static errno_t file_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
76static errno_t file_bd_get_block_size(bd_srv_t *, size_t *);
77static errno_t file_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
78
79static bd_ops_t file_bd_ops = {
80 .open = file_bd_open,
81 .close = file_bd_close,
82 .read_blocks = file_bd_read_blocks,
83 .write_blocks = file_bd_write_blocks,
84 .get_block_size = file_bd_get_block_size,
85 .get_num_blocks = file_bd_get_num_blocks
86};
87
88int main(int argc, char **argv)
89{
90 errno_t rc;
91 char *image_name;
92 char *device_name;
93 category_id_t disk_cat;
94
95 printf(NAME ": File-backed block device driver\n");
96
97 block_size = DEFAULT_BLOCK_SIZE;
98
99 ++argv; --argc;
100 while (*argv != NULL && (*argv)[0] == '-') {
101 /* Option */
102 if (str_cmp(*argv, "-b") == 0) {
103 if (argc < 2) {
104 printf("Argument missing.\n");
105 print_usage();
106 return -1;
107 }
108
109 rc = str_size_t(argv[1], NULL, 10, true, &block_size);
110 if (rc != EOK || block_size == 0) {
111 printf("Invalid block size '%s'.\n", argv[1]);
112 print_usage();
113 return -1;
114 }
115 ++argv; --argc;
116 } else {
117 printf("Invalid option '%s'.\n", *argv);
118 print_usage();
119 return -1;
120 }
121 ++argv; --argc;
122 }
123
124 if (argc < 2) {
125 printf("Missing arguments.\n");
126 print_usage();
127 return -1;
128 }
129
130 image_name = argv[0];
131 device_name = argv[1];
132
133 if (file_bd_init(image_name) != EOK)
134 return -1;
135
136 rc = loc_service_register(device_name, &service_id);
137 if (rc != EOK) {
138 printf("%s: Unable to register device '%s': %s.\n",
139 NAME, device_name, str_error(rc));
140 return rc;
141 }
142
143 rc = loc_category_get_id("disk", &disk_cat, IPC_FLAG_BLOCKING);
144 if (rc != EOK) {
145 printf("%s: Failed resolving category 'disk': %s\n", NAME, str_error(rc));
146 return rc;
147 }
148
149 rc = loc_service_add_to_cat(service_id, disk_cat);
150 if (rc != EOK) {
151 printf("%s: Failed adding %s to category: %s",
152 NAME, device_name, str_error(rc));
153 return rc;
154 }
155
156 printf("%s: Accepting connections\n", NAME);
157 task_retval(0);
158 async_manager();
159
160 /* Not reached */
161 return 0;
162}
163
164static void print_usage(void)
165{
166 printf("Usage: " NAME " [-b <block_size>] <image_file> <device_name>\n");
167}
168
169static errno_t file_bd_init(const char *fname)
170{
171 bd_srvs_init(&bd_srvs);
172 bd_srvs.ops = &file_bd_ops;
173
174 async_set_fallback_port_handler(file_bd_connection, NULL);
175 errno_t rc = loc_server_register(NAME);
176 if (rc != EOK) {
177 printf("%s: Unable to register driver.\n", NAME);
178 return rc;
179 }
180
181 img = fopen(fname, "rb+");
182 if (img == NULL)
183 return EINVAL;
184
185 if (fseek(img, 0, SEEK_END) != 0) {
186 fclose(img);
187 return EIO;
188 }
189
190 off64_t img_size = ftell(img);
191 if (img_size < 0) {
192 fclose(img);
193 return EIO;
194 }
195
196 num_blocks = img_size / block_size;
197
198 fibril_mutex_initialize(&dev_lock);
199
200 return EOK;
201}
202
203static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
204{
205 bd_conn(iid, icall, &bd_srvs);
206}
207
208/** Open device. */
209static errno_t file_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
210{
211 return EOK;
212}
213
214/** Close device. */
215static errno_t file_bd_close(bd_srv_t *bd)
216{
217 return EOK;
218}
219
220/** Read blocks from the device. */
221static errno_t file_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, void *buf,
222 size_t size)
223{
224 size_t n_rd;
225
226 if (size < cnt * block_size)
227 return EINVAL;
228
229 /* Check whether access is within device address bounds. */
230 if (ba + cnt > num_blocks) {
231 printf(NAME ": Accessed blocks %" PRIuOFF64 "-%" PRIuOFF64 ", while "
232 "max block number is %" PRIuOFF64 ".\n", ba, ba + cnt - 1,
233 num_blocks - 1);
234 return ELIMIT;
235 }
236
237 fibril_mutex_lock(&dev_lock);
238
239 clearerr(img);
240 if (fseek(img, ba * block_size, SEEK_SET) < 0) {
241 fibril_mutex_unlock(&dev_lock);
242 return EIO;
243 }
244
245 n_rd = fread(buf, block_size, cnt, img);
246
247 if (ferror(img)) {
248 fibril_mutex_unlock(&dev_lock);
249 return EIO; /* Read error */
250 }
251
252 fibril_mutex_unlock(&dev_lock);
253
254 if (n_rd < cnt)
255 return EINVAL; /* Read beyond end of device */
256
257 return EOK;
258}
259
260/** Write blocks to the device. */
261static errno_t file_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
262 const void *buf, size_t size)
263{
264 size_t n_wr;
265
266 if (size < cnt * block_size)
267 return EINVAL;
268
269 /* Check whether access is within device address bounds. */
270 if (ba + cnt > num_blocks) {
271 printf(NAME ": Accessed blocks %" PRIuOFF64 "-%" PRIuOFF64 ", while "
272 "max block number is %" PRIuOFF64 ".\n", ba, ba + cnt - 1,
273 num_blocks - 1);
274 return ELIMIT;
275 }
276
277 fibril_mutex_lock(&dev_lock);
278
279 clearerr(img);
280 if (fseek(img, ba * block_size, SEEK_SET) < 0) {
281 fibril_mutex_unlock(&dev_lock);
282 return EIO;
283 }
284
285 n_wr = fwrite(buf, block_size, cnt, img);
286
287 if (ferror(img) || n_wr < cnt) {
288 fibril_mutex_unlock(&dev_lock);
289 return EIO; /* Write error */
290 }
291
292 if (fflush(img) != 0) {
293 fibril_mutex_unlock(&dev_lock);
294 return EIO;
295 }
296
297 fibril_mutex_unlock(&dev_lock);
298
299 return EOK;
300}
301
302/** Get device block size. */
303static errno_t file_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
304{
305 *rsize = block_size;
306 return EOK;
307}
308
309/** Get number of blocks on device. */
310static errno_t file_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
311{
312 *rnb = num_blocks;
313 return EOK;
314}
315
316/**
317 * @}
318 */
Note: See TracBrowser for help on using the repository browser.