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 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 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 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 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 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 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 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 142 static void atexit_handler(void) 143 { 144 if (normal_exit) 145 return; 146 147 cleanup(); 148 } 149 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