main.cpp revision 79e31bedcaabcca55aaf40a9de61abed11c9a2e0
1/* 2 * Copyright (C) 2008 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 <stdio.h> 18#include <stdlib.h> 19#include <errno.h> 20#include <string.h> 21#include <sys/stat.h> 22#include <sys/types.h> 23 24#include <fcntl.h> 25#include <dirent.h> 26 27#define LOG_TAG "Vold" 28 29#include "cutils/log.h" 30 31#include "VolumeManager.h" 32#include "CommandListener.h" 33#include "NetlinkManager.h" 34#include "DirectVolume.h" 35 36static int process_config(VolumeManager *vm); 37static void coldboot(const char *path); 38 39int main() { 40 41 VolumeManager *vm; 42 CommandListener *cl; 43 NetlinkManager *nm; 44 45 LOGI("Vold 2.0 (the revenge) firing up"); 46 47 mkdir("/dev/block/vold", 0755); 48 49 /* Create our singleton managers */ 50 if (!(vm = VolumeManager::Instance())) { 51 LOGE("Unable to create VolumeManager"); 52 exit(1); 53 }; 54 55 if (!(nm = NetlinkManager::Instance())) { 56 LOGE("Unable to create NetlinkManager"); 57 exit(1); 58 }; 59 60 61 cl = new CommandListener(); 62 vm->setBroadcaster((SocketListener *) cl); 63 nm->setBroadcaster((SocketListener *) cl); 64 65 if (vm->start()) { 66 LOGE("Unable to start VolumeManager (%s)", strerror(errno)); 67 exit(1); 68 } 69 70 if (process_config(vm)) { 71 LOGE("Error reading configuration (%s)", strerror(errno)); 72 exit(1); 73 } 74 75 if (nm->start()) { 76 LOGE("Unable to start NetlinkManager (%s)", strerror(errno)); 77 exit(1); 78 } 79 80 coldboot("/sys/block"); 81 /* 82 * Switch uevents are broken. 83 * For now we manually bootstrap 84 * the ums switch 85 */ 86 { 87 FILE *fp; 88 char state[255]; 89 90 if ((fp = fopen("/sys/devices/virtual/switch/usb_mass_storage/state", 91 "r"))) { 92 if (!fgets(state, sizeof(state), fp)) { 93 LOGE("Failed to read switch state (%s)", strerror(errno)); 94 fclose(fp); 95 exit(1); 96 } 97 if (!strncmp(state, "online", 6)) { 98 LOGD("Bootstrapped ums is connected"); 99 vm->notifyUmsConnected(true); 100 } else { 101 LOGD("Bootstrapped ums is disconnected"); 102 vm->notifyUmsConnected(false); 103 } 104 fclose(fp); 105 } else { 106 LOGW("No UMS switch available"); 107 } 108 } 109// coldboot("/sys/class/switch"); 110 111 /* 112 * Now that we're up, we can respond to commands 113 */ 114 if (cl->startListener()) { 115 LOGE("Unable to start CommandListener (%s)", strerror(errno)); 116 exit(1); 117 } 118 119 // Eventually we'll become the monitoring thread 120 while(1) { 121 sleep(1000); 122 } 123 124 LOGI("Vold exiting"); 125 exit(0); 126} 127 128static void do_coldboot(DIR *d, int lvl) 129{ 130 struct dirent *de; 131 int dfd, fd; 132 133 dfd = dirfd(d); 134 135 fd = openat(dfd, "uevent", O_WRONLY); 136 if(fd >= 0) { 137 write(fd, "add\n", 4); 138 close(fd); 139 } 140 141 while((de = readdir(d))) { 142 DIR *d2; 143 144 if (de->d_name[0] == '.') 145 continue; 146 147 if (de->d_type != DT_DIR && lvl > 0) 148 continue; 149 150 fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY); 151 if(fd < 0) 152 continue; 153 154 d2 = fdopendir(fd); 155 if(d2 == 0) 156 close(fd); 157 else { 158 do_coldboot(d2, lvl + 1); 159 closedir(d2); 160 } 161 } 162} 163 164static void coldboot(const char *path) 165{ 166 DIR *d = opendir(path); 167 if(d) { 168 do_coldboot(d, 0); 169 closedir(d); 170 } 171} 172 173static int process_config(VolumeManager *vm) { 174 FILE *fp; 175 int n = 0; 176 char line[255]; 177 178 if (!(fp = fopen("/etc/vold.fstab", "r"))) { 179 return -1; 180 } 181 182 while(fgets(line, sizeof(line), fp)) { 183 char *next = line; 184 char *type, *label, *mount_point; 185 186 n++; 187 line[strlen(line)-1] = '\0'; 188 189 if (line[0] == '#' || line[0] == '\0') 190 continue; 191 192 if (!(type = strsep(&next, " \t"))) { 193 LOGE("Error parsing type"); 194 goto out_syntax; 195 } 196 if (!(label = strsep(&next, " \t"))) { 197 LOGE("Error parsing label"); 198 goto out_syntax; 199 } 200 if (!(mount_point = strsep(&next, " \t"))) { 201 LOGE("Error parsing mount point"); 202 goto out_syntax; 203 } 204 205 if (!strcmp(type, "dev_mount")) { 206 DirectVolume *dv = NULL; 207 char *part, *sysfs_path; 208 209 if (!(part = strsep(&next, " \t"))) { 210 LOGE("Error parsing partition"); 211 goto out_syntax; 212 } 213 if (strcmp(part, "auto") && atoi(part) == 0) { 214 LOGE("Partition must either be 'auto' or 1 based index instead of '%s'", part); 215 goto out_syntax; 216 } 217 218 if (!strcmp(part, "auto")) { 219 dv = new DirectVolume(vm, label, mount_point, -1); 220 } else { 221 dv = new DirectVolume(vm, label, mount_point, atoi(part)); 222 } 223 224 while((sysfs_path = strsep(&next, " \t"))) { 225 if (dv->addPath(sysfs_path)) { 226 LOGE("Failed to add devpath %s to volume %s", sysfs_path, 227 label); 228 goto out_fail; 229 } 230 } 231 vm->addVolume(dv); 232 } else if (!strcmp(type, "map_mount")) { 233 } else { 234 LOGE("Unknown type '%s'", type); 235 goto out_syntax; 236 } 237 } 238 239 fclose(fp); 240 return 0; 241 242out_syntax: 243 LOGE("Syntax error on config line %d", n); 244 errno = -EINVAL; 245out_fail: 246 fclose(fp); 247 return -1; 248} 249