1 /*
2  * quota.c
3  * (C)1998-2011 by Marc Huber <Marc.Huber@web.de>
4  *
5  * $Id: quota.c,v 1.13 2015/03/14 06:11:27 marc Exp marc $
6  *
7  */
8 
9 #include <sys/types.h>
10 #include "headers.h"
11 #include <unistd.h>
12 #include <fcntl.h>
13 
14 static const char rcsid[] __attribute__ ((used)) = "$Id: quota.c,v 1.13 2015/03/14 06:11:27 marc Exp marc $";
15 
16 static int lock(int);
17 
quota_add(struct context * ctx,long long q)18 void quota_add(struct context *ctx, long long q)
19 {
20     int f;
21     ssize_t i;
22     char buffer[20];
23 
24     if (!ctx->quota_path)
25 	return;
26 
27     setegid(real_uid);
28     seteuid(real_gid);
29     f = open(ctx->quota_path, O_RDWR | O_CREAT | O_NOFOLLOW, 0644);
30     if (f > -1) {
31 	if (!lock(f)) {
32 	    buffer[0] = 0;
33 	    i = read(f, buffer, sizeof(buffer) - 1);
34 
35 	    if (i > 0)
36 		buffer[i] = 0;
37 
38 	    sscanf(buffer, "%lld", &ctx->quota_ondisk);
39 
40 	    if (q < 0 && ctx->quota_ondisk < -q)
41 		ctx->quota_ondisk = 0;
42 	    else
43 		ctx->quota_ondisk += q;
44 
45 	    if (q) {
46 		lseek(f, 0, SEEK_SET);
47 		if (ftruncate(f, 0)) {
48 		    //FIXME
49 		}
50 
51 		snprintf(buffer, sizeof(buffer), "%lld", ctx->quota_ondisk);
52 		if (write(f, buffer, strlen(buffer))) {
53 		    //FIXME
54 		}
55 	    }
56 	} else
57 	    logmsg("Updating quota file %s failed (%lld).", ctx->quota_path, q);
58 	close(f);
59     }
60     setegid(ctx->gid);
61     seteuid(ctx->uid);
62 }
63 
lock(int fn)64 static int lock(int fn)
65 {
66     struct flock fl;
67     int i;
68     sigset_t sig_set;
69 
70     Debug((DEBUG_LOCK, "+ %s (%d)\n", __func__, fn));
71 
72     fl.l_type = F_WRLCK;	/* exclusive lock */
73     fl.l_whence = SEEK_SET;
74     fl.l_len = 0;		/* lock whole file */
75     fl.l_start = 0;
76 
77     sigemptyset(&sig_set);
78     sigaddset(&sig_set, SIGALRM);
79     sigprocmask(SIG_UNBLOCK, &sig_set, NULL);
80 
81     alarm(2);			/* wait at most 2 seconds for the lock */
82     i = fcntl(fn, F_SETLKW, &fl);
83     alarm(0);
84 
85     sigprocmask(SIG_BLOCK, &sig_set, NULL);
86 
87     Debug((DEBUG_LOCK, "- %s %s\n", __func__, i ? "FAILURE" : "SUCCESS"));
88     return i;
89 }
90