• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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