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 <fcntl.h>
     19 #include <unistd.h>
     20 #include <errno.h>
     21 #include <string.h>
     22 
     23 #include <sys/types.h>
     24 #include <sys/stat.h>
     25 
     26 #include <linux/kdev_t.h>
     27 
     28 #define LOG_TAG "Vold"
     29 
     30 #include <cutils/log.h>
     31 
     32 #include <sysutils/SocketClient.h>
     33 #include "Loop.h"
     34 
     35 int Loop::dumpState(SocketClient *c) {
     36     int i;
     37     int fd;
     38     char filename[256];
     39 
     40     for (i = 0; i < LOOP_MAX; i++) {
     41         struct loop_info li;
     42         int rc;
     43 
     44         sprintf(filename, "/dev/block/loop%d", i);
     45 
     46         if ((fd = open(filename, O_RDWR)) < 0) {
     47             if (errno != ENOENT) {
     48                 SLOGE("Unable to open %s (%s)", filename, strerror(errno));
     49             } else {
     50                 continue;
     51             }
     52             return -1;
     53         }
     54 
     55         rc = ioctl(fd, LOOP_GET_STATUS, &li);
     56         close(fd);
     57         if (rc < 0 && errno == ENXIO) {
     58             continue;
     59         }
     60 
     61         if (rc < 0) {
     62             SLOGE("Unable to get loop status for %s (%s)", filename,
     63                  strerror(errno));
     64             return -1;
     65         }
     66         char *tmp = NULL;
     67         asprintf(&tmp, "%s %d %d:%d %lu %d:%d %d 0x%x {%s}", filename, li.lo_number,
     68                 MAJOR(li.lo_device), MINOR(li.lo_device), li.lo_inode, MAJOR(li.lo_rdevice),
     69                         MINOR(li.lo_rdevice), li.lo_offset, li.lo_flags, li.lo_name);
     70         c->sendMsg(0, tmp, false);
     71         free(tmp);
     72     }
     73     return 0;
     74 }
     75 
     76 int Loop::lookupActive(const char *id, char *buffer, size_t len) {
     77     int i;
     78     int fd;
     79     char filename[256];
     80 
     81     memset(buffer, 0, len);
     82 
     83     for (i = 0; i < LOOP_MAX; i++) {
     84         struct loop_info li;
     85         int rc;
     86 
     87         sprintf(filename, "/dev/block/loop%d", i);
     88 
     89         if ((fd = open(filename, O_RDWR)) < 0) {
     90             if (errno != ENOENT) {
     91                 SLOGE("Unable to open %s (%s)", filename, strerror(errno));
     92             } else {
     93                 continue;
     94             }
     95             return -1;
     96         }
     97 
     98         rc = ioctl(fd, LOOP_GET_STATUS, &li);
     99         close(fd);
    100         if (rc < 0 && errno == ENXIO) {
    101             continue;
    102         }
    103 
    104         if (rc < 0) {
    105             SLOGE("Unable to get loop status for %s (%s)", filename,
    106                  strerror(errno));
    107             return -1;
    108         }
    109         if (!strncmp(li.lo_name, id, LO_NAME_SIZE)) {
    110             break;
    111         }
    112     }
    113 
    114     if (i == LOOP_MAX) {
    115         errno = ENOENT;
    116         return -1;
    117     }
    118     strncpy(buffer, filename, len -1);
    119     return 0;
    120 }
    121 
    122 int Loop::create(const char *id, const char *loopFile, char *loopDeviceBuffer, size_t len) {
    123     int i;
    124     int fd;
    125     char filename[256];
    126 
    127     for (i = 0; i < LOOP_MAX; i++) {
    128         struct loop_info li;
    129         int rc;
    130 
    131         sprintf(filename, "/dev/block/loop%d", i);
    132 
    133         /*
    134          * The kernel starts us off with 8 loop nodes, but more
    135          * are created on-demand if needed.
    136          */
    137         mode_t mode = 0660 | S_IFBLK;
    138         unsigned int dev = (0xff & i) | ((i << 12) & 0xfff00000) | (7 << 8);
    139         if (mknod(filename, mode, dev) < 0) {
    140             if (errno != EEXIST) {
    141                 SLOGE("Error creating loop device node (%s)", strerror(errno));
    142                 return -1;
    143             }
    144         }
    145 
    146         if ((fd = open(filename, O_RDWR)) < 0) {
    147             SLOGE("Unable to open %s (%s)", filename, strerror(errno));
    148             return -1;
    149         }
    150 
    151         rc = ioctl(fd, LOOP_GET_STATUS, &li);
    152         if (rc < 0 && errno == ENXIO)
    153             break;
    154 
    155         close(fd);
    156 
    157         if (rc < 0) {
    158             SLOGE("Unable to get loop status for %s (%s)", filename,
    159                  strerror(errno));
    160             return -1;
    161         }
    162     }
    163 
    164     if (i == LOOP_MAX) {
    165         SLOGE("Exhausted all loop devices");
    166         errno = ENOSPC;
    167         return -1;
    168     }
    169 
    170     strncpy(loopDeviceBuffer, filename, len -1);
    171 
    172     int file_fd;
    173 
    174     if ((file_fd = open(loopFile, O_RDWR)) < 0) {
    175         SLOGE("Unable to open %s (%s)", loopFile, strerror(errno));
    176         close(fd);
    177         return -1;
    178     }
    179 
    180     if (ioctl(fd, LOOP_SET_FD, file_fd) < 0) {
    181         SLOGE("Error setting up loopback interface (%s)", strerror(errno));
    182         close(file_fd);
    183         close(fd);
    184         return -1;
    185     }
    186 
    187     struct loop_info li;
    188 
    189     memset(&li, 0, sizeof(li));
    190     strncpy(li.lo_name, id, LO_NAME_SIZE);
    191 
    192     if (ioctl(fd, LOOP_SET_STATUS, &li) < 0) {
    193         SLOGE("Error setting loopback status (%s)", strerror(errno));
    194         close(file_fd);
    195         close(fd);
    196         return -1;
    197     }
    198 
    199     close(fd);
    200     close(file_fd);
    201 
    202     return 0;
    203 }
    204 
    205 int Loop::destroyByDevice(const char *loopDevice) {
    206     int device_fd;
    207 
    208     device_fd = open(loopDevice, O_RDONLY);
    209     if (device_fd < 0) {
    210         SLOGE("Failed to open loop (%d)", errno);
    211         return -1;
    212     }
    213 
    214     if (ioctl(device_fd, LOOP_CLR_FD, 0) < 0) {
    215         SLOGE("Failed to destroy loop (%d)", errno);
    216         close(device_fd);
    217         return -1;
    218     }
    219 
    220     close(device_fd);
    221     return 0;
    222 }
    223 
    224 int Loop::destroyByFile(const char *loopFile) {
    225     errno = ENOSYS;
    226     return -1;
    227 }
    228 
    229 int Loop::createImageFile(const char *file, unsigned int numSectors) {
    230     int fd;
    231 
    232     if ((fd = creat(file, 0600)) < 0) {
    233         SLOGE("Error creating imagefile (%s)", strerror(errno));
    234         return -1;
    235     }
    236 
    237     if (ftruncate(fd, numSectors * 512) < 0) {
    238         SLOGE("Error truncating imagefile (%s)", strerror(errno));
    239         close(fd);
    240         return -1;
    241     }
    242     close(fd);
    243     return 0;
    244 }
    245