source: bootcd/isolinux/syslinux-6.03/extlinux/mountinfo.c @ dd1be7c

Last change on this file since dd1be7c was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 5.9 KB
Line 
1/* ----------------------------------------------------------------------- *
2 *
3 *   Copyright 2012 Intel Corporation; All Rights Reserved
4 *
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.
10 *
11 * ----------------------------------------------------------------------- */
12
13#include <stdio.h>
14#include <string.h>
15#include <limits.h>
16#include <stdlib.h>
17#include <errno.h>
18#include <unistd.h>
19#include <sys/stat.h>
20#include <sys/sysmacros.h>
21#include "mountinfo.h"
22
23/*
24 * Parse /proc/self/mountinfo
25 */
26static int get_string(FILE *f, char *string_buf, size_t string_len, char *ec)
27{
28    int ch;
29    char *p = string_buf;
30
31    for (;;) {
32        if (!string_len)
33            return -2;          /* String too long */
34
35        ch = getc(f);
36        if (ch == EOF) {
37            return -1;          /* Got EOF */
38        } else if (ch == ' ' || ch == '\t' || ch == '\n') {
39            *ec = ch;
40            *p = '\0';
41            return p - string_buf;
42        } else if (ch == '\\') {
43            /* Should always be followed by 3 octal digits in 000..377 */
44            int oc = 0;
45            int i;
46            for (i = 0; i < 3; i++) {
47                ch = getc(f);
48                if (ch < '0' || ch > '7' || (i == 0 && ch > '3'))
49                    return -1;  /* Bad escape sequence */
50                oc = (oc << 3) + (ch - '0');
51            }
52            if (!oc)
53                return -1;      /* We can't handle \000 */
54            *p++ = oc;
55            string_len--;
56        } else {
57            *p++ = ch;
58            string_len--;
59        }
60    }
61}
62
63static void free_mountinfo(struct mountinfo *m)
64{
65    struct mountinfo *nx;
66
67    while (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);
73        nx = m->next;
74        free(m);
75        m = nx;
76    }
77}
78
79static struct mountinfo *head = NULL, **tail = &head;
80
81static void parse_mountinfo(void)
82{
83    FILE *f;
84    struct mountinfo *m, *mm;
85    char string_buf[PATH_MAX*8];
86    int n;
87    char ec, *ep;
88    unsigned int ma, mi;
89
90    f = fopen("/proc/self/mountinfo", "r");
91    if (!f)
92        return;
93
94    for (;;) {
95        m = malloc(sizeof(struct mountinfo));
96        if (!m)
97            break;
98        memset(m, 0, sizeof *m);
99
100        n = get_string(f, string_buf, sizeof string_buf, &ec);
101        if (n < 0 || ec == '\n')
102            break;
103
104        m->mountid = strtoul(string_buf, &ep, 10);
105        if (*ep)
106            break;
107
108        n = get_string(f, string_buf, sizeof string_buf, &ec);
109        if (n < 0 || ec == '\n')
110            break;
111
112        m->parentid = strtoul(string_buf, &ep, 10);
113        if (*ep)
114            break;
115
116        n = get_string(f, string_buf, sizeof string_buf, &ec);
117        if (n < 0 || ec == '\n')
118            break;
119
120        if (sscanf(string_buf, "%u:%u", &ma, &mi) != 2)
121            break;
122
123        m->dev = makedev(ma, mi);
124
125        n = get_string(f, string_buf, sizeof string_buf, &ec);
126        if (n < 1 || ec == '\n' || string_buf[0] != '/')
127            break;
128
129        m->root = strdup(string_buf);
130        if (!m->root)
131            break;
132
133        n = get_string(f, string_buf, sizeof string_buf, &ec);
134        if (n < 1 || ec == '\n' || string_buf[0] != '/')
135            break;
136
137        m->path = strdup(string_buf);
138        m->pathlen = (n == 1) ? 0 : n; /* Treat / as empty */
139
140        /* Skip tagged attributes */
141        do {
142            n = get_string(f, string_buf, sizeof string_buf, &ec);
143            if (n < 0 || ec == '\n')
144                goto quit;
145        } while (n != 1 || string_buf[0] != '-');
146
147        n = get_string(f, string_buf, sizeof string_buf, &ec);
148        if (n < 0 || ec == '\n')
149            break;
150
151        m->fstype = strdup(string_buf);
152        if (!m->fstype)
153            break;
154
155        n = get_string(f, string_buf, sizeof string_buf, &ec);
156        if (n < 0 || ec == '\n')
157            break;
158
159        m->devpath = strdup(string_buf);
160        if (!m->devpath)
161            break;
162
163        n = get_string(f, string_buf, sizeof string_buf, &ec);
164        if (n < 0)
165            break;
166
167        m->mountopt = strdup(string_buf);
168        if (!m->mountopt)
169            break;
170
171        /* Skip any previously unknown fields */
172        while (ec != '\n' && ec != EOF)
173            ec = getc(f);
174
175        *tail = m;
176        tail = &m->next;
177    }
178quit:
179    fclose(f);
180    free_mountinfo(m);
181
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) {
186                m->parent = mm;
187                if (!strcmp(m->path, mm->path))
188                    mm->hidden = 1; /* Hidden under another mount */
189                break;
190            }
191        }
192    }
193}
194
195const struct mountinfo *find_mount(const char *path, char **subpath)
196{
197    static int done_init;
198    char *real_path;
199    const struct mountinfo *m, *best;
200    struct stat st;
201    int len, matchlen;
202
203    if (!done_init) {
204        parse_mountinfo();
205        done_init = 1;
206    }
207
208    if (stat(path, &st))
209        return NULL;
210
211    real_path = realpath(path, NULL);
212    if (!real_path)
213        return NULL;
214
215    /*
216     * Tricky business: we need the longest matching subpath
217     * which isn't a parent of the same subpath.
218     */
219    len = strlen(real_path);
220    matchlen = 0;
221    best = NULL;
222    for (m = head; m; m = m->next) {
223        if (m->hidden)
224            continue;           /* Hidden underneath another mount */
225
226        if (m->pathlen > len)
227            continue;           /* Cannot possibly match */
228
229        if (m->pathlen < matchlen)
230            continue;           /* No point in testing this one */
231
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;
236            best = m;
237        }
238    }
239
240    if (best && subpath) {
241        if (real_path[best->pathlen] == '\0')
242            *subpath = strdup("/");
243        else
244            *subpath = strdup(real_path + best->pathlen);
245    }
246
247    return best;
248}
249
250#ifdef TEST
251
252int main(int argc, char *argv[])
253{
254    int i;
255    const struct mountinfo *m;
256    char *subpath;
257
258    parse_mountinfo();
259
260    for (i = 1; i < argc; i++) {
261        m = find_mount(argv[i], &subpath);
262        if (!m) {
263            printf("%s: %s\n", argv[i], strerror(errno));
264            continue;
265        }
266
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));
271        free(subpath);
272    }
273
274    return 0;
275}
276
277#endif
Note: See TracBrowser for help on using the repository browser.