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
free_volume_internals(const MountedVolume * volume,int zero)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
scan_mounted_volumes()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 *
find_mounted_volume_by_device(const char * device)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 *
find_mounted_volume_by_mount_point(const char * mount_point)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
unmount_mounted_volume(const MountedVolume * volume)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
remount_read_only(const MountedVolume * volume)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