fatblock.c revision 0cb61411eadd92b7202e045c1c9ec8df7fb636fe
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
29static struct fs fs;
30static struct ublock_ctx *ub;
31static int ums_lun = 0;
32
33static 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
52static 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
66static 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
73static struct ublock_ops ops = {
74	.read = &read_callback,
75	.write = &write_callback
76};
77
78
79
80static 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
103static 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
125static 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
133static void signal_handler(int sig)
134{
135	WARN("received signal %d\n", sig);
136	cleanup();
137	exit(0);
138}
139
140static int normal_exit = 0;
141
142static void atexit_handler(void)
143{
144	if (normal_exit)
145		return;
146
147	cleanup();
148}
149
150int 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