1 /* ----------------------------------------------------------------------- *
3 * Copyright 2012 Intel Corporation; All Rights Reserved
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
8 * Boston MA 02110-1301, USA; either version 2 of the License, or
9 * (at your option) any later version; incorporated herein by reference.
11 * ----------------------------------------------------------------------- */
20 #include <sys/sysmacros.h>
21 #include "mountinfo.h"
24 * Parse /proc/self/mountinfo
26 static int get_string(FILE *f
, char *string_buf
, size_t string_len
, char *ec
)
33 return -2; /* String too long */
37 return -1; /* Got EOF */
38 } else if (ch
== ' ' || ch
== '\t' || ch
== '\n') {
41 return p
- string_buf
;
42 } else if (ch
== '\\') {
43 /* Should always be followed by 3 octal digits in 000..377 */
46 for (i
= 0; i
< 3; i
++) {
48 if (ch
< '0' || ch
> '7' || (i
== 0 && ch
> '3'))
49 return -1; /* Bad escape sequence */
50 oc
= (oc
<< 3) + (ch
- '0');
53 return -1; /* We can't handle \000 */
63 static void free_mountinfo(struct mountinfo
*m
)
68 free((char *)m
->root
);
69 free((char *)m
->path
);
70 free((char *)m
->fstype
);
71 free((char *)m
->devpath
);
72 free((char *)m
->mountopt
);
79 static struct mountinfo
*head
= NULL
, **tail
= &head
;
81 static void parse_mountinfo(void)
84 struct mountinfo
*m
, *mm
;
85 char string_buf
[PATH_MAX
*8];
90 f
= fopen("/proc/self/mountinfo", "r");
95 m
= malloc(sizeof(struct mountinfo
));
98 memset(m
, 0, sizeof *m
);
100 n
= get_string(f
, string_buf
, sizeof string_buf
, &ec
);
101 if (n
< 0 || ec
== '\n')
104 m
->mountid
= strtoul(string_buf
, &ep
, 10);
108 n
= get_string(f
, string_buf
, sizeof string_buf
, &ec
);
109 if (n
< 0 || ec
== '\n')
112 m
->parentid
= strtoul(string_buf
, &ep
, 10);
116 n
= get_string(f
, string_buf
, sizeof string_buf
, &ec
);
117 if (n
< 0 || ec
== '\n')
120 if (sscanf(string_buf
, "%u:%u", &ma
, &mi
) != 2)
123 m
->dev
= makedev(ma
, mi
);
125 n
= get_string(f
, string_buf
, sizeof string_buf
, &ec
);
126 if (n
< 1 || ec
== '\n' || string_buf
[0] != '/')
129 m
->root
= strdup(string_buf
);
133 n
= get_string(f
, string_buf
, sizeof string_buf
, &ec
);
134 if (n
< 1 || ec
== '\n' || string_buf
[0] != '/')
137 m
->path
= strdup(string_buf
);
138 m
->pathlen
= (n
== 1) ? 0 : n
; /* Treat / as empty */
140 /* Skip tagged attributes */
142 n
= get_string(f
, string_buf
, sizeof string_buf
, &ec
);
143 if (n
< 0 || ec
== '\n')
145 } while (n
!= 1 || string_buf
[0] != '-');
147 n
= get_string(f
, string_buf
, sizeof string_buf
, &ec
);
148 if (n
< 0 || ec
== '\n')
151 m
->fstype
= strdup(string_buf
);
155 n
= get_string(f
, string_buf
, sizeof string_buf
, &ec
);
156 if (n
< 0 || ec
== '\n')
159 m
->devpath
= strdup(string_buf
);
163 n
= get_string(f
, string_buf
, sizeof string_buf
, &ec
);
167 m
->mountopt
= strdup(string_buf
);
171 /* Skip any previously unknown fields */
172 while (ec
!= '\n' && ec
!= EOF
)
182 /* Create parent links */
183 for (m
= head
; m
; m
= m
->next
) {
184 for (mm
= head
; mm
; mm
= mm
->next
) {
185 if (m
->parentid
== mm
->mountid
) {
187 if (!strcmp(m
->path
, mm
->path
))
188 mm
->hidden
= 1; /* Hidden under another mount */
195 const struct mountinfo
*find_mount(const char *path
, char **subpath
)
197 static int done_init
;
199 const struct mountinfo
*m
, *best
;
211 real_path
= realpath(path
, NULL
);
216 * Tricky business: we need the longest matching subpath
217 * which isn't a parent of the same subpath.
219 len
= strlen(real_path
);
222 for (m
= head
; m
; m
= m
->next
) {
224 continue; /* Hidden underneath another mount */
226 if (m
->pathlen
> len
)
227 continue; /* Cannot possibly match */
229 if (m
->pathlen
< matchlen
)
230 continue; /* No point in testing this one */
232 if (st
.st_dev
== m
->dev
&&
233 !memcmp(m
->path
, real_path
, m
->pathlen
) &&
234 (real_path
[m
->pathlen
] == '/' || real_path
[m
->pathlen
] == '\0')) {
235 matchlen
= m
->pathlen
;
240 if (best
&& subpath
) {
241 if (real_path
[best
->pathlen
] == '\0')
242 *subpath
= strdup("/");
244 *subpath
= strdup(real_path
+ best
->pathlen
);
252 int main(int argc
, char *argv
[])
255 const struct mountinfo
*m
;
260 for (i
= 1; i
< argc
; i
++) {
261 m
= find_mount(argv
[i
], &subpath
);
263 printf("%s: %s\n", argv
[i
], strerror(errno
));
267 printf("%s -> %s @ %s(%u,%u):%s %s %s\n",
268 argv
[i
], subpath
, m
->devpath
, major(m
->dev
), minor(m
->dev
),
269 m
->root
, m
->fstype
, m
->mountopt
);
270 printf("Usable device: %s\n", find_device(m
->dev
, m
->devpath
));