libfstools: gather mountpoints from /proc/self/mountinfo
[project/fstools.git] / libfstools / find.c
1 /*
2 * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 2.1
6 * as published by the Free Software Foundation
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14 #include <errno.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <sys/stat.h>
18
19 #include "libfstools.h"
20
21 int
22 find_overlay_mount(char *overlay)
23 {
24 FILE *fp = fopen("/proc/mounts", "r");
25 static char line[256];
26 int ret = -1;
27
28 if(!fp)
29 return ret;
30
31 while (ret && fgets(line, sizeof(line), fp))
32 if (!strncmp(line, overlay, strlen(overlay)))
33 ret = 0;
34
35 fclose(fp);
36
37 return ret;
38 }
39
40 /*
41 * Find path of a device mounted to the given point.
42 */
43 char*
44 find_mount(char *mp)
45 {
46 FILE *fp = fopen("/proc/mounts", "r");
47 static char line[256];
48 char *point = NULL;
49
50 if(!fp)
51 return NULL;
52
53 while (fgets(line, sizeof(line), fp)) {
54 char *s, *t = strstr(line, " ");
55
56 if (!t) {
57 fclose(fp);
58 return NULL;
59 }
60 *t = '\0';
61 t++;
62 s = strstr(t, " ");
63 if (!s) {
64 fclose(fp);
65 return NULL;
66 }
67 *s = '\0';
68
69 if (!strcmp(t, mp)) {
70 fclose(fp);
71 return line;
72 }
73 }
74
75 fclose(fp);
76
77 return point;
78 }
79
80 /*
81 * Match filesystem type against a bunch of valid types
82 *
83 * jffs2reset may ask if the filesystem type is actually ready for use
84 * with overlayfs before wiping it...
85 */
86 static int fs_rootfs_only(char *fstype)
87 {
88 if (strncmp(fstype, "ext4", 4) &&
89 strncmp(fstype, "f2fs", 4) &&
90 strncmp(fstype, "jffs2", 5) &&
91 strncmp(fstype, "ubifs", 5)) {
92 ULOG_ERR("block is mounted with wrong fs\n");
93 return 1;
94 }
95 return 0;
96 }
97
98 /*
99 * Check if a given device is mounted and return its mountpoint
100 */
101 char*
102 find_mount_point(char *block, int root_only)
103 {
104 FILE *fp = fopen("/proc/self/mountinfo", "r");
105 static char line[256];
106 int len = strlen(block);
107 char *point = NULL, *pos, *tmp, *cpoint, *devname, *fstype;
108 struct stat s;
109 int rstat;
110 unsigned int minor, major;
111
112 if (!fp)
113 return NULL;
114
115 rstat = stat(block, &s);
116
117 while (fgets(line, sizeof(line), fp)) {
118 /* skip first two columns */
119 pos = strchr(line, ' ');
120 if (!pos)
121 continue;
122
123 pos = strchr(pos + 1, ' ');
124 if (!pos)
125 continue;
126
127 /* extract block device major:minor */
128 tmp = ++pos;
129 pos = strchr(pos, ':');
130 if (!pos)
131 continue;
132
133 *pos = '\0';
134 major = atoi(tmp);
135
136 tmp = ++pos;
137 pos = strchr(pos, ' ');
138 if (!pos)
139 continue;
140
141 *pos = '\0';
142 minor = atoi(tmp);
143
144 /* skip another column */
145 pos = strchr(pos + 1, ' ');
146 if (!pos)
147 continue;
148
149 /* get mountpoint */
150 tmp = ++pos;
151 pos = strchr(pos, ' ');
152 if (!pos)
153 continue;
154
155 *pos = '\0';
156 cpoint = tmp;
157
158 /* skip another two columns */
159 pos = strchr(pos + 1, ' ');
160 if (!pos)
161 continue;
162
163 pos = strchr(pos + 1, ' ');
164 if (!pos)
165 continue;
166
167 /* get fstype */
168 tmp = ++pos;
169 pos = strchr(pos, ' ');
170 if (!pos)
171 continue;
172
173 *pos = '\0';
174 fstype = tmp;
175
176 /* get device name */
177 tmp = ++pos;
178 pos = strchr(pos, ' ');
179 if (!pos)
180 continue;
181
182 *pos = '\0';
183 devname = tmp;
184
185 /* if device name matches */
186 if (!strncmp(block, devname, len)) {
187 if (root_only && fs_rootfs_only(fstype))
188 break;
189
190 /* found, return mountpoint */
191 point = strdup(cpoint);
192 break;
193 }
194
195 /* last chance: check if major:minor of block device match */
196 if (rstat)
197 continue;
198
199 if (!S_ISBLK(s.st_mode))
200 continue;
201
202 if (major == major(s.st_rdev) &&
203 minor == minor(s.st_rdev)) {
204 if (root_only && fs_rootfs_only(fstype))
205 break;
206
207 /* found, return mountpoint */
208 point = strdup(cpoint);
209 break;
210 }
211 }
212
213 fclose(fp);
214
215 return point;
216 }
217
218 int
219 find_filesystem(char *fs)
220 {
221 FILE *fp = fopen("/proc/filesystems", "r");
222 static char line[256];
223 int ret = -1;
224
225 if (!fp) {
226 ULOG_ERR("opening /proc/filesystems failed: %s\n", strerror(errno));
227 goto out;
228 }
229
230 while (ret && fgets(line, sizeof(line), fp))
231 if (strstr(line, fs))
232 ret = 0;
233
234 fclose(fp);
235
236 out:
237 return ret;
238 }