]> arthur.barton.de Git - netdata.git/blob - src/proc_self_mountinfo.c
Merge pull request #775 from ktsaou/health
[netdata.git] / src / proc_self_mountinfo.c
1 #include "common.h"
2
3 // find the mount info with the given major:minor
4 // in the supplied linked list of mountinfo structures
5 struct mountinfo *mountinfo_find(struct mountinfo *root, unsigned long major, unsigned long minor) {
6     struct mountinfo *mi;
7
8     for(mi = root; mi ; mi = mi->next)
9         if(mi->major == major && mi->minor == minor)
10             return mi;
11
12     return NULL;
13 }
14
15 // find the mount info with the given filesystem and mount_source
16 // in the supplied linked list of mountinfo structures
17 struct mountinfo *mountinfo_find_by_filesystem_mount_source(struct mountinfo *root, const char *filesystem, const char *mount_source) {
18     struct mountinfo *mi;
19     uint32_t filesystem_hash = simple_hash(filesystem), mount_source_hash = simple_hash(mount_source);
20
21     for(mi = root; mi ; mi = mi->next)
22         if(mi->filesystem
23                 && mi->mount_source
24                 && mi->filesystem_hash == filesystem_hash
25                 && mi->mount_source_hash == mount_source_hash
26                 && !strcmp(mi->filesystem, filesystem)
27                 && !strcmp(mi->mount_source, mount_source))
28             return mi;
29
30     return NULL;
31 }
32
33 struct mountinfo *mountinfo_find_by_filesystem_super_option(struct mountinfo *root, const char *filesystem, const char *super_options) {
34     struct mountinfo *mi;
35     uint32_t filesystem_hash = simple_hash(filesystem);
36
37     size_t solen = strlen(super_options);
38
39     for(mi = root; mi ; mi = mi->next)
40         if(mi->filesystem
41                 && mi->super_options
42                 && mi->filesystem_hash == filesystem_hash
43                 && !strcmp(mi->filesystem, filesystem)) {
44
45             // super_options is a comma separated list
46             char *s = mi->super_options, *e;
47             while(*s) {
48                 e = s + 1;
49                 while(*e && *e != ',') e++;
50
51                 size_t len = e - s;
52                 if(len == solen && !strncmp(s, super_options, len))
53                     return mi;
54
55                 if(*e == ',') s = ++e;
56                 else s = e;
57             }
58         }
59
60     return NULL;
61 }
62
63
64 // free a linked list of mountinfo structures
65 void mountinfo_free(struct mountinfo *mi) {
66     if(unlikely(!mi))
67         return;
68
69     if(likely(mi->next))
70         mountinfo_free(mi->next);
71
72     freez(mi->root);
73     freez(mi->mount_point);
74     freez(mi->mount_options);
75
76 /*
77     if(mi->optional_fields_count) {
78         int i;
79         for(i = 0; i < mi->optional_fields_count ; i++)
80             free(*mi->optional_fields[i]);
81     }
82     free(mi->optional_fields);
83 */
84     freez(mi->filesystem);
85     freez(mi->mount_source);
86     freez(mi->super_options);
87     freez(mi);
88 }
89
90 static char *strdupz_decoding_octal(const char *string) {
91     char *buffer = strdupz(string);
92
93     char *d = buffer;
94     const char *s = string;
95
96     while(*s) {
97         if(unlikely(*s == '\\')) {
98             s++;
99             if(likely(isdigit(*s) && isdigit(s[1]) && isdigit(s[2]))) {
100                 char c = *s++ - '0';
101                 c <<= 3;
102                 c |= *s++ - '0';
103                 c <<= 3;
104                 c |= *s++ - '0';
105                 *d++ = c;
106             }
107             else *d++ = '_';
108         }
109         else *d++ = *s++;
110     }
111     *d = '\0';
112
113     return buffer;
114 }
115
116 // read the whole mountinfo into a linked list
117 struct mountinfo *mountinfo_read() {
118     procfile *ff = NULL;
119
120     char filename[FILENAME_MAX + 1];
121     snprintfz(filename, FILENAME_MAX, "%s/proc/self/mountinfo", global_host_prefix);
122     ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
123     if(!ff) {
124         snprintfz(filename, FILENAME_MAX, "%s/proc/1/mountinfo", global_host_prefix);
125         ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
126         if(!ff) return NULL;
127     }
128
129     ff = procfile_readall(ff);
130     if(!ff) return NULL;
131
132     struct mountinfo *root = NULL, *last = NULL, *mi = NULL;
133
134     unsigned long l, lines = procfile_lines(ff);
135     for(l = 0; l < lines ;l++) {
136         if(procfile_linewords(ff, l) < 5)
137             continue;
138
139         mi = mallocz(sizeof(struct mountinfo));
140
141         if(unlikely(!root))
142             root = last = mi;
143         else
144             last->next = mi;
145
146         last = mi;
147         mi->next = NULL;
148
149         unsigned long w = 0;
150         mi->id = strtoul(procfile_lineword(ff, l, w), NULL, 10); w++;
151         mi->parentid = strtoul(procfile_lineword(ff, l, w), NULL, 10); w++;
152
153         char *major = procfile_lineword(ff, l, w), *minor; w++;
154         for(minor = major; *minor && *minor != ':' ;minor++) ;
155         *minor = '\0';
156         minor++;
157
158         mi->major = strtoul(major, NULL, 10);
159         mi->minor = strtoul(minor, NULL, 10);
160
161         mi->root = strdupz(procfile_lineword(ff, l, w)); w++;
162         mi->root_hash = simple_hash(mi->root);
163
164         mi->mount_point = strdupz_decoding_octal(procfile_lineword(ff, l, w)); w++;
165         mi->mount_point_hash = simple_hash(mi->mount_point);
166
167         mi->mount_options = strdupz(procfile_lineword(ff, l, w)); w++;
168
169         // count the optional fields
170 /*
171         unsigned long wo = w;
172 */
173         mi->optional_fields_count = 0;
174         char *s = procfile_lineword(ff, l, w);
175         while(*s && *s != '-') {
176             w++;
177             s = procfile_lineword(ff, l, w);
178             mi->optional_fields_count++;
179         }
180
181 /*
182         if(unlikely(mi->optional_fields_count)) {
183             // we have some optional fields
184             // read them into a new array of pointers;
185
186             mi->optional_fields = malloc(mi->optional_fields_count * sizeof(char *));
187             if(unlikely(!mi->optional_fields))
188                 fatal("Cannot allocate memory for %d mountinfo optional fields", mi->optional_fields_count);
189
190             int i;
191             for(i = 0; i < mi->optional_fields_count ; i++) {
192                 *mi->optional_fields[wo] = strdup(procfile_lineword(ff, l, w));
193                 if(!mi->optional_fields[wo]) fatal("Cannot allocate memory");
194                 wo++;
195             }
196         }
197         else
198             mi->optional_fields = NULL;
199 */
200
201         if(likely(*s == '-')) {
202             w++;
203
204             mi->filesystem = strdupz(procfile_lineword(ff, l, w)); w++;
205             mi->filesystem_hash = simple_hash(mi->filesystem);
206
207             mi->mount_source = strdupz(procfile_lineword(ff, l, w)); w++;
208             mi->mount_source_hash = simple_hash(mi->mount_source);
209
210             mi->super_options = strdupz(procfile_lineword(ff, l, w)); w++;
211         }
212         else {
213             mi->filesystem = NULL;
214             mi->mount_source = NULL;
215             mi->super_options = NULL;
216         }
217
218 /*
219         info("MOUNTINFO: %u %u %u:%u root '%s', mount point '%s', mount options '%s', filesystem '%s', mount source '%s', super options '%s'",
220              mi->id,
221              mi->parentid,
222              mi->major,
223              mi->minor,
224              mi->root,
225              mi->mount_point,
226              mi->mount_options,
227              mi->filesystem,
228              mi->mount_source,
229              mi->super_options
230         );
231 */
232     }
233
234     procfile_close(ff);
235     return root;
236 }