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