blob: 6a9b03d3034c288fa39a3468cad462d7faafac35 [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
Yabin Cuia382e2b2015-01-02 14:00:13 -080017#include <mntent.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080018#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
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{
Yabin Cuia382e2b2015-01-02 14:00:13 -080063 FILE* fp;
64 struct mntent* mentry;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080065
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
Yabin Cuia382e2b2015-01-02 14:00:13 -080086 /* Open and read mount table entries. */
87 fp = setmntent(PROC_MOUNTS_FILENAME, "r");
88 if (fp == NULL) {
89 return -1;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080090 }
Yabin Cuia382e2b2015-01-02 14:00:13 -080091 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);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080097 }
Yabin Cuia382e2b2015-01-02 14:00:13 -080098 endmntent(fp);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080099 return 0;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800100}
101
102const MountedVolume *
103find_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
121const MountedVolume *
122find_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
140int
141unmount_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}
Doug Zongker8e5e4da2010-09-14 18:06:55 -0700154
155int
156remount_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}