2 * collectd - src/utils_mount.c
3 * Copyright (C) 2005 Niki W. Waibel
5 * This program is free software; you can redistribute it and/
6 * or modify it under the terms of the GNU General Public Li-
7 * cence as published by the Free Software Foundation; either
8 * version 2 of the Licence, or any later version.
10 * This program is distributed in the hope that it will be use-
11 * ful, but WITHOUT ANY WARRANTY; without even the implied war-
12 * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public Licence for more details.
15 * You should have received a copy of the GNU General Public
16 * Licence along with this program; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
21 * Niki W. Waibel <niki.waibel@gmx.net>
29 #define xfs_mem_dqinfo fs_quota_stat
30 #define Q_XFS_GETQSTAT Q_XGETQSTAT
31 #define XFS_SUPER_MAGIC_STR "XFSB"
32 #define XFS_SUPER_MAGIC2_STR "BSFX"
34 #include "utils_debug.h"
35 #include "utils_mount.h"
39 /* *** *** *** local functions *** *** *** */
43 /* stolen from quota-3.13 (quota-tools) */
45 #define PROC_PARTITIONS "/proc/partitions"
46 #define DEVLABELDIR "/dev"
50 #define AUTOFS_DIR_MAX 64 /* Maximum number of autofs directories */
52 static struct uuidCache_s {
53 struct uuidCache_s *next;
59 #define EXT2_SUPER_MAGIC 0xEF53
60 struct ext2_super_block {
61 unsigned char s_dummy1[56];
62 unsigned char s_magic[2];
63 unsigned char s_dummy2[46];
64 unsigned char s_uuid[16];
65 char s_volume_name[16];
67 #define ext2magic(s) ((unsigned int)s.s_magic[0] \
68 + (((unsigned int)s.s_magic[1]) << 8))
71 struct xfs_super_block {
72 unsigned char s_magic[4];
73 unsigned char s_dummy[28];
74 unsigned char s_uuid[16];
75 unsigned char s_dummy2[60];
78 #endif /* HAVE_XFS_XQM_H */
80 #define REISER_SUPER_MAGIC "ReIsEr2Fs"
81 struct reiserfs_super_block {
82 unsigned char s_dummy1[52];
83 unsigned char s_magic[10];
84 unsigned char s_dummy2[22];
85 unsigned char s_uuid[16];
86 char s_volume_name[16];
89 /* for now, only ext2 and xfs are supported */
91 get_label_uuid(const char *device, char **label, char *uuid)
93 /* start with ext2 and xfs tests, taken from mount_guess_fstype */
94 /* should merge these later */
97 struct ext2_super_block e2sb;
99 struct xfs_super_block xfsb;
101 struct reiserfs_super_block reisersb;
103 fd = open(device, O_RDONLY);
108 if(lseek(fd, 1024, SEEK_SET) == 1024
109 && read(fd, (char *)&e2sb, sizeof(e2sb)) == sizeof(e2sb)
110 && ext2magic(e2sb) == EXT2_SUPER_MAGIC) {
111 memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid));
112 namesize = sizeof(e2sb.s_volume_name);
113 *label = smalloc(namesize + 1);
114 sstrncpy(*label, e2sb.s_volume_name, namesize);
117 } else if(lseek(fd, 0, SEEK_SET) == 0
118 && read(fd, (char *)&xfsb, sizeof(xfsb)) == sizeof(xfsb)
119 && (strncmp((char *)&xfsb.s_magic, XFS_SUPER_MAGIC_STR, 4) == 0 ||
120 strncmp((char *)&xfsb.s_magic, XFS_SUPER_MAGIC2_STR, 4) == 0)) {
121 memcpy(uuid, xfsb.s_uuid, sizeof(xfsb.s_uuid));
122 namesize = sizeof(xfsb.s_fsname);
123 *label = smalloc(namesize + 1);
124 sstrncpy(*label, xfsb.s_fsname, namesize);
126 #endif /* HAVE_XFS_XQM_H */
127 } else if(lseek(fd, 65536, SEEK_SET) == 65536
128 && read(fd, (char *)&reisersb, sizeof(reisersb)) == sizeof(reisersb)
129 && !strncmp((char *)&reisersb.s_magic, REISER_SUPER_MAGIC, 9)) {
130 memcpy(uuid, reisersb.s_uuid, sizeof(reisersb.s_uuid));
131 namesize = sizeof(reisersb.s_volume_name);
132 *label = smalloc(namesize + 1);
133 sstrncpy(*label, reisersb.s_volume_name, namesize);
141 uuidcache_addentry(char *device, char *label, char *uuid)
143 struct uuidCache_s *last;
146 last = uuidCache = smalloc(sizeof(*uuidCache));
148 for(last = uuidCache; last->next; last = last->next);
149 last->next = smalloc(sizeof(*uuidCache));
153 last->device = device;
155 memcpy(last->uuid, uuid, sizeof(last->uuid));
164 static char ptname[100];
166 char uuid[16], *label = NULL;
175 procpt = fopen(PROC_PARTITIONS, "r");
180 for(firstPass = 1; firstPass >= 0; firstPass--) {
181 fseek(procpt, 0, SEEK_SET);
182 while(fgets(line, sizeof(line), procpt)) {
183 if(sscanf(line, " %d %d %d %[^\n ]",
184 &ma, &mi, &sz, ptname) != 4)
189 /* skip extended partitions (heuristic: size 1) */
194 /* look only at md devices on first pass */
195 handleOnFirst = !strncmp(ptname, "md", 2);
196 if(firstPass != handleOnFirst) {
200 /* skip entire disk (minor 0, 64, ... on ide;
202 /* heuristic: partition name ends in a digit */
204 for(s = ptname; *s; s++);
206 if(isdigit((int)s[-1])) {
208 * Note: this is a heuristic only - there is no reason
209 * why these devices should live in /dev.
210 * Perhaps this directory should be specifiable by option.
211 * One might for example have /devlabel with links to /dev
212 * for the devices that may be accessed in this way.
213 * (This is useful, if the cdrom on /dev/hdc must not
216 snprintf(device, sizeof(device), "%s/%s",
217 DEVLABELDIR, ptname);
218 if(!get_label_uuid(device, &label, uuid)) {
219 uuidcache_addentry(sstrdup(device),
231 if(isdigit((int)c)) {
233 } else if(islower((int)c)) {
234 return (c - 'a' + 10);
236 return (c - 'A' + 10);
241 get_spec_by_x(int n, const char *t)
243 struct uuidCache_s *uc;
251 if(!memcmp(t, uc->uuid, sizeof(uc->uuid))) {
252 return sstrdup(uc->device);
256 if(!strcmp(t, uc->label)) {
257 return sstrdup(uc->device);
267 get_spec_by_uuid(const char *s)
273 || s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-') {
277 for(i=0; i<16; i++) {
281 if(!isxdigit((int)s[0]) || !isxdigit((int)s[1])) {
284 uuid[i] = ((fromhex(s[0]) << 4) | fromhex(s[1]));
287 return get_spec_by_x(UUID, uuid);
290 DBG("Found an invalid UUID: %s", s);
295 get_spec_by_volume_label(const char *s)
297 return get_spec_by_x(VOL, s);
301 get_device_name(const char *item)
305 if(!strncmp(item, "UUID=", 5)) {
306 DBG("TODO: check UUID= code!");
307 rc = get_spec_by_uuid(item + 5);
308 } else if(!strncmp(item, "LABEL=", 6)) {
309 DBG("TODO: check LABEL= code!");
310 rc = get_spec_by_volume_label(item + 6);
315 DBG("Error checking device name: %s", item);
322 cu_mount_listmntent(struct tabmntent *mntlist, cu_mount_t **list)
327 for(p = mntlist; p; p = p->next) {
329 *list = smalloc(sizeof(cu_mount_t));
330 list->device = strdup(mnt->mnt_fsname);
331 list->name = strdup(mnt->mnt_dir);
332 list->type = strdup(mnt->mnt_type);
336 freemntlist(mntlist);
338 #endif /* HAVE_LISTMNTENT */
344 cu_mount_getvfsmnt(FILE *mntf, cu_mount_t **list)
346 DBG("TODO: getvfsmnt");
349 #endif /* HAVE_GETVFSENT */
352 cu_mount_checkmountopt(char *line, char *keyword, int full)
355 int l = strlen(keyword);
358 if(line == NULL || keyword == NULL) {
365 line2 = sstrdup(line);
375 p2 = strchr(line, ',');
377 if(strncmp(line2+(p1-line)+1, keyword, l+full) == 0) {
383 p2 = strchr(p1+1, ',');
389 } /* char *cu_mount_checkmountopt(char *line, char *keyword, int full) */
392 cu_mount_getmountopt(char *line, char *keyword)
396 r = cu_mount_checkmountopt(line, keyword, 0);
399 r += strlen(keyword);
411 m = (char *)smalloc(p-r+1);
412 sstrncpy(m, r, p-r+1);
417 } /* char *cu_mount_getmountopt(char *line, char *keyword) */
421 cu_mount_getmntent(FILE *mntf, cu_mount_t **list)
423 cu_mount_t *last = *list;
427 while((mnt = getmntent(mntf)) != NULL) {
428 #endif /* HAVE_GETMNTENT1 */
429 char *loop = NULL, *device = NULL;
432 DBG("------------------ BEGIN");
433 DBG("mnt->mnt_fsname %s", mnt->mnt_fsname);
434 DBG("mnt->mnt_dir %s", mnt->mnt_dir);
435 DBG("mnt->mnt_type %s", mnt->mnt_type);
436 DBG("mnt->mnt_opts %s", mnt->mnt_opts);
437 DBG("mnt->mnt_freq %d", mnt->mnt_freq);
438 DBG("mnt->mnt_passno %d", mnt->mnt_passno);
441 loop = cu_mount_getmountopt(mnt->mnt_opts, "loop=");
442 if(loop == NULL) { /* no loop= mount */
443 device = get_device_name(mnt->mnt_fsname);
445 DBG("can't get devicename for fs (%s) %s (%s)"
446 ": ignored", mnt->mnt_type,
447 mnt->mnt_dir, mnt->mnt_fsname);
455 DBG("device %s", device);
456 DBG("------------------ END");
459 *list = (cu_mount_t *)smalloc(sizeof(cu_mount_t));
462 last->next = (cu_mount_t *)smalloc(sizeof(cu_mount_t));
465 last->dir = sstrdup(mnt->mnt_dir);
466 last->spec_device = sstrdup(mnt->mnt_fsname);
467 last->device = device;
468 last->type = sstrdup(mnt->mnt_type);
469 last->options = sstrdup(mnt->mnt_opts);
471 } /* while((mnt = getmntent(mntf)) != NULL) */
474 } /* static cu_mount_t *cu_mount_getmntent(FILE *mntf, cu_mount_t **list) */
475 #endif /* HAVE_GETMNTENT */
480 cu_mount_getlist(cu_mount_t **list)
482 cu_mount_t *last = NULL;
484 /* yes, i know that the indentation is wrong.
485 but show me a better way to do this... */
486 /* see lib/mountlist.c of coreutils for all
488 #if HAVE_GETMNTENT && defined(_PATH_MOUNTED)
491 if((mntf = setmntent(_PATH_MOUNTED, "r")) == NULL) {
492 DBG("opening %s failed: %s", _PATH_MOUNTED, strerror(errno));
494 #if HAVE_GETMNTENT && defined(MNT_MNTTAB)
497 if((mntf = setmntent(MNT_MNTTAB, "r")) == NULL) {
498 DBG("opening %s failed: %s", MNT_MNTTAB, strerror(errno));
500 #if HAVE_GETMNTENT && defined(MNTTABNAME)
503 if((mntf = setmntent(MNTTABNAME, "r")) == NULL) {
504 DBG("opening %s failed: %s", MNTTABNAME, strerror(errno));
506 #if HAVE_GETMNTENT && defined(_PATH_MNTTAB)
509 if((mntf = setmntent(_PATH_MNTTAB, "r")) == NULL) {
510 DBG("opening %s failed: %s", _PATH_MNTTAB, strerror(errno));
512 #if HAVE_GETVFSENT && defined(VFSTAB)
515 if((mntf = fopen(VFSTAB, "r")) == NULL) {
516 DBG("opening %s failed: %s", VFSTAB, strerror(errno));
520 struct tabmntent *mntlist;
522 if(listmntent(&mntlist, KMTAB, NULL, NULL) < 0) {
523 DBG("calling listmntent() failed: %s", strerror(errno));
526 DBG("failed get local mountpoints");
530 } else { last = cu_mount_listmntent(mntlist, list); }
531 freemntlist(mntlist);
534 #if HAVE_GETVFSENT && defined(VFSTAB)
535 } else { last = cu_mount_getvfsmnt(mntf, list); }
539 #if HAVE_GETMNTENT && defined(_PATH_MNTTAB)
540 } else { last = cu_mount_getmntent(mntf, list); }
541 (void)endmntent(mntf);
544 #if HAVE_GETMNTENT && defined(MNTTABNAME)
545 } else { last = cu_mount_getmntent(mntf, list); }
546 (void)endmntent(mntf);
549 #if HAVE_GETMNTENT && defined(MNT_MNTTAB)
550 } else { last = cu_mount_getmntent(mntf, list); }
551 (void)endmntent(mntf);
554 #if HAVE_GETMNTENT && defined(_PATH_MOUNTED)
555 } else { last = cu_mount_getmntent(mntf, list); }
556 (void)endmntent(mntf);
560 } /* cu_mount_t *cu_mount_getlist(cu_mount_t **list) */
563 cu_mount_freelist(cu_mount_t *list)
565 cu_mount_t *l = list, *p = NULL;
568 while(l->next != NULL) {
576 sfree(l->spec_device);
587 } /* while(l != NULL) */
588 } /* void cu_mount_freelist(cu_mount_t *list) */
591 cu_mount_type(const char *type)
593 if(strcmp(type, "ext3") == 0) return CUMT_EXT3;
594 if(strcmp(type, "ext2") == 0) return CUMT_EXT2;
595 if(strcmp(type, "ufs") == 0) return CUMT_UFS;
596 if(strcmp(type, "vxfs") == 0) return CUMT_VXFS;
597 if(strcmp(type, "zfs") == 0) return CUMT_ZFS;
599 } /* int cu_mount_type(const char *type) */