/* -*- C -*- * $Id: quota.c,v 1.25 2002/03/30 14:59:12 ttate Exp $ * Copyright (C) 2000 Takaaki Tateishi */ #include "ruby.h" #define RUBY_QUOTA_VERSION "0.4.1" #ifdef HAVE_LINUX_QUOTA_H /* for linux-2.4.x */ # define USE_LINUX_QUOTA #endif #ifdef HAVE_SYS_FS_UFS_QUOTA_H /* for Solaris-2.6,7,8 */ # define USE_SOLARIS_QUOTA #endif #ifdef HAVE_UFS_UFS_QUOTA_H /* for *BSD */ # define USE_BSD_QUOTA #endif #ifdef USE_LINUX_QUOTA #ifdef HAVE_LINUX_TYPES_H # include #else # include #endif #ifdef HAVE_LINUX_QUOTA_H # include #else # include #endif #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) # define USE_LINUX_QUOTA_24 # define uid_t qid_t # define dqblk disk_dqblk #endif #endif #ifdef USE_SOLARIS_QUOTA #include #include #include #endif #ifdef USE_BSD_QUOTA #include #include #include #include #include #if defined(SYS_UCRED_H) # include /* required by NetBSD,FreeBSD */ #endif #endif static VALUE rb_mQuota; static VALUE rb_cUID_, rb_cGroupID, rb_cUserID; static VALUE rb_sDiskQuota; static VALUE rb_eQuotaError, rb_eQuotaCtlError; typedef struct q_uid_data { uid_t uid; } q_uid_data; static uid_t rb_quota_uid(VALUE vuid) { return ((q_uid_data*)DATA_PTR(vuid))->uid; }; static void rb_quota_uid_free(q_uid_data *data) { if( data ) free(data); }; static VALUE rb_quota_uid_new(VALUE klass, uid_t uid) { q_uid_data *data; VALUE obj; obj = Data_Make_Struct(klass, q_uid_data, 0, rb_quota_uid_free, data); data->uid = uid; return obj; }; static VALUE rb_quota_uid_s_new(int argc, VALUE argv[], VALUE klass) { VALUE num, obj; rb_scan_args(argc, argv, "1", &num); obj = rb_quota_uid_new(klass, NUM2UINT(num)); rb_obj_call_init(obj, argc, argv); return obj; }; static VALUE rb_quota_uid_initialize(int argc, VALUE argv[], VALUE self) { return Qnil; }; static VALUE rb_quota_uid_to_i(VALUE self) { return UINT2NUM(((q_uid_data*)DATA_PTR(self))->uid); }; static void get_uid(VALUE vuid, uid_t *uid, int *is_gid) { if( (TYPE(vuid) == T_FIXNUM) || (TYPE(vuid) == T_BIGNUM) ){ if( uid ) *uid = NUM2UINT(vuid); if( is_gid ) *is_gid = 0; } else if( vuid == Qnil ){ if( uid ) *uid = 0; if( is_gid ) *is_gid = 0; } else if( rb_obj_is_kind_of(vuid, rb_cUserID) ){ if( uid ) *uid = rb_quota_uid(vuid); if( is_gid ) *is_gid = 0; } else if( rb_obj_is_kind_of(vuid, rb_cGroupID) ){ if( uid ) *uid = rb_quota_uid(vuid); if( is_gid ) *is_gid = 1; } else{ rb_raise(rb_eTypeError, "An uid or gid is expected."); }; }; #if defined(USE_LINUX_QUOTA) /* for Linux */ static int rb_quotactl(int cmd, char *dev, VALUE vuid, caddr_t addr) { int is_gid; uid_t uid; get_uid(vuid, &uid, &is_gid); printf("cmd = %d, dev = %s, uid = %d, gid? = %d\n", cmd, dev, uid, is_gid); if( is_gid ){ return quotactl(QCMD(cmd,GRPQUOTA),dev,(qid_t)uid,addr); } else{ return quotactl(QCMD(cmd,USRQUOTA),dev,(qid_t)uid,addr); }; }; #elif defined(USE_BSD_QUOTA) /* for *BSD */ static int rb_quotactl(int cmd, char *dev, VALUE vuid, caddr_t addr) { char *path; int is_gid; uid_t uid; struct statfs *buff; int i, count, ret; buff = 0; path = dev; count = getmntinfo(&buff, MNT_WAIT); for( i=0; idqb_bhardlimit = GetMember("bhardlimit"); c_dqb->dqb_bsoftlimit = GetMember("bsoftlimit"); #if !defined(USE_LINUX_QUOTA_24) c_dqb->dqb_curblocks = GetMember("curblocks"); #endif c_dqb->dqb_ihardlimit = GetMember("ihardlimit"); c_dqb->dqb_isoftlimit = GetMember("isoftlimit"); c_dqb->dqb_curinodes = GetMember("curinodes"); c_dqb->dqb_btime = GetMember("btimelimit"); c_dqb->dqb_itime = GetMember("itimelimit"); #elif defined(USE_BSD_QUOTA) c_dqb->dqb_bhardlimit = GetMember("bhardlimit"); c_dqb->dqb_bsoftlimit = GetMember("bsoftlimit"); c_dqb->dqb_curblocks = GetMember("curblocks"); c_dqb->dqb_ihardlimit = GetMember("ihardlimit"); c_dqb->dqb_isoftlimit = GetMember("isoftlimit"); c_dqb->dqb_curinodes = GetMember("curinodes"); c_dqb->dqb_btime = GetMember("btimelimit"); c_dqb->dqb_itime = GetMember("itimelimit"); #elif defined(USE_SOLARIS_QUOTA) c_dqb->dqb_bhardlimit = GetMember("bhardlimit"); c_dqb->dqb_bsoftlimit = GetMember("bsoftlimit"); c_dqb->dqb_curblocks = GetMember("curblocks"); c_dqb->dqb_fhardlimit = GetMember("ihardlimit"); c_dqb->dqb_fsoftlimit = GetMember("isoftlimit"); c_dqb->dqb_curfiles = GetMember("curfiles"); c_dqb->dqb_btimelimit = GetMember("btimelimit"); c_dqb->dqb_ftimelimit = GetMember("itimelimit"); #endif #undef GetMember }; VALUE rb_diskquota_new(struct dqblk *c_dqb) { VALUE dqb; #if defined(USE_LINUX_QUOTA) dqb = rb_struct_new(rb_sDiskQuota, UINT2NUM(c_dqb->dqb_bhardlimit), UINT2NUM(c_dqb->dqb_bsoftlimit), #if defined(USE_LINUX_QUOTA_24) UINT2NUM(c_dqb->dqb_curspace), #else UINT2NUM(c_dqb->dqb_curblocks), #endif UINT2NUM(c_dqb->dqb_ihardlimit), UINT2NUM(c_dqb->dqb_isoftlimit), UINT2NUM(c_dqb->dqb_curinodes), UINT2NUM(c_dqb->dqb_btime), UINT2NUM(c_dqb->dqb_itime), 0); #elif defined(USE_BSD_QUOTA) dqb = rb_struct_new(rb_sDiskQuota, UINT2NUM(c_dqb->dqb_bhardlimit), UINT2NUM(c_dqb->dqb_bsoftlimit), UINT2NUM(c_dqb->dqb_curblocks), UINT2NUM(c_dqb->dqb_ihardlimit), UINT2NUM(c_dqb->dqb_isoftlimit), UINT2NUM(c_dqb->dqb_curinodes), UINT2NUM(c_dqb->dqb_btime), UINT2NUM(c_dqb->dqb_itime), 0); #elif defined(USE_SOLARIS) dqb = rb_struct_new(rb_sDiskQuota, UINT2NUM(c_dqb->dqb_bhardlimit), UINT2NUM(c_dqb->dqb_bsoftlimit), UINT2NUM(c_dqb->dqb_curblocks), UINT2NUM(c_dqb->dqb_fhardlimit), UINT2NUM(c_dqb->dqb_fsoftlimit), UINT2NUM(c_dqb->dqb_curfiles), UINT2NUM(c_dqb->dqb_btimelimit), UINT2NUM(c_dqb->dqb_ftimelimit), 0); #endif return dqb; }; static VALUE rb_quota_getquota(VALUE self, VALUE dev, VALUE uid) { char *c_dev = STR2CSTR(dev); struct dqblk c_dqb; VALUE dqb = Qnil; if( rb_quotactl(Q_GETQUOTA,c_dev,uid,(caddr_t)(&c_dqb)) == -1 ){ rb_sys_fail("quotactl"); }; dqb = rb_diskquota_new(&c_dqb); return dqb; }; VALUE rb_quota_quotaoff(VALUE self, VALUE dev) { char *c_dev = STR2CSTR(dev); if( rb_quotactl(Q_QUOTAOFF,c_dev,Qnil,NULL) == -1 ){ rb_sys_fail("quotactl"); }; return Qnil; }; VALUE rb_quota_quotaon(VALUE self, VALUE dev, VALUE quotas) { char *c_dev = STR2CSTR(dev); char *c_quotas = STR2CSTR(quotas); if( rb_quotactl(Q_QUOTAON,c_dev,Qnil,(caddr_t)c_quotas) == -1 ){ rb_sys_fail("quotactl"); }; return Qnil; }; VALUE rb_quota_setquota(VALUE self, VALUE dev, VALUE uid, VALUE dqb) { char *c_dev = STR2CSTR(dev); struct dqblk c_dqb; rb_diskquota_get(dqb, &c_dqb); if( rb_quotactl(Q_SETQUOTA,c_dev,uid,(caddr_t)(&c_dqb)) == -1 ){ rb_sys_fail("quotactl"); }; return Qnil; }; VALUE rb_quota_setqlim(VALUE self, VALUE dev, VALUE uid, VALUE dqb) { #ifdef Q_SETQLIM char *c_dev = STR2CSTR(dev); struct dqblk c_dqb; rb_diskquota_get(dqb, &c_dqb); if( rb_quotactl(Q_SETQLIM,c_dev,uid,(caddr_t)(&c_dqb)) == -1 ){ rb_sys_fail("quotactl"); }; #ifdef DEBUG printf("bhardlimit = %d\n",c_dqb.dqb_bhardlimit); #endif #else rb_raise(rb_eQuotaError, "the system don't have Q_SETQLIM"); #endif return Qnil; }; VALUE rb_quota_sync(VALUE self, VALUE dev) { char *c_dev; if( dev == Qnil ){ c_dev = NULL; } else{ c_dev = STR2CSTR(dev); }; if( rb_quotactl(Q_SYNC,c_dev,Qnil,NULL) == -1 ){ /* uid and addr are ignored */ rb_sys_fail("quotactl"); }; return Qnil; }; void Init_quota() { rb_mQuota = rb_define_module("Quota"); rb_define_const(rb_mQuota, "VERSION", rb_tainted_str_new2(RUBY_QUOTA_VERSION)); rb_eQuotaError = rb_define_class_under(rb_mQuota, "QuotaError",rb_eRuntimeError); rb_eQuotaCtlError = rb_define_class_under(rb_mQuota, "QuotaCtlError",rb_eQuotaError); rb_cUID_ = rb_define_class_under(rb_mQuota, "UID_", rb_cObject); rb_define_singleton_method(rb_cUID_, "new", rb_quota_uid_s_new, -1); rb_define_method(rb_cUID_, "initialize", rb_quota_uid_initialize, -1); rb_define_method(rb_cUID_, "to_i", rb_quota_uid_to_i, 0); rb_alias(CLASS_OF(rb_cUID_), rb_intern("[]"), rb_intern("new")); rb_alias(CLASS_OF(rb_cUID_), '|', rb_intern("new")); rb_alias(CLASS_OF(rb_cUID_), '+', rb_intern("new")); rb_cUserID = rb_define_class_under(rb_mQuota, "UserID", rb_cUID_); rb_define_singleton_method(rb_cUserID, "new", rb_quota_uid_s_new, -1); rb_cGroupID = rb_define_class_under(rb_mQuota, "GroupID", rb_cUID_); rb_define_singleton_method(rb_cUserID, "new", rb_quota_uid_s_new, -1); rb_sDiskQuota = rb_struct_define("DiskQuota", "bhardlimit", "bsoftlimit", "curblocks", "ihardlimit", "isoftlimit", "curinodes", "btimelimit", "itimelimit", 0); /* for compatibility */ #define DQ_ALIAS(a,b) rb_alias(rb_sDiskQuota,rb_intern(#a),rb_intern(#b)) DQ_ALIAS(fhardlimit, ihardlimit); DQ_ALIAS(fsoftlimit, isoftlimit); DQ_ALIAS(curfiles, curinodes); DQ_ALIAS(ftimelimit, itimelimit); DQ_ALIAS(fhardlimit=, ihardlimit=); DQ_ALIAS(fsoftlimit=, isoftlimit=); DQ_ALIAS(curfiles=, curinodes=); DQ_ALIAS(ftimelimit=, itimelimit=); #if defined(USE_LINUX_QUOTA_24) DQ_ALIAS(curspace, curblocks); DQ_ALIAS(curspace=, curblocks=); #endif #undef DQ_ALIAS rb_define_const(rb_mQuota, "DiskQuota", rb_sDiskQuota); rb_define_module_function(rb_mQuota,"quotaon",rb_quota_quotaon,2); rb_define_module_function(rb_mQuota,"quotaoff",rb_quota_quotaoff,1); rb_define_module_function(rb_mQuota,"getquota",rb_quota_getquota,2); rb_define_module_function(rb_mQuota,"setquota",rb_quota_setquota,3); rb_define_module_function(rb_mQuota,"setqlim",rb_quota_setqlim,3); rb_define_module_function(rb_mQuota,"sync",rb_quota_sync,1); };