#include #include #include #include #include #include "diskquotaconf.h" #include "diskquotaconf.m" #include "quota.h" #include #include static HELP_FILE help_uquota ("diskquotaconf","uquota"); static HELP_FILE help_gquota ("diskquotaconf","gquota"); static HELP_FILE help_userdef_g ("diskquotaconf","userdef_g"); extern HELP_FILE help_quota; class QUOTA_COMNG: public USERACCT_COMNG{ QUOTA_TYPE type; // Edit a user or a group or a group defaults SSTRING name; SSTRING group; QUOTA_SPECS specs; // effective specs of the current user or group bool is_new; // We are editing a new user/group /*~PROTOBEG~ QUOTA_COMNG */ public: QUOTA_COMNG (DICTIONARY&_dict, QUOTA_TYPE type); int deluser (PRIVILEGE *priv); private: void geteffspec (QUOTA_DEV *d, QUOTA_SPEC&eff, const char *ptname); void geteffspec (QUOTA_DEV *d, QUOTA_SPEC&eff); QUOTA_SPEC *getspec (QUOTA_DEV *d); public: int save (PRIVILEGE *priv); void setgroup (const char *grp); void setupdia (DIALOG&dia); private: void show_curvalue (DIALOG&dia, const char *title, int value); public: int validate (DIALOG&, int &nof); ~QUOTA_COMNG (void); /*~PROTOEND~ QUOTA_COMNG */ }; /* Prepare the edition of disk quota for a user account or group */ PUBLIC QUOTA_COMNG::QUOTA_COMNG (DICTIONARY &_dict, QUOTA_TYPE type) : USERACCT_COMNG (_dict) { this->type = type; name.setfrom(dict.get_str("name")); group.setfrom (dict.get_str("group")); is_new = dict.get_bool ("is_new"); quota_allocctl(); for (int i=0; idevs.getnb(); i++){ QUOTA_DEV *d = ctl->devs.getitem(i); QUOTA_SPEC *u = getspec(d); if (u == NULL){ u = new QUOTA_SPEC(); u->name.setfrom (name); }else{ u = new QUOTA_SPEC(u); } specs.add (u); } } PUBLIC void QUOTA_COMNG::setgroup (const char *grp) { group.setfrom (grp); } PUBLIC QUOTA_COMNG::~QUOTA_COMNG () { quota_freectl(); } /* Extract the quota spec associated with the name. Return NULL if not found */ PRIVATE QUOTA_SPEC *QUOTA_COMNG::getspec (QUOTA_DEV *d) { QUOTA_SPEC *u = NULL; const char *nam = name.get(); if (nam[0] != '\0'){ if (type == QUOTA_USER){ u = d->getuserspec (nam); }else if (type == QUOTA_GROUP){ u= d->getgroupspec (nam); }else if (type == QUOTA_USERDEF_G){ u= d->getuserdef_gspec (nam); } } return u; } PRIVATE void QUOTA_COMNG::show_curvalue ( DIALOG &dia, const char *title, int value) { if (type != QUOTA_USERDEF_G && value >= 0){ dia.newf_num (title,value); dia.set_lastreadonly(); } } static void format_defval (char tmp[100],int soft, int hard) { char v1[100],v2[100]; sprintf (v1,"%d",soft); sprintf (v2,"%d",hard); sprintf (tmp,"%s/%s" ,soft == 0 ? MSG_R(I_NOLIMIT) : v1 ,hard == 0 ? MSG_R(I_NOLIMIT) : v2); } /* Add the different fields in the dialog for that user or group */ PUBLIC void QUOTA_COMNG::setupdia ( DIALOG &dia) { int n = specs.getnb(); if (n > 0){ static const char *tbtitle[]={ MSG_U(T_DISKQUOTAS,"Disk quotas"), MSG_U(T_GDISKQUOTAS,"Group disk quotas"), MSG_U(T_UDEFDISKQUOTAS,"Members default disk quotas"), }; int id = -1; switch (type){ case QUOTA_USER: { struct passwd *p = getpwnam (name.get()); if (p != NULL) id = p->pw_uid; } dia.addhelp (help_uquota,MSG_U(T_UDISKQUOTAS,"User disk quotas")); break; case QUOTA_GROUP: { struct group *p = getgrnam (name.get()); if (p != NULL) id = p->gr_gid; } dia.addhelp (help_gquota,MSG_R(T_GDISKQUOTAS)); break; case QUOTA_USERDEF_G: dia.addhelp (help_userdef_g,MSG_R(T_UDEFDISKQUOTAS)); break; } dia.addhelp (help_quota,MSG_R(T_DISKQUOTAS)); dia.newf_title (tbtitle[type],1,"",tbtitle[type]); for (int i=0; idevs.getitem(i); if (!d->has_quota_u && type != QUOTA_GROUP) continue; if (!d->has_quota_g && type == QUOTA_GROUP) continue; QUOTA_SPEC *s = specs.getitem(i); const char *title = d->device.get(); const char *device = d->getrealdevice(); QUOTA_USED cur; switch (type){ case QUOTA_USER: quota_read (cur,id,true,device); break; case QUOTA_GROUP: quota_read (cur,id,false,device); break; case QUOTA_USERDEF_G: // No current setting. We are defining defaults here break; } dia.newf_title (title,2,"",title); static const char *tbvals[]={ MSG_U(I_DEFAULT,"Default"), MSG_R(I_NOLIMIT), NULL }; static int vals[]={-1,0}; dia.newf_chkm_num (MSG_R(F_SOFTK),s->soft_maxk,vals,tbvals); dia.newf_chkm_num (MSG_R(F_HARDK),s->hard_maxk,vals,tbvals); show_curvalue (dia,MSG_U(F_CURUSEDK,"Current usage(k)"),cur.block_used); // Get the inherited default configuration QUOTA_SPEC eff; geteffspec (d,eff,""); char tmp[100]; format_defval (tmp,eff.soft_maxk,eff.hard_maxk); dia.newf_info (MSG_U(F_DEFLIMITS,"Inherited limits soft/hard") ,tmp); dia.newf_str (MSG_R(F_GRACEK),s->grace_k); dia.newf_title ("",""); dia.newf_chkm_num (MSG_R(F_SOFTF),s->soft_maxf,vals,tbvals); dia.newf_chkm_num (MSG_R(F_HARDF),s->hard_maxf,vals,tbvals); show_curvalue (dia,MSG_U(F_CURUSEDF,"Current usage(Files)"),cur.inode_used); format_defval (tmp,eff.soft_maxk,eff.hard_maxk); dia.newf_info (MSG_R(F_DEFLIMITS),tmp); dia.newf_str (MSG_R(F_GRACEF),s->grace_f); } } } /* Accept the changes done for this user or group */ PUBLIC int QUOTA_COMNG::save( PRIVILEGE *priv) { const char *nam = dict.get_str ("name"); for (int i=0; idevs.getitem(i); QUOTA_SPEC *s = specs.getitem(i); s->name.setfrom (nam); QUOTA_SPEC old_eff; // Current effective state of the quota // spec for this user or group geteffspec (d,old_eff); bool empty = s->soft_maxk == -1 && s->soft_maxf == -1 && s->hard_maxk == -1 && s->hard_maxf == -1; QUOTA_SPEC *u = getspec(d); if (u == NULL){ if (!empty){ QUOTA_SPEC *ns = new QUOTA_SPEC(s); if (type == QUOTA_USER){ d->users.add (ns); }else if (type == QUOTA_GROUP){ d->groups.add (ns); }else if (type == QUOTA_USERDEF_G){ d->userdef_g.add (ns); } } }else{ if (empty){ if (type == QUOTA_USER){ d->deluserspec (nam); }else if (type == QUOTA_GROUP){ d->delgroupspec (nam); }else if (type == QUOTA_USERDEF_G){ d->deluserdef_gspec (nam); } }else{ u->setfrom (s); } } QUOTA_SPEC new_eff; geteffspec (d,new_eff); if (is_new || old_eff.isdiff (new_eff)){ if (d->setrealdevice()!=-1){ const char *device = d->realdev.get(); if (type == QUOTA_USER){ struct passwd *p = getpwnam (nam); if (p != NULL){ quota_apply (new_eff,p->pw_uid,true,device); } }else if (type == QUOTA_GROUP){ struct group *g = getgrnam (nam); if (g != NULL){ quota_apply (new_eff,g->gr_gid,false,device); } }else if (type == QUOTA_USERDEF_G){ // We have to walk all member of the group and maybe // update their quota struct group *g = getgrnam (nam); if (g != NULL){ gid_t gid = g->gr_gid; setpwent(); struct passwd *p; while ((p=getpwent())!=NULL){ if (p->pw_gid == gid){ QUOTA_SPEC eff; d->geteffuserspec (p->pw_name,nam,eff); quota_apply (eff,p->pw_uid,true,device); } } } } } } } quota_closecmdfile(); return ctl->write(priv); } PUBLIC int QUOTA_COMNG::validate( DIALOG &, int &nof) { int ret = 0; name.setfrom (dict.get_str("name")); group.setfrom (dict.get_str("group")); return ret; } int quota_deluser (const char *id) { quota_allocctl(); int ret = ctl->deluser (QUOTA_USER,id,NULL); quota_freectl(); return ret; } /* Remove the user from the quota.conf file */ PUBLIC int QUOTA_COMNG::deluser ( PRIVILEGE *priv) { const char *nam = dict.get_str ("name"); return ctl->deluser (type,nam,priv); } /* Extract the effective quota spec associated with a name. */ PRIVATE void QUOTA_COMNG::geteffspec ( QUOTA_DEV *d, QUOTA_SPEC &eff, const char *ptname) { if (type == QUOTA_USER){ d->geteffuserspec (ptname,group.get(),eff); }else if (type == QUOTA_GROUP){ d->geteffgroupspec (ptname,eff); }else if (type == QUOTA_USERDEF_G){ d->geteffuserspec ("",ptname,eff); } } /* Extract the effective quota spec associated with the name. */ PRIVATE void QUOTA_COMNG::geteffspec (QUOTA_DEV *d, QUOTA_SPEC &eff) { geteffspec (d,eff,name.get()); } /* Set useron if at least one device has user quota enabled. Does the same thing for groupon for group quota. */ static void quota_somedevs(bool &useron, bool &groupon) { groupon = useron = false; FSTAB fs; for (int i=0; ihas_quota_u()) useron = true; if (e->has_quota_g()) groupon = true; } } /* With one REGISTER_USERACCT_COMNG, we can only create one COMNG object and for group, we need 2. So we create two register objects. */ static USERACCT_COMNG *quota_newcomng1( const char *key, DICTIONARY &dict) { USERACCT_COMNG *ret = NULL; const char *domain = dict.get_str("domain"); if (domain != NULL && strcmp(domain,"/")==0){ bool useron, groupon; quota_somedevs (useron,groupon); if (strcmp(key,"user")==0 && useron){ if (perm_getuid()==0 || policies_mayeditquota()){ ret = new QUOTA_COMNG (dict,QUOTA_USER); } }else if (strcmp(key,"group")==0 && groupon){ ret = new QUOTA_COMNG (dict,QUOTA_GROUP); } } return ret; } static REGISTER_USERACCT_COMNG qqq1 (quota_newcomng1); static USERACCT_COMNG *quota_newcomng2( const char *key, DICTIONARY &dict) { USERACCT_COMNG *ret = NULL; const char *domain = dict.get_str("domain"); if (domain != NULL && strcmp(domain,"/")==0){ bool useron, groupon; quota_somedevs (useron,groupon); if (strcmp(key,"group")==0 && useron){ ret = new QUOTA_COMNG (dict,QUOTA_USERDEF_G); } } return ret; } static REGISTER_USERACCT_COMNG qqq2 (quota_newcomng2);