libfstools: fit: improve fit_volume_find string handling
[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 #include <sys/sysmacros.h>
19
20 #include "libfstools.h"
21
22 int
23 find_overlay_mount(char *overlay)
24 {
25 FILE *fp = fopen("/proc/mounts", "r");
26 size_t len = strlen(overlay);
27 static char line[256];
28 int ret = -1;
29
30 if(!fp)
31 return ret;
32
33 while (ret && fgets(line, sizeof(line), fp))
34 if (len < sizeof(line) && !strncmp(line, overlay, len) && line[len] == ' ')
35 ret = 0;
36
37 fclose(fp);
38
39 return ret;
40 }
41
42 /*
43 * Find path of a device mounted to the given point.
44 */
45 char*
46 find_mount(char *mp)
47 {
48 FILE *fp = fopen("/proc/mounts", "r");
49 static char line[256];
50
51 if(!fp)
52 return NULL;
53
54 while (fgets(line, sizeof(line), fp)) {
55 char *s, *t = strstr(line, " ");
56
57 if (!t) {
58 fclose(fp);
59 return NULL;
60 }
61 *t = '\0';
62 t++;
63 s = strstr(t, " ");
64 if (!s) {
65 fclose(fp);
66 return NULL;
67 }
68 *s = '\0';
69
70 if (!strcmp(t, mp)) {
71 fclose(fp);
72 return line;
73 }
74 }
75
76 fclose(fp);
77
78 return NULL;
79 }
80
81 /*
82 * Match filesystem type against a bunch of valid types
83 *
84 * jffs2reset may ask if the filesystem type is actually ready for use
85 * with overlayfs before wiping it...
86 */
87 static int fs_rootfs_only(char *fstype)
88 {
89 if (strncmp(fstype, "ext4", 4) &&
90 strncmp(fstype, "f2fs", 4) &&
91 strncmp(fstype, "jffs2", 5) &&
92 strncmp(fstype, "ubifs", 5)) {
93 ULOG_ERR("block is mounted with wrong fs\n");
94 return 1;
95 }
96 return 0;
97 }
98
99 /*
100 * Check if a given device is mounted and return its mountpoint
101 */
102 char*
103 find_mount_point(char *block, int root_only)
104 {
105 FILE *fp = fopen("/proc/self/mountinfo", "r");
106 static char line[256];
107 char *point = NULL, *pos, *tmp, *cpoint, *devname, *fstype;
108 struct stat s;
109 int rstat;
110 unsigned int minor, major;
111
112 if (!block)
113 return NULL;
114
115 if (!fp)
116 return NULL;
117
118 rstat = stat(block, &s);
119
120 while (fgets(line, sizeof(line), fp)) {
121 /* skip first two columns */
122 pos = strchr(line, ' ');
123 if (!pos)
124 continue;
125
126 pos = strchr(pos + 1, ' ');
127 if (!pos)
128 continue;
129
130 /* extract block device major:minor */
131 tmp = ++pos;
132 pos = strchr(pos, ':');
133 if (!pos)
134 continue;
135
136 *pos = '\0';
137 major = atoi(tmp);
138
139 tmp = ++pos;
140 pos = strchr(pos, ' ');
141 if (!pos)
142 continue;
143
144 *pos = '\0';
145 minor = atoi(tmp);
146
147 /* skip another column */
148 pos = strchr(pos + 1, ' ');
149 if (!pos)
150 continue;
151
152 /* get mountpoint */
153 tmp = ++pos;
154 pos = strchr(pos, ' ');
155 if (!pos)
156 continue;
157
158 *pos = '\0';
159 cpoint = tmp;
160
161 /* skip another two columns */
162 pos = strchr(pos + 1, ' ');
163 if (!pos)
164 continue;
165
166 pos = strchr(pos + 1, ' ');
167 if (!pos)
168 continue;
169
170 /* get fstype */
171 tmp = ++pos;
172 pos = strchr(pos, ' ');
173 if (!pos)
174 continue;
175
176 *pos = '\0';
177 fstype = tmp;
178
179 /* get device name */
180 tmp = ++pos;
181 pos = strchr(pos, ' ');
182 if (!pos)
183 continue;
184
185 *pos = '\0';
186 devname = tmp;
187
188 /* if device name matches */
189 if (!strcmp(block, devname)) {
190 if (root_only && fs_rootfs_only(fstype))
191 break;
192
193 /* found, return mountpoint */
194 point = strdup(cpoint);
195 break;
196 }
197
198 /* last chance: check if major:minor of block device match */
199 if (rstat)
200 continue;
201
202 if (!S_ISBLK(s.st_mode))
203 continue;
204
205 if (major == major(s.st_rdev) &&
206 minor == minor(s.st_rdev)) {
207 if (root_only && fs_rootfs_only(fstype))
208 break;
209
210 /* found, return mountpoint */
211 point = strdup(cpoint);
212 break;
213 }
214 }
215
216 fclose(fp);
217
218 return point;
219 }
220
221 int
222 find_filesystem(char *fs)
223 {
224 FILE *fp = fopen("/proc/filesystems", "r");
225 static char line[256];
226 int ret = -1;
227
228 if (!fp) {
229 ULOG_ERR("opening /proc/filesystems failed: %m\n");
230 goto out;
231 }
232
233 while (ret && fgets(line, sizeof(line), fp))
234 if (strstr(line, fs))
235 ret = 0;
236
237 fclose(fp);
238
239 out:
240 return ret;
241 }