Home | History | Annotate | Download | only in mtdutils
      1 /*
      2  * Copyright (C) 2007 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 <string.h>
     20 #include <fcntl.h>
     21 #include <errno.h>
     22 #include <sys/mount.h>
     23 
     24 #include "mounts.h"
     25 
     26 struct MountedVolume {
     27     const char *device;
     28     const char *mount_point;
     29     const char *filesystem;
     30     const char *flags;
     31 };
     32 
     33 typedef struct {
     34     MountedVolume *volumes;
     35     int volumes_allocd;
     36     int volume_count;
     37 } MountsState;
     38 
     39 static MountsState g_mounts_state = {
     40     NULL,   // volumes
     41     0,      // volumes_allocd
     42     0       // volume_count
     43 };
     44 
     45 static inline void
     46 free_volume_internals(const MountedVolume *volume, int zero)
     47 {
     48     free((char *)volume->device);
     49     free((char *)volume->mount_point);
     50     free((char *)volume->filesystem);
     51     free((char *)volume->flags);
     52     if (zero) {
     53         memset((void *)volume, 0, sizeof(*volume));
     54     }
     55 }
     56 
     57 #define PROC_MOUNTS_FILENAME   "/proc/mounts"
     58 
     59 int
     60 scan_mounted_volumes()
     61 {
     62     char buf[2048];
     63     const char *bufp;
     64     int fd;
     65     ssize_t nbytes;
     66 
     67     if (g_mounts_state.volumes == NULL) {
     68         const int numv = 32;
     69         MountedVolume *volumes = malloc(numv * sizeof(*volumes));
     70         if (volumes == NULL) {
     71             errno = ENOMEM;
     72             return -1;
     73         }
     74         g_mounts_state.volumes = volumes;
     75         g_mounts_state.volumes_allocd = numv;
     76         memset(volumes, 0, numv * sizeof(*volumes));
     77     } else {
     78         /* Free the old volume strings.
     79          */
     80         int i;
     81         for (i = 0; i < g_mounts_state.volume_count; i++) {
     82             free_volume_internals(&g_mounts_state.volumes[i], 1);
     83         }
     84     }
     85     g_mounts_state.volume_count = 0;
     86 
     87     /* Open and read the file contents.
     88      */
     89     fd = open(PROC_MOUNTS_FILENAME, O_RDONLY);
     90     if (fd < 0) {
     91         goto bail;
     92     }
     93     nbytes = read(fd, buf, sizeof(buf) - 1);
     94     close(fd);
     95     if (nbytes < 0) {
     96         goto bail;
     97     }
     98     buf[nbytes] = '\0';
     99 
    100     /* Parse the contents of the file, which looks like:
    101      *
    102      *     # cat /proc/mounts
    103      *     rootfs / rootfs rw 0 0
    104      *     /dev/pts /dev/pts devpts rw 0 0
    105      *     /proc /proc proc rw 0 0
    106      *     /sys /sys sysfs rw 0 0
    107      *     /dev/block/mtdblock4 /system yaffs2 rw,nodev,noatime,nodiratime 0 0
    108      *     /dev/block/mtdblock5 /data yaffs2 rw,nodev,noatime,nodiratime 0 0
    109      *     /dev/block/mmcblk0p1 /sdcard vfat rw,sync,dirsync,fmask=0000,dmask=0000,codepage=cp437,iocharset=iso8859-1,utf8 0 0
    110      *
    111      * The zeroes at the end are dummy placeholder fields to make the
    112      * output match Linux's /etc/mtab, but don't represent anything here.
    113      */
    114     bufp = buf;
    115     while (nbytes > 0) {
    116         char device[64];
    117         char mount_point[64];
    118         char filesystem[64];
    119         char flags[128];
    120         int matches;
    121 
    122         /* %as is a gnu extension that malloc()s a string for each field.
    123          */
    124         matches = sscanf(bufp, "%63s %63s %63s %127s",
    125                 device, mount_point, filesystem, flags);
    126 
    127         if (matches == 4) {
    128             device[sizeof(device)-1] = '\0';
    129             mount_point[sizeof(mount_point)-1] = '\0';
    130             filesystem[sizeof(filesystem)-1] = '\0';
    131             flags[sizeof(flags)-1] = '\0';
    132 
    133             MountedVolume *v =
    134                     &g_mounts_state.volumes[g_mounts_state.volume_count++];
    135             v->device = strdup(device);
    136             v->mount_point = strdup(mount_point);
    137             v->filesystem = strdup(filesystem);
    138             v->flags = strdup(flags);
    139         } else {
    140 printf("matches was %d on <<%.40s>>\n", matches, bufp);
    141         }
    142 
    143         /* Eat the line.
    144          */
    145         while (nbytes > 0 && *bufp != '\n') {
    146             bufp++;
    147             nbytes--;
    148         }
    149         if (nbytes > 0) {
    150             bufp++;
    151             nbytes--;
    152         }
    153     }
    154 
    155     return 0;
    156 
    157 bail:
    158 //TODO: free the strings we've allocated.
    159     g_mounts_state.volume_count = 0;
    160     return -1;
    161 }
    162 
    163 const MountedVolume *
    164 find_mounted_volume_by_device(const char *device)
    165 {
    166     if (g_mounts_state.volumes != NULL) {
    167         int i;
    168         for (i = 0; i < g_mounts_state.volume_count; i++) {
    169             MountedVolume *v = &g_mounts_state.volumes[i];
    170             /* May be null if it was unmounted and we haven't rescanned.
    171              */
    172             if (v->device != NULL) {
    173                 if (strcmp(v->device, device) == 0) {
    174                     return v;
    175                 }
    176             }
    177         }
    178     }
    179     return NULL;
    180 }
    181 
    182 const MountedVolume *
    183 find_mounted_volume_by_mount_point(const char *mount_point)
    184 {
    185     if (g_mounts_state.volumes != NULL) {
    186         int i;
    187         for (i = 0; i < g_mounts_state.volume_count; i++) {
    188             MountedVolume *v = &g_mounts_state.volumes[i];
    189             /* May be null if it was unmounted and we haven't rescanned.
    190              */
    191             if (v->mount_point != NULL) {
    192                 if (strcmp(v->mount_point, mount_point) == 0) {
    193                     return v;
    194                 }
    195             }
    196         }
    197     }
    198     return NULL;
    199 }
    200 
    201 int
    202 unmount_mounted_volume(const MountedVolume *volume)
    203 {
    204     /* Intentionally pass NULL to umount if the caller tries
    205      * to unmount a volume they already unmounted using this
    206      * function.
    207      */
    208     int ret = umount(volume->mount_point);
    209     if (ret == 0) {
    210         free_volume_internals(volume, 1);
    211         return 0;
    212     }
    213     return ret;
    214 }
    215 
    216 int
    217 remount_read_only(const MountedVolume* volume)
    218 {
    219     return mount(volume->device, volume->mount_point, volume->filesystem,
    220                  MS_NOATIME | MS_NODEV | MS_NODIRATIME |
    221                  MS_RDONLY | MS_REMOUNT, 0);
    222 }
    223