1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <assert.h>
18 #include <errno.h>
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <unistd.h>
22
23 #include <ublock/ublock.h>
24
25 #include "fatblock.h"
26 #include "fs.h"
27 #include "utils.h"
28
29 static struct fs fs;
30 static struct ublock_ctx *ub;
31 static int ums_lun = 0;
32
fs_import(struct fs * fs,uint16_t cluster_size,offset_t data_size,offset_t * total_size_out)33 static int fs_import(struct fs *fs,
34 uint16_t cluster_size, offset_t data_size,
35 offset_t *total_size_out)
36 {
37 int ret;
38
39 ret = fs_init(fs, cluster_size, data_size, total_size_out);
40 if (ret)
41 return ret;
42
43 ret = import_tree(fs, ".");
44 if (ret)
45 return ret;
46
47 return 0;
48 }
49
50
51
read_callback(char * buf,uint64_t length,uint64_t offset)52 static int read_callback(char *buf, uint64_t length, uint64_t offset)
53 {
54 int result;
55 int i;
56
57 result = fs_read(&fs, buf, offset, length);
58 if (result == SKY_IS_FALLING) {
59 WARN("underlying filesystem has been modified; stopping.\n");
60 ublock_stop(ub);
61 }
62
63 return result ? -EINVAL : 0;
64 }
65
write_callback(const char * buf,uint64_t length,uint64_t offset)66 static int write_callback(const char *buf, uint64_t length, uint64_t offset)
67 {
68 DEBUG("writing to (%llu, %llu): we are read-only\n", offset, length);
69
70 return -EINVAL;
71 }
72
73 static struct ublock_ops ops = {
74 .read = &read_callback,
75 .write = &write_callback
76 };
77
78
79
set_ums_file(int index)80 static int set_ums_file(int index)
81 {
82 char filename[PATH_MAX];
83 FILE *file;
84
85 sprintf(filename, "/sys/devices/platform/usb_mass_storage/lun%d/file",
86 ums_lun);
87 file = fopen(filename, "w");
88 if (!file) {
89 WARN("setting USB mass storage file: fopen(%s) failed: %s\n",
90 filename, strerror(errno));
91 return -1;
92 }
93
94 WARN("writing '/dev/block/ublock%d' to %s.\n", index, filename);
95
96 fprintf(file, "/dev/block/ublock%d", index);
97
98 fclose(file);
99
100 return 0;
101 }
102
clear_ums_file(void)103 static int clear_ums_file(void)
104 {
105 char filename[PATH_MAX];
106 FILE *file;
107
108 sprintf(filename, "/sys/devices/platform/usb_mass_storage/lun%d/file",
109 ums_lun);
110 file = fopen(filename, "w");
111 if (!file) {
112 WARN("clearing USB mass storage file: fopen(%s) failed: %s\n",
113 filename, strerror(errno));
114 return -1;
115 }
116
117 fclose(file);
118
119 return 0;
120 }
121
122
123
124
cleanup(void)125 static void cleanup(void)
126 {
127 WARN("cleanup: clearing USB mass storage file\n");
128 clear_ums_file();
129 WARN("cleanup: destroying block device\n");
130 ublock_destroy(ub);
131 }
132
signal_handler(int sig)133 static void signal_handler(int sig)
134 {
135 WARN("received signal %d\n", sig);
136 cleanup();
137 exit(0);
138 }
139
140 static int normal_exit = 0;
141
atexit_handler(void)142 static void atexit_handler(void)
143 {
144 if (normal_exit)
145 return;
146
147 cleanup();
148 }
149
main(int argc,char * argv[])150 int main(int argc, char *argv[]) {
151 char *path;
152 int mb;
153 offset_t total_size;
154 int index;
155 int ret;
156
157 signal(SIGINT, &signal_handler);
158 signal(SIGTERM, &signal_handler);
159 atexit(&atexit_handler);
160
161 if (argc != 3)
162 DIE("Usage: fatblock <path> <size in MB>\n");
163
164 path = argv[1];
165 mb = atoi(argv[2]);
166
167 INFO("fatblock: importing filesystem from %s (%d MB)\n", path, mb);
168
169 ret = chdir(path);
170 if (ret < 0)
171 DIE("fatblock: chdir(%s) failed: %s; aborting\n", path, strerror(errno));
172
173 ret = fs_import(&fs, 32768, 1048576LL * mb, &total_size);
174 if (ret)
175 DIE("fatblock: couldn't import filesystem; aborting\n");
176
177 INFO("fatblock: filesystem imported (%llu bytes)\n", total_size);
178
179 ret = ublock_init(&ub, &ops, total_size);
180 if (ret)
181 DIE("fatblock: couldn't create block device; aborting\n");
182 index = ublock_index(ub);
183 if (index < 0)
184 DIE("fatblock: invalid ublock index %d; aborting\n", index);
185
186 INFO("fatblock: block device ublock%d created\n", index);
187 set_ums_file(index);
188
189 INFO("fatblock: entering main loop\n");
190 ublock_run(ub);
191
192 INFO("fatblock: destroying block device\n");
193 clear_ums_file();
194 ublock_destroy(ub);
195
196 normal_exit = 1;
197
198 INFO("fatblock: goodbye!\n");
199 return 0;
200 }
201