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