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