summaryrefslogtreecommitdiff
path: root/warnquota.c
diff options
context:
space:
mode:
authorjkar8572 <jkar8572>2002-07-23 15:59:27 +0000
committerjkar8572 <jkar8572>2002-07-23 15:59:27 +0000
commit8e0302ea1b0d327c66839ad738d2d5271e25f4d7 (patch)
tree544a35abe5b1978eeed817f964bfb82a0db3c89a /warnquota.c
parent2d1fc29bbe752b590d9f320df80913c3808f7545 (diff)
* fixed quotacheck(8) to continue when old quota files were not found (Jan Kara)
* quota(1) now doesn't report failure to connect to rpc.rquotad server when -Q specified (Jan Kara) * add quota(1) option -l (report only local filesystems) (Jan Kara) * warnquota(8) now also mails specified member of the group about violation of the group quotas when -g option is specified (Jan Kara) * added options by which user can specify whether repquota(8) should translate names in big chunks by scanning all users or individually. Added automagic detection using nsswitch.conf which behaviour should lead to faster translating. (Jan Kara)
Diffstat (limited to 'warnquota.c')
-rw-r--r--warnquota.c208
1 files changed, 178 insertions, 30 deletions
diff --git a/warnquota.c b/warnquota.c
index 17638a5..f973fa6 100644
--- a/warnquota.c
+++ b/warnquota.c
@@ -10,7 +10,7 @@
*
* Author: Marco van Wieringen <mvw@planets.elm.net>
*
- * Version: $Id: warnquota.c,v 1.10 2002/03/27 16:21:26 jkar8572 Exp $
+ * Version: $Id: warnquota.c,v 1.11 2002/07/23 15:59:27 jkar8572 Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,6 +26,7 @@
#include <errno.h>
#include <ctype.h>
#include <signal.h>
+#include <grp.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -44,21 +45,36 @@
#define SUPPORT "support@localhost"
#define PHONE "(xxx) xxx-xxxx or (yyy) yyy-yyyy"
-#define DEF_MESSAGE _("Hi,\n\nWe noticed that you are in violation with the quotasystem\n" \
+#define DEF_USER_MESSAGE _("Hi,\n\nWe noticed that you are in violation with the quotasystem\n" \
"used on this system. We have found the following violations:\n\n")
-#define DEF_SIGNATURE _("\nWe hope that you will cleanup before your grace period expires.\n" \
+#define DEF_USER_SIGNATURE _("\nWe hope that you will cleanup before your grace period expires.\n" \
"\nBasically, this means that the system thinks you are using more disk space\n" \
"on the above partition(s) than you are allowed. If you do not delete files\n" \
"and get below your quota before the grace period expires, the system will\n" \
"prevent you from creating new files.\n\n" \
"For additional assistance, please contact us at %s\nor via " \
"phone at %s.\n")
+#define DEF_GROUP_MESSAGE _("Hi,\n\nWe noticed that the group %s you are member of violates the quotasystem\n" \
+ "used on this system. We have found the following violations:\n\n")
+#define DEF_GROUP_SIGNATURE _("\nPlease cleanup the group data before the grace period expires.\n" \
+ "\nBasically, this means that the system thinks group is using more disk space\n" \
+ "on the above partition(s) than it is allowed. If you do not delete files\n" \
+ "and get below group quota before the grace period expires, the system will\n" \
+ "prevent you and other members of the group from creating new files owned by\n" \
+ "the group.\n\n" \
+ "For additional assistance, please contact us at %s\nor via " \
+ "phone at %s.\n")
#define SHELL "/bin/sh"
#define QUOTATAB "/etc/quotatab"
#define CNF_BUFFER 2048
#define IOBUF_SIZE 16384 /* Size of buffer for line in config files */
+#define ADMIN_TAB_ALLOC 256 /* How many entries to admins table should we allocate at once? */
#define WARNQUOTA_CONF "/etc/warnquota.conf"
+#define ADMINSFILE "/etc/quotagrpadmins"
+
+#define FL_USER 1
+#define FL_GROUP 2
struct usage {
char *devicename;
@@ -73,11 +89,14 @@ struct configparams {
char cc_to[CNF_BUFFER];
char support[CNF_BUFFER];
char phone[CNF_BUFFER];
- char *message;
- char *signature;
+ char *user_message;
+ char *user_signature;
+ char *group_message;
+ char *group_signature;
};
struct offenderlist {
+ int offender_type;
int offender_id;
char *offender_name;
struct usage *usage;
@@ -89,29 +108,37 @@ typedef struct quotatable {
char *devdesc;
} quotatable_t;
-int qtab_i = 0, fmt = -1;
-char *configfile = WARNQUOTA_CONF, *quotatabfile = QUOTATAB;
+struct adminstable {
+ char *grpname;
+ char *adminname;
+};
+
+int qtab_i = 0, fmt = -1, flags;
+char *configfile = WARNQUOTA_CONF, *quotatabfile = QUOTATAB, *adminsfile = ADMINSFILE;
char *progname;
-quotatable_t *quotatable = (quotatable_t *) NULL;
+quotatable_t *quotatable;
+int adminscnt, adminsalloc;
+struct adminstable *adminstable;
/*
* Global pointers to list.
*/
static struct offenderlist *offenders = (struct offenderlist *)0;
-struct offenderlist *add_offender(int id, char *name)
+struct offenderlist *add_offender(int type, int id, char *name)
{
struct offenderlist *offender;
char namebuf[MAXNAMELEN];
if (!name) {
- if (id2name(id, USRQUOTA, namebuf)) {
- errstr(_("Can't get name for uid %u.\n"), id);
+ if (id2name(id, type, namebuf)) {
+ errstr(_("Can't get name for uid/gid %u.\n"), id);
return NULL;
}
name = namebuf;
}
offender = (struct offenderlist *)smalloc(sizeof(struct offenderlist));
+ offender->offender_type = type;
offender->offender_id = id;
offender->offender_name = sstrdup(name);
offender->usage = (struct usage *)NULL;
@@ -126,11 +153,11 @@ void add_offence(struct dquot *dquot, char *name)
struct usage *usage;
for (lptr = offenders; lptr; lptr = lptr->next)
- if (lptr->offender_id == dquot->dq_id)
+ if (dquot->dq_h->qh_type == lptr->offender_type && lptr->offender_id == dquot->dq_id)
break;
if (!lptr)
- if (!(lptr = add_offender(dquot->dq_id, name)))
+ if (!(lptr = add_offender(dquot->dq_h->qh_type, dquot->dq_id, name)))
return;
usage = (struct usage *)smalloc(sizeof(struct usage));
@@ -183,6 +210,11 @@ FILE *run_mailer(char *command)
}
}
+int admin_name_cmp(const void *key, const void *mem)
+{
+ return strcmp(key, ((struct adminstable *)mem)->grpname);
+}
+
int mail_user(struct offenderlist *offender, struct configparams *config)
{
struct usage *lptr;
@@ -190,19 +222,37 @@ int mail_user(struct offenderlist *offender, struct configparams *config)
int cnt, status;
char timebuf[MAXTIMELEN];
struct util_dqblk *dqb;
+ char *to;
+
+ if (offender->offender_type == USRQUOTA)
+ to = offender->offender_name;
+ else {
+ struct adminstable *admin;
+ if (!(admin = bsearch(offender->offender_name, adminstable, adminscnt, sizeof(struct adminstable), admin_name_cmp))) {
+ errstr(_("Administrator for a group %s not found. Cancelling mail.\n"), offender->offender_name);
+ return -1;
+ }
+ to = admin->adminname;
+ }
if (!(fp = run_mailer(config->mail_cmd)))
return -1;
fprintf(fp, "From: %s\n", config->from);
fprintf(fp, "Reply-To: %s\n", config->support);
fprintf(fp, "Subject: %s\n", config->subject);
- fprintf(fp, "To: %s\n", offender->offender_name);
+ fprintf(fp, "To: %s\n", to);
fprintf(fp, "Cc: %s\n", config->cc_to);
fprintf(fp, "\n");
- if (config->message)
- fputs(config->message, fp);
+ if (offender->offender_type == USRQUOTA)
+ if (config->user_message)
+ fputs(config->user_message, fp);
+ else
+ fputs(DEF_USER_MESSAGE, fp);
else
- fputs(DEF_MESSAGE, fp);
+ if (config->group_message)
+ fprintf(fp, config->group_message, offender->offender_name);
+ else
+ fprintf(fp, DEF_GROUP_MESSAGE, offender->offender_name);
for (lptr = offender->usage; lptr; lptr = lptr->next) {
dqb = &lptr->dq_dqb;
@@ -235,10 +285,16 @@ int mail_user(struct offenderlist *offender, struct configparams *config)
fprintf(fp, " %6Lu%6Lu%6Lu%7s\n\n", (long long)dqb->dqb_curinodes,
(long long)dqb->dqb_isoftlimit, (long long)dqb->dqb_ihardlimit, timebuf);
}
- if (config->signature)
- fputs(config->signature, fp);
+ if (offender->offender_type == USRQUOTA)
+ if (config->user_signature)
+ fputs(config->user_signature, fp);
+ else
+ fprintf(fp, DEF_USER_SIGNATURE, config->support, config->phone);
else
- fprintf(fp, DEF_SIGNATURE, config->support, config->phone);
+ if (config->group_signature)
+ fputs(config->group_signature, fp);
+ else
+ fprintf(fp, DEF_GROUP_SIGNATURE, config->support, config->phone);
fclose(fp);
if (wait(&status) < 0) /* Wait for mailer */
errstr(_("Can't wait for mailer: %s\n"), strerror(errno));
@@ -363,7 +419,7 @@ int readconfigfile(const char *filename, struct configparams *config)
sstrncpy(config->cc_to, CC_TO, CNF_BUFFER);
sstrncpy(config->support, SUPPORT, CNF_BUFFER);
sstrncpy(config->phone, PHONE, CNF_BUFFER);
- config->signature = config->message = NULL;
+ config->user_signature = config->user_message = config->group_signature = config->group_message = NULL;
if (!(fp = fopen(filename, "r"))) {
errstr(_("Can't open %s: %s\n"), filename, strerror(errno));
@@ -420,12 +476,20 @@ int readconfigfile(const char *filename, struct configparams *config)
else if (!strcmp(var, "PHONE"))
sstrncpy(config->phone, value, CNF_BUFFER);
else if (!strcmp(var, "MESSAGE")) {
- config->message = sstrdup(value);
- create_eoln(config->message);
+ config->user_message = sstrdup(value);
+ create_eoln(config->user_message);
}
else if (!strcmp(var, "SIGNATURE")) {
- config->signature = sstrdup(value);
- create_eoln(config->signature);
+ config->user_signature = sstrdup(value);
+ create_eoln(config->user_signature);
+ }
+ else if (!strcmp(var, "GROUP_MESSAGE")) {
+ config->group_message = sstrdup(value);
+ create_eoln(config->group_message);
+ }
+ else if (!strcmp(var, "GROUP_SIGNATURE")) {
+ config->group_signature = sstrdup(value);
+ create_eoln(config->group_signature);
}
else /* not matched at all */
errstr(_("Error in config file (line %d), ignoring\n"), line);
@@ -440,6 +504,68 @@ int readconfigfile(const char *filename, struct configparams *config)
return 0;
}
+int admin_cmp(const void *a1, const void *a2)
+{
+ return strcmp(((struct adminstable *)a1)->grpname, ((struct adminstable *)a2)->grpname);
+}
+
+/* Get administrators of the groups */
+int get_groupadmins(void)
+{
+ FILE *f;
+ int line = 0;
+ char buffer[IOBUF_SIZE], *colpos, *grouppos, *endname, *adminpos;
+
+ if (!(f = fopen(adminsfile, "r"))) {
+ errstr(_("Can't open file with group administrators: %s\n"), strerror(errno));
+ return -1;
+ }
+
+ while (fgets(buffer, IOBUF_SIZE, f)) {
+ line++;
+ if (buffer[0] == ';' || buffer[0] == '#')
+ continue;
+ /* Skip initial spaces */
+ for (colpos = buffer; isspace(*colpos); colpos++);
+ if (!*colpos) /* Empty line? */
+ continue;
+ /* Find splitting colon */
+ for (grouppos = colpos; *colpos && *colpos != ':'; colpos++);
+ if (!*colpos || grouppos == colpos) {
+ errstr(_("Parse error at line %d. Can't find end of group name.\n"), line);
+ continue;
+ }
+ /* Cut trailing spaces */
+ for (endname = colpos-1; isspace(*endname); endname--);
+ *(++endname) = 0;
+ /* Skip initial spaces at admins name */
+ for (colpos++; isspace(*colpos); colpos++);
+ if (!*colpos) {
+ errstr(_("Parse error at line %d. Can't find administrators name.\n"), line);
+ continue;
+ }
+ /* Go through admins name */
+ for (adminpos = colpos; !isspace(*colpos); colpos++);
+ if (*colpos) { /* Some characters after name? */
+ *colpos = 0;
+ /* Skip trailing spaces */
+ for (colpos++; isspace(*colpos); colpos++);
+ if (*colpos) {
+ errstr(_("Parse error at line %d. Trailing characters after administrators name.\n"), line);
+ continue;
+ }
+ }
+ if (adminscnt >= adminsalloc)
+ adminstable = srealloc(adminstable, sizeof(struct adminstable)*(adminsalloc+=ADMIN_TAB_ALLOC));
+ adminstable[adminscnt].grpname = sstrdup(grouppos);
+ adminstable[adminscnt++].adminname = sstrdup(adminpos);
+ }
+
+ fclose(f);
+ qsort(adminstable, adminscnt, sizeof(struct adminstable), admin_cmp);
+ return 0;
+}
+
void warn_quota(void)
{
struct quota_handle **handles;
@@ -451,9 +577,20 @@ void warn_quota(void)
if (get_quotatable() < 0)
exit(1);
- handles = create_handle_list(0, NULL, USRQUOTA, -1, IOI_LOCALONLY | IOI_READONLY | IOI_OPENFILE);
- for (i = 0; handles[i]; i++)
- handles[i]->qh_ops->scan_dquots(handles[i], check_offence);
+ if (flags & FL_USER) {
+ handles = create_handle_list(0, NULL, USRQUOTA, -1, IOI_LOCALONLY | IOI_READONLY | IOI_OPENFILE);
+ for (i = 0; handles[i]; i++)
+ handles[i]->qh_ops->scan_dquots(handles[i], check_offence);
+ dispose_handle_list(handles);
+ }
+ if (flags & FL_GROUP) {
+ if (get_groupadmins() < 0)
+ exit(1);
+ handles = create_handle_list(0, NULL, GRPQUOTA, -1, IOI_LOCALONLY | IOI_READONLY | IOI_OPENFILE);
+ for (i = 0; handles[i]; i++)
+ handles[i]->qh_ops->scan_dquots(handles[i], check_offence);
+ dispose_handle_list(handles);
+ }
if (mail_to_offenders(&config) < 0)
exit(1);
}
@@ -461,14 +598,14 @@ void warn_quota(void)
/* Print usage information */
static void usage(void)
{
- errstr(_("Usage:\n warnquota [-F quotaformat] [-c configfile] [-q quotatabfile]\n"));
+ errstr(_("Usage:\n warnquota [-ug] [-F quotaformat] [-c configfile] [-q quotatabfile]\n"));
}
static void parse_options(int argcnt, char **argstr)
{
int ret;
- while ((ret = getopt(argcnt, argstr, "VF:hc:q:")) != -1) {
+ while ((ret = getopt(argcnt, argstr, "ugVF:hc:q:a:")) != -1) {
switch (ret) {
case '?':
case 'h':
@@ -486,8 +623,19 @@ static void parse_options(int argcnt, char **argstr)
case 'q':
quotatabfile = optarg;
break;
+ case 'a':
+ adminsfile = optarg;
+ break;
+ case 'u':
+ flags |= FL_USER;
+ break;
+ case 'g':
+ flags |= FL_GROUP;
+ break;
}
}
+ if (!(flags & FL_USER) && !(flags & FL_GROUP))
+ flags |= FL_USER;
}
int main(int argc, char **argv)