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 <mntent.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <fcntl.h> 22 #include <errno.h> 23 #include <sys/mount.h> 24 25 #include "mounts.h" 26 27 struct MountedVolume { 28 const char *device; 29 const char *mount_point; 30 const char *filesystem; 31 const char *flags; 32 }; 33 34 typedef struct { 35 MountedVolume *volumes; 36 int volumes_allocd; 37 int volume_count; 38 } MountsState; 39 40 static MountsState g_mounts_state = { 41 NULL, // volumes 42 0, // volumes_allocd 43 0 // volume_count 44 }; 45 46 static inline void 47 free_volume_internals(const MountedVolume *volume, int zero) 48 { 49 free((char *)volume->device); 50 free((char *)volume->mount_point); 51 free((char *)volume->filesystem); 52 free((char *)volume->flags); 53 if (zero) { 54 memset((void *)volume, 0, sizeof(*volume)); 55 } 56 } 57 58 #define PROC_MOUNTS_FILENAME "/proc/mounts" 59 60 int 61 scan_mounted_volumes() 62 { 63 FILE* fp; 64 struct mntent* mentry; 65 66 if (g_mounts_state.volumes == NULL) { 67 const int numv = 32; 68 MountedVolume *volumes = malloc(numv * sizeof(*volumes)); 69 if (volumes == NULL) { 70 errno = ENOMEM; 71 return -1; 72 } 73 g_mounts_state.volumes = volumes; 74 g_mounts_state.volumes_allocd = numv; 75 memset(volumes, 0, numv * sizeof(*volumes)); 76 } else { 77 /* Free the old volume strings. 78 */ 79 int i; 80 for (i = 0; i < g_mounts_state.volume_count; i++) { 81 free_volume_internals(&g_mounts_state.volumes[i], 1); 82 } 83 } 84 g_mounts_state.volume_count = 0; 85 86 /* Open and read mount table entries. */ 87 fp = setmntent(PROC_MOUNTS_FILENAME, "r"); 88 if (fp == NULL) { 89 return -1; 90 } 91 while ((mentry = getmntent(fp)) != NULL) { 92 MountedVolume* v = &g_mounts_state.volumes[g_mounts_state.volume_count++]; 93 v->device = strdup(mentry->mnt_fsname); 94 v->mount_point = strdup(mentry->mnt_dir); 95 v->filesystem = strdup(mentry->mnt_type); 96 v->flags = strdup(mentry->mnt_opts); 97 } 98 endmntent(fp); 99 return 0; 100 } 101 102 const MountedVolume * 103 find_mounted_volume_by_device(const char *device) 104 { 105 if (g_mounts_state.volumes != NULL) { 106 int i; 107 for (i = 0; i < g_mounts_state.volume_count; i++) { 108 MountedVolume *v = &g_mounts_state.volumes[i]; 109 /* May be null if it was unmounted and we haven't rescanned. 110 */ 111 if (v->device != NULL) { 112 if (strcmp(v->device, device) == 0) { 113 return v; 114 } 115 } 116 } 117 } 118 return NULL; 119 } 120 121 const MountedVolume * 122 find_mounted_volume_by_mount_point(const char *mount_point) 123 { 124 if (g_mounts_state.volumes != NULL) { 125 int i; 126 for (i = 0; i < g_mounts_state.volume_count; i++) { 127 MountedVolume *v = &g_mounts_state.volumes[i]; 128 /* May be null if it was unmounted and we haven't rescanned. 129 */ 130 if (v->mount_point != NULL) { 131 if (strcmp(v->mount_point, mount_point) == 0) { 132 return v; 133 } 134 } 135 } 136 } 137 return NULL; 138 } 139 140 int 141 unmount_mounted_volume(const MountedVolume *volume) 142 { 143 /* Intentionally pass NULL to umount if the caller tries 144 * to unmount a volume they already unmounted using this 145 * function. 146 */ 147 int ret = umount(volume->mount_point); 148 if (ret == 0) { 149 free_volume_internals(volume, 1); 150 return 0; 151 } 152 return ret; 153 } 154 155 int 156 remount_read_only(const MountedVolume* volume) 157 { 158 return mount(volume->device, volume->mount_point, volume->filesystem, 159 MS_NOATIME | MS_NODEV | MS_NODIRATIME | 160 MS_RDONLY | MS_REMOUNT, 0); 161 } 162