52bc51f130d0db9120659a79706d098cd0b4ea7f
[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 }