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