blob: 2ab3ff60cf74460d2719234fda86b13e102dd35b [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>
22#include <sys/mount.h>
23
24#include "mounts.h"
25
26struct MountedVolume {
27 const char *device;
28 const char *mount_point;
29 const char *filesystem;
30 const char *flags;
31};
32
33typedef struct {
34 MountedVolume *volumes;
35 int volumes_allocd;
36 int volume_count;
37} MountsState;
38
39static MountsState g_mounts_state = {
40 NULL, // volumes
41 0, // volumes_allocd
42 0 // volume_count
43};
44
45static inline void
46free_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
59int
60scan_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 {
140printf("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
157bail:
158//TODO: free the strings we've allocated.
159 g_mounts_state.volume_count = 0;
160 return -1;
161}
162
163const MountedVolume *
164find_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
182const MountedVolume *
183find_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
201int
202unmount_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}