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