OSDN Git Service

vold: add class AutoVolume to support auto-mount and fake sdcard
[android-x86/system-vold.git] / main.cpp
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 "AutoVolume.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         const char *sdcard = 0;
177         if ((fp = fopen("/proc/cmdline", "r"))) {
178             while (fscanf(fp, "%s", line) > 0) {
179                 if (!strncmp(line, "SDCARD=", 7)) {
180                     sdcard = line + 7;
181                     break;
182                 }
183             }
184             fclose(fp);
185         }
186         // FIXME: should not hardcode the label and mount_point
187         AutoVolume *dv = new AutoVolume(vm, "sdcard", "/mnt/sdcard", sdcard);
188         vm->addVolume(dv);
189         return 0;
190     }
191
192     while(fgets(line, sizeof(line), fp)) {
193         const char *delim = " \t";
194         char *save_ptr;
195         char *type, *label, *mount_point;
196
197         n++;
198         line[strlen(line)-1] = '\0';
199
200         if (line[0] == '#' || line[0] == '\0')
201             continue;
202
203         if (!(type = strtok_r(line, delim, &save_ptr))) {
204             SLOGE("Error parsing type");
205             goto out_syntax;
206         }
207         if (!(label = strtok_r(NULL, delim, &save_ptr))) {
208             SLOGE("Error parsing label");
209             goto out_syntax;
210         }
211         if (!(mount_point = strtok_r(NULL, delim, &save_ptr))) {
212             SLOGE("Error parsing mount point");
213             goto out_syntax;
214         }
215
216         if (!strcmp(type, "dev_mount")) {
217             DirectVolume *dv = NULL;
218             char *part;
219
220             if (!(part = strtok_r(NULL, delim, &save_ptr))) {
221                 SLOGE("Error parsing partition");
222                 goto out_syntax;
223             }
224             if (int idx = (strcmp(part, "auto") ? atoi(part) : -1)) {
225                 dv = new DirectVolume(vm, label, mount_point, idx);
226             } else {
227                 SLOGE("Partition must either be 'auto' or 1 based index instead of '%s'", part);
228                 goto out_syntax;
229             }
230
231             while (char *sysfs_path = strtok_r(NULL, delim, &save_ptr)) {
232                 if (dv->addPath(sysfs_path)) {
233                     SLOGE("Failed to add devpath %s to volume %s", sysfs_path,
234                          label);
235                     goto out_fail;
236                 }
237             }
238             vm->addVolume(dv);
239         } else if (!strcmp(type, "map_mount")) {
240         } else {
241             SLOGE("Unknown type '%s'", type);
242             goto out_syntax;
243         }
244     }
245
246     fclose(fp);
247     return 0;
248
249 out_syntax:
250     SLOGE("Syntax error on config line %d", n);
251     errno = -EINVAL;
252 out_fail:
253     fclose(fp);
254     return -1;   
255 }