/*
// File: /adm/daemons/quota.c
// Purpose: maintain preset disk quotas by checking how much disk space
// a user is using before allowing them to use more
// 93-05-15 Created by Watcher@TMI-2
// This file is part of the TMI-2 distribution.
// Please keep this header if you use any of this code.
// 93-07-30 Grendel@TMI-2 Fixed a bug which didn't allow anyone
// to write to the root directory properly.
// 93-08-18 Pallando@TMI-2 Fixed another bug which was still preventing
// mv from working with files in the root directory.
*/
#include <uid.h>
#include <mudlib.h>
inherit DAEMON;
#define MAX_RECURSION 6
#define DEFAULT_QUOTA 200
#define STUDENT_QUOTA 100
#define USER_QUOTAS "/adm/etc/user_quotas"
void load_quotas();
int dir_size(string where, int level);
mapping quotas;
void create() { seteuid(getuid()); load_quotas(); }
// This function loads up all the preset user quotas
void load_quotas() {
string *tmp, file, name;
int loop, amount;
quotas = ([ ]); // Initialize the quotas mapping
file = read_file(USER_QUOTAS);
if(!file || !(tmp = explode(file, "\n"))) return;
for(loop=0; loop<sizeof(tmp); loop++)
if(tmp[loop][0] == '#' || tmp[loop][0] == '\n' || tmp[loop] == "" ||
sscanf(tmp[loop], "%s:%d", name, amount) != 2) continue;
else quotas[name] = amount;
}
// Allow an external user quota query to go through...but if it isn't
// coming from a ROOT daemon, only give them a copy of the mapping.
mapping query_quotas() {
//if(geteuid(previous_object()) == ROOT_UID) return quotas;
//else return copy(quotas);
return copy(quotas);
}
// This function actually performs the quota check and returns whether
// the write is allowed or not to the master system.
int quota_check(string dir) {
string *path;
int quota;
if(!dir || !stringp(dir)) return 0; // error
// Parse out the directory path
path = explode(dir, "/");
if(!path || !sizeof(path)) return 1; // root directory
// If an admin is trying to write somewhere ... let them.
if(this_player() && adminp(geteuid(this_player())))
return 1;
// First lets see if the requested file/dir is actually a
// user directory ... at least at the root user dir level.
if(path[0] == "u" && sizeof(path) >= 3) {
// Let Admins use as much space as they want ... they know best.
if(adminp(path[2])) return 1;
// Check to see if there is a preset quota in place for
// this particular user, if not, use the DEFAULT_QUOTA.
quota = quotas[path[2]];
if(!quota) quota = DEFAULT_QUOTA;
// Will this write put the user beyond their quota?
if(dir_size("/u/" + path[1] + "/" + path[2], 0)/1000 >= quota)
return 0;
else return 1;
}
else if(path[0] == "student" && sizeof(path) > 3) {
// Check to see if there is a preset quota in place for
// this particular user, if not, use the STUDENT_QUOTA.
quota = quotas[path[2]];
if(!quota) quota = STUDENT_QUOTA;
// Will this write put the user beyond their quota?
if(dir_size("/student/" + path[1], 0)/1000 >= quota)
return 0;
else return 1;
}
// Well, if we've gotten this far, its probably an admin or
// system directory, and since there are no quotas there,
// let the file write continue.
return 1; }
// This function performs the actual totaling of the files and
// subdirectories within the requested directory.
int dir_size(string path, int level) {
string *dir;
int loop, size, sub;
if(level > MAX_RECURSION) return 0;
size = file_size(path);
if(size == -1) return 0;
if(size == -2) {
size = 0;
dir = get_dir(path + "/");
if(dir) {
sub = sizeof(dir);
for(loop=0; loop<sub; loop++)
size += dir_size(path + "/" + dir[loop], level + 1);
}
}
return size; }