1/* 2 Unix SMB/CIFS implementation. 3 System QUOTA function wrappers for QUOTACTL_4A 4 Copyright (C) Stefan (metze) Metzmacher 2003 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20 21#include "includes.h" 22 23#undef DBGC_CLASS 24#define DBGC_CLASS DBGC_QUOTA 25 26#ifndef HAVE_SYS_QUOTAS 27#ifdef HAVE_QUOTACTL_4A 28#undef HAVE_QUOTACTL_4A 29#endif 30#endif 31 32#ifdef HAVE_QUOTACTL_4A 33/* long quotactl(int cmd, char *special, qid_t id, caddr_t addr) */ 34/* this is used by: HPUX,IRIX */ 35 36#ifdef HAVE_SYS_TYPES_H 37#include <sys/types.h> 38#endif 39 40#ifdef HAVE_ASM_TYPES_H 41#include <asm/types.h> 42#endif 43 44#ifdef HAVE_SYS_QUOTA_H 45#include <sys/quota.h> 46#endif 47 48#ifndef Q_SETQLIM 49#define Q_SETQLIM Q_SETQUOTA 50#endif 51 52#ifndef QCMD 53#define QCMD(x,y) x 54#endif 55 56#ifndef QCMD 57#define QCMD(x,y) x 58#endif 59 60#ifdef GRPQUOTA 61#define HAVE_GROUP_QUOTA 62#endif 63 64#ifndef QUOTABLOCK_SIZE 65#define QUOTABLOCK_SIZE DEV_BSIZE 66#endif 67 68#ifdef HAVE_DQB_FSOFTLIMIT 69#define dqb_isoftlimit dqb_fsoftlimit 70#define dqb_ihardlimit dqb_fhardlimit 71#define dqb_curinodes dqb_curfiles 72#endif 73 74#ifdef INITQFNAMES 75#define USERQUOTAFILE_EXTENSION ".user" 76#else 77#define USERQUOTAFILE_EXTENSION "" 78#endif 79 80#if !defined(QUOTAFILENAME) && defined(QFILENAME) 81#define QUOTAFILENAME QFILENAME 82#endif 83 84/**************************************************************************** 85 Abstract out the quotactl_4A get calls. 86****************************************************************************/ 87int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) 88{ 89 int ret = -1; 90 uint32 qflags = 0; 91 struct dqblk D; 92 uint64_t bsize = (uint64_t)QUOTABLOCK_SIZE; 93 94 ZERO_STRUCT(D); 95 ZERO_STRUCT(*dp); 96 dp->qtype = qtype; 97 98 switch (qtype) { 99 case SMB_USER_QUOTA_TYPE: 100 DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n", 101 path, bdev, (unsigned)id.uid)); 102 103 if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), (caddr_t)bdev, id.uid, (void *)&D))&&errno != EDQUOT) { 104 return ret; 105 } 106 107 if ((D.dqb_curblocks==0)&& 108 (D.dqb_bsoftlimit==0)&& 109 (D.dqb_bhardlimit==0)) { 110 /* the upper layer functions don't want empty quota records...*/ 111 return -1; 112 } 113 114 break; 115#ifdef HAVE_GROUP_QUOTA 116 case SMB_GROUP_QUOTA_TYPE: 117 DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n", 118 path, bdev, (unsigned)id.gid)); 119 120 if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), (caddr_t)bdev, id.gid, (void *)&D))&&errno != EDQUOT) { 121 return ret; 122 } 123 124 if ((D.dqb_curblocks==0)&& 125 (D.dqb_bsoftlimit==0)&& 126 (D.dqb_bhardlimit==0)) { 127 /* the upper layer functions don't want empty quota records...*/ 128 return -1; 129 } 130 131 break; 132#endif /* HAVE_GROUP_QUOTA */ 133 case SMB_USER_FS_QUOTA_TYPE: 134 id.uid = getuid(); 135 136 DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n", 137 path, (caddr_t)bdev, (unsigned)id.uid)); 138 139 if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), (caddr_t)bdev, id.uid, (void *)&D))==0) { 140 qflags |= QUOTAS_DENY_DISK; 141 } 142 143 ret = 0; 144 break; 145#ifdef HAVE_GROUP_QUOTA 146 case SMB_GROUP_FS_QUOTA_TYPE: 147 id.gid = getgid(); 148 149 DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n", 150 path, bdev, (unsigned)id.gid)); 151 152 if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), (caddr_t)bdev, id.gid, (void *)&D))==0) { 153 qflags |= QUOTAS_DENY_DISK; 154 } 155 156 ret = 0; 157 break; 158#endif /* HAVE_GROUP_QUOTA */ 159 default: 160 errno = ENOSYS; 161 return -1; 162 } 163 164 dp->bsize = bsize; 165 dp->softlimit = (uint64_t)D.dqb_bsoftlimit; 166 dp->hardlimit = (uint64_t)D.dqb_bhardlimit; 167 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit; 168 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit; 169 dp->curinodes = (uint64_t)D.dqb_curinodes; 170 dp->curblocks = (uint64_t)D.dqb_curblocks; 171 172 173 dp->qflags = qflags; 174 175 return ret; 176} 177 178/**************************************************************************** 179 Abstract out the quotactl_4A set calls. 180****************************************************************************/ 181int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) 182{ 183 int ret = -1; 184 uint32 qflags = 0; 185 uint32 oldqflags = 0; 186 struct dqblk D; 187 uint64_t bsize = (uint64_t)QUOTABLOCK_SIZE; 188 189 ZERO_STRUCT(D); 190 191 if (bsize == dp->bsize) { 192 D.dqb_bsoftlimit = dp->softlimit; 193 D.dqb_bhardlimit = dp->hardlimit; 194 D.dqb_ihardlimit = dp->ihardlimit; 195 D.dqb_isoftlimit = dp->isoftlimit; 196 } else { 197 D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize; 198 D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize; 199 D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize; 200 D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize; 201 } 202 203 qflags = dp->qflags; 204 205 switch (qtype) { 206 case SMB_USER_QUOTA_TYPE: 207 DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n", 208 path, bdev, (unsigned)id.uid)); 209 210 ret = quotactl(QCMD(Q_SETQLIM,USRQUOTA), (caddr_t)bdev, id.uid, (void *)&D); 211 break; 212#ifdef HAVE_GROUP_QUOTA 213 case SMB_GROUP_QUOTA_TYPE: 214 DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n", 215 path, bdev, (unsigned)id.gid)); 216 217 ret = quotactl(QCMD(Q_SETQLIM,GRPQUOTA), (caddr_t)bdev, id.gid, (void *)&D); 218 break; 219#endif /* HAVE_GROUP_QUOTA */ 220 case SMB_USER_FS_QUOTA_TYPE: 221 /* this stuff didn't work as it should: 222 * switching on/off quota via quotactl() 223 * didn't work! 224 * So we just return 0 225 * --metze 226 * 227 * On HPUX we didn't have the mount path, 228 * we need to fix sys_path_to_bdev() 229 * 230 */ 231 id.uid = getuid(); 232 DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n", 233 path, bdev, (unsigned)id.uid)); 234 235#if 0 236 ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), (caddr_t)bdev, id.uid, (void *)&D); 237 238 if ((qflags"AS_DENY_DISK)||(qflags"AS_ENABLED)) { 239 if (ret == 0) { 240 char *quota_file = NULL; 241 242 asprintf("a_file,"/%s/%s%s",path, QUOTAFILENAME,USERQUOTAFILE_EXTENSION); 243 if (quota_file == NULL) { 244 DEBUG(0,("asprintf() failed!\n")); 245 errno = ENOMEM; 246 return -1; 247 } 248 249 ret = quotactl(QCMD(Q_QUOTAON,USRQUOTA), (caddr_t)bdev, -1,(void *)quota_file); 250 } else { 251 ret = 0; 252 } 253 } else { 254 if (ret != 0) { 255 /* turn off */ 256 ret = quotactl(QCMD(Q_QUOTAOFF,USRQUOTA), (caddr_t)bdev, -1, (void *)0); 257 } else { 258 ret = 0; 259 } 260 } 261 262 DEBUG(0,("sys_set_vfs_quota: ret(%d) errno(%d)[%s] uid(%d) bdev[%s]\n", 263 ret,errno,strerror(errno),id.uid,bdev)); 264#else 265 if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), (caddr_t)bdev, id.uid, (void *)&D))==0) { 266 oldqflags |= QUOTAS_DENY_DISK; 267 } 268 269 if (oldqflags == qflags) { 270 ret = 0; 271 } else { 272 ret = -1; 273 } 274#endif 275 break; 276#ifdef HAVE_GROUP_QUOTA 277 case SMB_GROUP_FS_QUOTA_TYPE: 278 /* this stuff didn't work as it should: 279 * switching on/off quota via quotactl() 280 * didn't work! 281 * So we just return 0 282 * --metze 283 * 284 * On HPUX we didn't have the mount path, 285 * we need to fix sys_path_to_bdev() 286 * 287 */ 288 id.gid = getgid(); 289 DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n", 290 path, bdev, (unsigned)id.gid)); 291 292#if 0 293 ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id, (void *)&D); 294 295 if ((qflags"AS_DENY_DISK)||(qflags"AS_ENABLED)) { 296 if (ret == 0) { 297 char *quota_file = NULL; 298 299 asprintf("a_file,"/%s/%s%s",path, QUOTAFILENAME,GROUPQUOTAFILE_EXTENSION); 300 if (quota_file == NULL) { 301 DEBUG(0,("asprintf() failed!\n")); 302 errno = ENOMEM; 303 return -1; 304 } 305 306 ret = quotactl(QCMD(Q_QUOTAON,GRPQUOTA), (caddr_t)bdev, -1,(void *)quota_file); 307 } else { 308 ret = 0; 309 } 310 } else { 311 if (ret != 0) { 312 /* turn off */ 313 ret = quotactl(QCMD(Q_QUOTAOFF,GRPQUOTA), (caddr_t)bdev, -1, (void *)0); 314 } else { 315 ret = 0; 316 } 317 } 318 319 DEBUG(0,("sys_set_vfs_quota: ret(%d) errno(%d)[%s] uid(%d) bdev[%s]\n", 320 ret,errno,strerror(errno),id.gid,bdev)); 321#else 322 if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), (caddr_t)bdev, id.gid, (void *)&D))==0) { 323 oldqflags |= QUOTAS_DENY_DISK; 324 } 325 326 if (oldqflags == qflags) { 327 ret = 0; 328 } else { 329 ret = -1; 330 } 331#endif 332 break; 333#endif /* HAVE_GROUP_QUOTA */ 334 default: 335 errno = ENOSYS; 336 return -1; 337 } 338 339 return ret; 340} 341 342#else /* HAVE_QUOTACTL_4A */ 343 void dummy_sysquotas_4A(void); 344 345 void dummy_sysquotas_4A(void){} 346#endif /* HAVE_QUOTACTL_4A */ 347