Home | History | Annotate | Download | only in vold
      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