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