From 82f5d974814caecbfcf9501723baf739b7b1da97 Mon Sep 17 00:00:00 2001 From: niki Date: Fri, 2 Dec 2005 12:47:23 +0000 Subject: [PATCH] Many changes. Got rid of hasmntopt (own version is in place now), detect loop= and --bind mounts, added sfree (not sure if really necessary), added usrjquota/grpjquota infrastructure. --- configure.in | 1 + src/config.h.in | 6 ++ src/quota_fs.c | 121 ++++++++++++++++++++++----------- src/quota_fs.h | 9 ++- src/quota_mnt.c | 163 +++++++++++++++++++++++++++++++++++++-------- src/quota_mnt.h | 2 + src/quota_plugin.c | 21 +++--- 7 files changed, 245 insertions(+), 78 deletions(-) diff --git a/configure.in b/configure.in index ad4e77ea..5d6bd7d8 100644 --- a/configure.in +++ b/configure.in @@ -66,6 +66,7 @@ AC_CHECK_FUNCS(strncasecmp strcasecmp strncmp) AC_CHECK_FUNCS(getfsent getvfsent listmntent) AC_FUNC_GETMNTENT AC_CHECK_FUNCS(quotactl) +AC_CHECK_FUNCS(getgrgid getpwuid) AC_MSG_CHECKING([for kernel type ($host_os)]) case $host_os in diff --git a/src/config.h.in b/src/config.h.in index 5ec5c6fd..afb9fa00 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -60,12 +60,18 @@ /* Define to 1 if you have the `getfsent' function. */ #undef HAVE_GETFSENT +/* Define to 1 if you have the `getgrgid' function. */ +#undef HAVE_GETGRGID + /* Define to 1 if you have the `gethostbyname' function. */ #undef HAVE_GETHOSTBYNAME /* Define to 1 if you have the `getmntent' function. */ #undef HAVE_GETMNTENT +/* Define to 1 if you have the `getpwuid' function. */ +#undef HAVE_GETPWUID + /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY diff --git a/src/quota_fs.c b/src/quota_fs.c index d8ab22d4..e151c393 100644 --- a/src/quota_fs.c +++ b/src/quota_fs.c @@ -31,19 +31,26 @@ # include #endif + + /* *** *** *** prototypes of local functions *** *** *** */ + + static int qft(const char *type); static quota_t *getquota_ext3(quota_t **quota, quota_mnt_t *m); static quota_t *getquota_ext3_v1(quota_t **quota, quota_mnt_t *m); static quota_t *getquota_ext3_v2(quota_t **quota, quota_mnt_t *m); -static quota_t *getquota_ext2(quota_t **quota, quota_mnt_t *m); static quota_t *getquota_ufs(quota_t **quota, quota_mnt_t *m); static quota_t *getquota_vxfs(quota_t **quota, quota_mnt_t *m); static quota_t *getquota_zfs(quota_t **quota, quota_mnt_t *m); + + /* *** *** *** local functions *** *** *** */ + + static int qft(const char *type) { @@ -55,6 +62,8 @@ qft(const char *type) return QFT_NONE; } /* static int qft(const char *type) */ + + static quota_t * getquota_ext3(quota_t **quota, quota_mnt_t *m) { @@ -81,6 +90,8 @@ getquota_ext3(quota_t **quota, quota_mnt_t *m) return NULL; } /* static quota_t *getquota_ext3(quota_t **quota, quota_mnt_t *m) */ + + static quota_t * getquota_ext3_v1(quota_t **quota, quota_mnt_t *m) { @@ -94,16 +105,30 @@ getquota_ext3_v1(quota_t **quota, quota_mnt_t *m) if(quotactl(QCMD(Q_GETINFO, USRQUOTA), m->device, 0, (void *)&dqi_usr) == -1) { - DBG("quotactl (Q_GETINFO, USRQUOTA) returned -1: %s", - strerror(errno)); + DBG("quotactl (Q_GETINFO, USRQUOTA) returned -1 on" + " %s: %s", m->device, strerror(errno)); + *quota = NULL; + return NULL; + } + if(quotactl(QCMD(Q_SYNC, USRQUOTA), m->device, 0, NULL) == -1) + { + DBG("quotactl (Q_SYNC, USRQUOTA) returned -1 on" + " %s: %s", m->device, strerror(errno)); *quota = NULL; return NULL; } if(quotactl(QCMD(Q_GETINFO, GRPQUOTA), m->device, 0, (void *)&dqi_grp) == -1) { - DBG("quotactl (Q_GETINFO, GRPQUOTA) returned -1: %s", - strerror(errno)); + DBG("quotactl (Q_GETINFO, GRPQUOTA) returned -1 on" + " %s: %s", m->device, strerror(errno)); + *quota = NULL; + return NULL; + } + if(quotactl(QCMD(Q_SYNC, GRPQUOTA), m->device, 0, NULL) == -1) + { + DBG("quotactl (Q_SYNC, GRPQUOTA) returned -1 on" + " %s: %s", m->device, strerror(errno)); *quota = NULL; return NULL; } @@ -112,11 +137,11 @@ getquota_ext3_v1(quota_t **quota, quota_mnt_t *m) q = *quota = (quota_t *)smalloc(sizeof(quota_t)); q->type = (char *)sstrdup("usrquota"); -#if HAVE_GRP_H -/* struct group *getgrid((gid_t)500) */ +#if HAVE_GETPWUID +/* struct group *getpwuid((uid_t)500) */ q->name = (char *)sstrdup("niki"); #else - q->name = (char *)sstrdup(""); + q->name = (char *)sstrdup("500"); #endif q->id = (char *)sstrdup("500"); q->dir = (char *)sstrdup(m->dir); @@ -124,22 +149,22 @@ getquota_ext3_v1(quota_t **quota, quota_mnt_t *m) q->bquota = 100; q->blimit = 180; q->bgrace = dqi_usr.dqi_bgrace; - q->btimeleft = 0; + q->btimeleft = -1; q->inodes = 5; q->iquota = 100; q->ilimit = 180; q->igrace = dqi_usr.dqi_igrace; - q->itimeleft = 0; + q->itimeleft = -1; q->next = NULL; q->next = (quota_t *)smalloc(sizeof(quota_t)); q = q->next; q->type = (char *)sstrdup("grpquota"); -#if HAVE_GRP_H -/* struct group *getgrid((gid_t)500) */ +#if HAVE_GETGRGID +/* struct group *getgrgid((gid_t)100) */ q->name = (char *)sstrdup("users"); #else - q->name = (char *)sstrdup(""); + q->name = (char *)sstrdup("100"); #endif q->id = (char *)sstrdup("100"); q->dir = (char *)sstrdup(m->dir); @@ -147,17 +172,19 @@ getquota_ext3_v1(quota_t **quota, quota_mnt_t *m) q->bquota = 100; q->blimit = 180; q->bgrace = dqi_grp.dqi_bgrace; - q->btimeleft = 0; + q->btimeleft = -1; q->inodes = 5; q->iquota = 100; q->ilimit = 180; q->igrace = dqi_grp.dqi_igrace; - q->itimeleft = 0; + q->itimeleft = -1; q->next = NULL; return *quota; } + + static quota_t * getquota_ext3_v2(quota_t **quota, quota_mnt_t *m) { @@ -165,11 +192,7 @@ getquota_ext3_v2(quota_t **quota, quota_mnt_t *m) return getquota_ext3_v1(quota, m); } -static quota_t * -getquota_ext2(quota_t **quota, quota_mnt_t *m) -{ - return NULL; -} + static quota_t * getquota_ufs(quota_t **quota, quota_mnt_t *m) @@ -177,20 +200,50 @@ getquota_ufs(quota_t **quota, quota_mnt_t *m) return NULL; } + + static quota_t * getquota_vxfs(quota_t **quota, quota_mnt_t *m) { return NULL; } + + static quota_t * getquota_zfs(quota_t **quota, quota_mnt_t *m) { return NULL; } + + /* *** *** *** global functions *** *** *** */ + + +#if QUOTA_PLUGIN_DEBUG +void +quota_fs_printquota_dbg(quota_t *q) +{ + while(q != NULL) { + DBG("\ttype: %s", q->type); + DBG("\tname: %s", q->name); + DBG("\tid: %s", q->id); + DBG("\tdir: %s", q->dir); + DBG("\tblocks: %llu (%lld/%lld) %lld %lld", + q->blocks, q->bquota, q->blimit, + q->bgrace, q->btimeleft); + DBG("\tinodes: %llu (%lld/%lld) %lld %lld", + q->inodes, q->iquota, q->ilimit, + q->igrace, q->itimeleft); + q = q->next; + } /* while(q != NULL) */ +} /* void quota_fs_printquota_dbg(quota_t *quota) */ +#endif /* QUOTA_PLUGIN_DEBUG */ + + + int quota_fs_issupported(const char *fsname) { @@ -209,6 +262,8 @@ quota_fs_issupported(const char *fsname) } } /* int quota_fs_issupported(const char *fsname) */ + + int quota_fs_isnfs(const char *fsname) { @@ -219,12 +274,13 @@ quota_fs_isnfs(const char *fsname) } } /* int quota_fs_isnfs(const char *fsname) */ + + void quota_fs_freequota(quota_t *quota) { quota_t *q = quota, *prev = NULL; -DBG("x"); while(q != NULL) { while(q->next != NULL) { prev = q; @@ -247,6 +303,8 @@ DBG("x"); } /* while(q != NULL) */ } /* void quota_fs_freequota(quota_t *quota) */ + + quota_t * quota_fs_getquota(quota_t **quota, quota_mnt_t *mnt) { @@ -256,12 +314,10 @@ quota_fs_getquota(quota_t **quota, quota_mnt_t *mnt) *quota = NULL; while(m != NULL) { switch(qft(m->type)) { + case QFT_EXT2: case QFT_EXT3: q = getquota_ext3(&q, m); break; - case QFT_EXT2: - q = getquota_ext2(&q, m); - break; case QFT_UFS: q = getquota_ufs(&q, m); break; @@ -273,32 +329,17 @@ quota_fs_getquota(quota_t **quota, quota_mnt_t *mnt) break; } if(q != NULL) { /* found some quotas */ - DBG("\ttype: %s", (*quota)->type); - DBG("\tname: %s", (*quota)->name); - DBG("\tid: %s", (*quota)->id); - DBG("\tdir: %s", (*quota)->dir); - DBG("\tblocks: %llu (%lld/%lld) %llu %llu", - (*quota)->blocks, (*quota)->bquota, (*quota)->blimit, - (*quota)->bgrace, (*quota)->btimeleft); - DBG("\tinodes: %llu (%lld/%lld) %llu %llu", - (*quota)->inodes, (*quota)->iquota, (*quota)->ilimit, - (*quota)->igrace, (*quota)->itimeleft); - if(*quota == NULL) { /* not init yet */ -DBG("a"); *quota = q; /* init */ } else { /* we have some quotas already */ -DBG("b"); quota_t *t = *quota; /* goto last entry */ while(t->next != NULL) { t = t->next; -DBG("c"); } t->next = q; /* set next pointer */ } - } -DBG("z"); + } /* if(q != NULL) */ m = m->next; } /* while(m != NULL) */ diff --git a/src/quota_fs.h b/src/quota_fs.h index 9a8f9369..5d3eb803 100644 --- a/src/quota_fs.h +++ b/src/quota_fs.h @@ -25,6 +25,7 @@ #define COLLECTD_QUOTA_FS_H 1 #include "common.h" +#include "quota_debug.h" #include "quota_mnt.h" /* Quota Filesystem Type */ @@ -44,16 +45,20 @@ struct _quota_t { char *dir; unsigned long long blocks; long long bquota, blimit; - unsigned long long bgrace, btimeleft; + long long bgrace, btimeleft; unsigned long long inodes; long long iquota, ilimit; - unsigned long long igrace, itimeleft; + long long igrace, itimeleft; quota_t *next; }; int quota_fs_issupported(const char *fsname); int quota_fs_isnfs(const char *fsname); +#if QUOTA_PLUGIN_DEBUG +void quota_fs_printquota_dbg(quota_t *quota); +#endif + quota_t *quota_fs_getquota(quota_t **quota, quota_mnt_t *m); void quota_fs_freequota(quota_t *quota); diff --git a/src/quota_mnt.c b/src/quota_mnt.c index 435a69af..cfb071ff 100644 --- a/src/quota_mnt.c +++ b/src/quota_mnt.c @@ -73,8 +73,19 @@ #include "quota_mntopt.h" + + +/* *** *** *** prototypes *** *** *** */ + +static char *getmountopt(char *line, char *keyword); +static char *checkmountopt(char *line, char *keyword, int full); + + + /* *** *** *** local functions *** *** *** */ + + /* stolen from quota-3.13 (quota-tools) */ #define PROC_PARTITIONS "/proc/partitions" @@ -332,10 +343,10 @@ get_spec_by_volume_label(const char *s) return get_spec_by_x(VOL, s); } -const char * +static char * get_device_name(const char *item) { - const char *rc; + char *rc; if(!strncmp(item, "UUID=", 5)) { DBG("TODO: check UUID= code!"); @@ -399,7 +410,7 @@ hasxfsquota(struct mntent *mnt, int type) ret = 1; #endif /* XFS_ROOTHACK */ } - free((char *)dev); + sfree((char *)dev); return ret; } #endif /* HAVE_XFS_XQM_H */ @@ -436,7 +447,73 @@ quota_mnt_getvfsmnt(FILE *mntf, quota_mnt_t **list) } #endif /* HAVE_GETVFSENT */ +static char * +checkmountopt(char *line, char *keyword, int full) +{ + char *line2, *l2; + int l = strlen(keyword); + char *p1, *p2; + + if(line == NULL || keyword == NULL) { + return NULL; + } + if(full != 0) { + full = 1; + } + + line2 = sstrdup(line); + l2 = line2; + while(*l2 != '\0') { + if(*l2 == ',') { + *l2 = '\0'; + } + l2++; + } + p1 = line - 1; + p2 = strchr(line, ','); + do { + if(strncmp(line2+(p1-line)+1, keyword, l+full) == 0) { + free(line2); + return p1+1; + } + p1 = p2; + if(p1 != NULL) { + p2 = strchr(p1+1, ','); + } + } while(p1 != NULL); + + free(line2); + return NULL; +} /* static char *checkmountopt(char *line, char *keyword, int full) */ + +static char * +getmountopt(char *line, char *keyword) +{ + char *r; + + r = checkmountopt(line, keyword, 0); + if(r != NULL) { + char *p; + r += strlen(keyword); + p = strchr(r, ','); + if(p == NULL) { + if(strlen(r) == 0) { + return NULL; + } + return sstrdup(r); + } else { + char *m; + if((p-r) == 1) { + return NULL; + } + m = (char *)smalloc(p-r+1); + sstrncpy(m, r, p-r+1); + return m; + } + } + return r; +} /* static char *getmountopt(char *line, char *keyword) */ #if HAVE_GETMNTENT static void @@ -445,7 +522,9 @@ quota_mnt_getmntent(FILE *mntf, quota_mnt_t **list) struct mntent *mnt; while((mnt = getmntent(mntf)) != NULL) { - const char *devname; + char *loop = NULL, *device = NULL; + char *usrjquota = NULL; + char *grpjquota = NULL; #if 0 DBG("------------------"); @@ -456,17 +535,42 @@ quota_mnt_getmntent(FILE *mntf, quota_mnt_t **list) DBG("mnt->mnt_freq %d", mnt->mnt_freq); DBG("mnt->mnt_passno %d", mnt->mnt_passno); #endif - if(!(devname = get_device_name(mnt->mnt_fsname))) { - DBG("can't get devicename for fs (%s) %s (%s): ignored", + + if(quota_fs_issupported(mnt->mnt_type) == EXIT_FAILURE) + { + DBG("unsupportet fs (%s) %s (%s): ignored", mnt->mnt_type, mnt->mnt_dir, mnt->mnt_fsname); continue; } - if(hasmntopt(mnt, MNTOPT_NOQUOTA) != NULL) { + + if(checkmountopt(mnt->mnt_opts, MNTOPT_NOQUOTA, 1) != NULL) { DBG("noquota option on fs (%s) %s (%s): ignored", mnt->mnt_type, mnt->mnt_dir, mnt->mnt_fsname); - free((char *)devname); continue; } + + if(checkmountopt(mnt->mnt_opts, "bind", 1) != NULL) { + DBG("bind mount on fs (%s) %s (%s): ignored", + mnt->mnt_type, mnt->mnt_dir, mnt->mnt_fsname); + continue; + } + + loop = getmountopt(mnt->mnt_opts, "loop="); + if(loop == NULL) { /* no loop= mount */ + device = get_device_name(mnt->mnt_fsname); + if(device == NULL) { + DBG("can't get devicename for fs (%s) %s (%s)" + ": ignored", mnt->mnt_type, + mnt->mnt_dir, mnt->mnt_fsname); + continue; + } + } else { + device = loop; + } + + usrjquota = getmountopt(mnt->mnt_opts, "usrjquota="); + grpjquota = getmountopt(mnt->mnt_opts, "grpjquota="); + #if HAVE_XFS_XQM_H if(!strcmp(mnt->mnt_type, MNTTYPE_XFS)) { if(hasxfsquota(mnt, USRQUOTA) == 0 @@ -475,48 +579,50 @@ quota_mnt_getmntent(FILE *mntf, quota_mnt_t **list) DBG("no quota on fs (%s) %s (%s): ignored", mnt->mnt_type, mnt->mnt_dir, mnt->mnt_fsname); - free((char *)devname); + sfree(loop); + sfree(usrjquota); + sfree(grpjquota); continue; } } else { #endif /* HAVE_XFS_XQM_H */ - if(hasmntopt(mnt, MNTOPT_QUOTA) == NULL - && hasmntopt(mnt, MNTOPT_USRQUOTA) == NULL - && hasmntopt(mnt, MNTOPT_GRPQUOTA) == NULL + if(checkmountopt(mnt->mnt_opts, MNTOPT_QUOTA, 1) + == NULL + && checkmountopt(mnt->mnt_opts, MNTOPT_USRQUOTA, 1) + == NULL + && checkmountopt(mnt->mnt_opts, MNTOPT_GRPQUOTA, 1) + == NULL && quota_fs_isnfs(mnt->mnt_type) == EXIT_FAILURE) { DBG("neither quota/usrquota/grpquota option" " nor nfs fs (%s) %s (%s): ignored", mnt->mnt_type, mnt->mnt_dir, mnt->mnt_fsname); - free((char *)devname); + sfree(loop); + sfree(usrjquota); + sfree(grpjquota); continue; } #if HAVE_XFS_XQM_H } #endif /* HAVE_XFS_XQM_H */ - if(quota_fs_issupported(mnt->mnt_type) == EXIT_FAILURE) - { - DBG("unsupportet fs (%s) %s (%s): ignored", - mnt->mnt_type, mnt->mnt_dir, mnt->mnt_fsname); - free((char *)devname); - continue; - } #if 0 DBG("------------------ OK"); #endif *list = (quota_mnt_t *)smalloc(sizeof(quota_mnt_t)); (*list)->dir = sstrdup(mnt->mnt_dir); - (*list)->device = sstrdup(mnt->mnt_fsname); + (*list)->device = device; + (*list)->usrjquota = usrjquota; + (*list)->grpjquota = grpjquota; (*list)->type = sstrdup(mnt->mnt_type); (*list)->opts = QMO_NONE; /* TODO: this is not sufficient for XFS! */ /* TODO: maybe we should anyway NOT rely on the option in the mountfile... ... maybe the fs should be asked direktly all time! */ - if(hasmntopt(mnt, MNTOPT_QUOTA) != NULL - || hasmntopt(mnt, MNTOPT_USRQUOTA) != NULL) { + if(checkmountopt(mnt->mnt_opts, MNTOPT_QUOTA, 1) != NULL + || checkmountopt(mnt->mnt_opts, MNTOPT_USRQUOTA, 1) != NULL) { (*list)->opts |= QMO_USRQUOTA; } - if(hasmntopt(mnt, MNTOPT_GRPQUOTA) != NULL) { + if(checkmountopt(mnt->mnt_opts, MNTOPT_GRPQUOTA, 1) != NULL) { (*list)->opts |= QMO_GRPQUOTA; } (*list)->next = NULL; @@ -622,9 +728,12 @@ quota_mnt_freelist(quota_mnt_t *list) if(p != NULL) { p->next = NULL; } - free(l->dir); - free(l->device); - free(l); + sfree(l->dir); + sfree(l->device); + sfree(l->type); + sfree(l->usrjquota); + sfree(l->grpjquota); + sfree(l); p = NULL; if(l != list) { l = list; diff --git a/src/quota_mnt.h b/src/quota_mnt.h index faa37608..f8e95406 100644 --- a/src/quota_mnt.h +++ b/src/quota_mnt.h @@ -36,6 +36,8 @@ struct _quota_mnt_t { char *dir; char *device; char *type; + char *usrjquota; + char *grpjquota; int opts; quota_mnt_t *next; }; diff --git a/src/quota_plugin.c b/src/quota_plugin.c index 900dd293..2fef085e 100644 --- a/src/quota_plugin.c +++ b/src/quota_plugin.c @@ -63,16 +63,16 @@ quota_submit(quota_t *q) char *name, *n; r = snprintf(buf, BUFSIZE, - "%u:%llu:%lld:%lld:%llu:%llu:%llu:%lld:%lld:%llu:%llu", - (unsigned int)curtime, + "%ld:%llu:%lld:%lld:%lld:%lld:%llu:%lld:%lld:%lld:%lld", + (signed long)curtime, q->blocks, q->bquota, q->blimit, q->bgrace, q->btimeleft, q->inodes, q->iquota, q->ilimit, q->igrace, q->itimeleft); if(r < 1 || r >= BUFSIZE) { DBG("failed"); return; } - n = name = (char *)smalloc(strlen(q->type) + 1 + strlen(q->dir) - + 1 + strlen(q->name) + 1 + strlen(q->id)); + n = name = (char *)smalloc(strlen(q->type) + 1 + strlen(q->name) + + 1 + strlen(q->id) + 1 + strlen(q->dir) + 1); sstrncpy(n, q->type, strlen(q->type)+1); n += strlen(q->type); sstrncpy(n, "-", 1+1); @@ -86,7 +86,6 @@ quota_submit(quota_t *q) sstrncpy(n, "-", 1+1); n += 1; sstrncpy(n, q->dir, strlen(q->dir)+1); - n += strlen(q->dir); n = name; /* translate '/' -> '_' */ while(*n != '\0') { @@ -94,11 +93,12 @@ quota_submit(quota_t *q) *n = '_'; } n++; - } + } /* while(*n != '\0') */ DBG("rrd file: %s-%s", MODULE_NAME, name); plugin_submit(MODULE_NAME, name, buf); -} + free(name); +} /* static void quota_submit(quota_t *q) */ #undef BUFSIZE /* *** *** *** local plugin functions *** *** *** */ @@ -120,6 +120,9 @@ quota_read(void) while(l != NULL) { DBG("\tdir: %s", l->dir); DBG("\tdevice: %s", l->device); + DBG("\ttype: %s", l->type); + DBG("\tusrjquota: %s", l->usrjquota); + DBG("\tgrpjquota: %s", l->grpjquota); DBG("\topts: %s (0x%04x)", (l->opts == QMO_NONE) ? "-" : (l->opts == QMO_USRQUOTA) ? "USRQUOTA" @@ -141,10 +144,10 @@ quota_read(void) DBG("\tname: %s", q->name); DBG("\tid: %s", q->id); DBG("\tdir: %s", q->dir); - DBG("\tblocks: %llu (%lld/%lld) %llu %llu", + DBG("\tblocks: %llu (%lld/%lld) %lld %lld", q->blocks, q->bquota, q->blimit, q->bgrace, q->btimeleft); - DBG("\tinodes: %llu (%lld/%lld) %llu %llu", + DBG("\tinodes: %llu (%lld/%lld) %lld %lld", q->inodes, q->iquota, q->ilimit, q->igrace, q->itimeleft); quota_submit(q); -- 2.30.2