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 #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