source: trunk/libtransmission/platform-quota.c @ 14316

Last change on this file since 14316 was 14316, checked in by livings124, 8 years ago

Use built-in _WIN32 macro instead of WIN32

  • Property svn:keywords set to Date Rev Author Id
File size: 8.2 KB
Line 
1/*
2 * This file Copyright (C) 2013-2014 Mnemosyne LLC
3 *
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
6 *
7 * $Id: platform-quota.c 14316 2014-07-04 00:00:07Z livings124 $
8 */
9
10#include <errno.h>
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h> /* getuid() */
14#include <event2/util.h> /* evutil_ascii_strcasecmp () */
15
16#ifndef _WIN32
17 #include <sys/types.h> /* types needed by quota.h */
18 #if defined(__FreeBSD__) || defined(__OpenBSD__)
19  #include <ufs/ufs/quota.h> /* quotactl() */
20 #elif defined (__NetBSD__)
21  #include <sys/param.h>
22  #ifndef statfs
23   #define statfs statvfs
24  #endif
25 #elif defined (__sun)
26  #include <sys/fs/ufs_quota.h> /* quotactl */
27 #else
28  #include <sys/quota.h> /* quotactl() */
29 #endif
30 #ifdef HAVE_GETMNTENT
31  #ifdef __sun
32   #include <sys/types.h>
33   #include <sys/stat.h>
34   #include <fcntl.h>
35   #include <stdio.h>
36   #include <sys/mntent.h>
37   #include <sys/mnttab.h>
38   #define _PATH_MOUNTED MNTTAB
39  #else
40   #include <mntent.h>
41   #include <paths.h> /* _PATH_MOUNTED */
42  #endif
43 #else /* BSD derived systems */
44  #include <sys/param.h>
45  #include <sys/ucred.h>
46  #include <sys/mount.h>
47 #endif
48#endif
49
50#ifdef __APPLE__
51 #define HAVE_SYS_STATVFS_H
52 #define HAVE_STATVFS
53#endif
54
55#ifdef HAVE_SYS_STATVFS_H
56 #include <sys/statvfs.h>
57#endif
58
59#ifdef HAVE_XFS_XFS_H
60 #define HAVE_XQM
61 #include <xfs/xqm.h>
62#endif
63
64#include "transmission.h"
65#include "utils.h"
66#include "platform-quota.h"
67
68/***
69****
70***/
71
72#ifndef _WIN32
73static const char *
74getdev (const char * path)
75{
76#ifdef HAVE_GETMNTENT
77
78  FILE * fp;
79
80#ifdef __sun
81  struct mnttab mnt;
82  fp = fopen(_PATH_MOUNTED, "r");
83  if (fp == NULL)
84    return NULL;
85
86  while (getmntent(fp, &mnt))
87    if (!tr_strcmp0 (path, mnt.mnt_mountp))
88      break;
89  fclose(fp);
90  return mnt.mnt_special;
91#else
92  struct mntent * mnt;
93
94  fp = setmntent(_PATH_MOUNTED, "r");
95  if (fp == NULL)
96    return NULL;
97
98  while ((mnt = getmntent(fp)) != NULL)
99    if (!tr_strcmp0 (path, mnt->mnt_dir))
100      break;
101
102  endmntent(fp);
103  return mnt ? mnt->mnt_fsname : NULL;
104#endif
105#else /* BSD derived systems */
106
107  int i;
108  int n;
109  struct statfs * mnt;
110
111  n = getmntinfo(&mnt, MNT_WAIT);
112  if (!n)
113    return NULL;
114
115  for (i=0; i<n; i++)
116    if (!tr_strcmp0 (path, mnt[i].f_mntonname))
117      break;
118
119  return (i < n) ? mnt[i].f_mntfromname : NULL;
120
121#endif
122}
123
124static const char *
125getfstype (const char * device)
126{
127
128#ifdef HAVE_GETMNTENT
129
130  FILE * fp;
131#ifdef __sun
132  struct mnttab mnt;
133  fp = fopen(_PATH_MOUNTED, "r");
134  if (fp == NULL)
135    return NULL;
136  while (getmntent(fp, &mnt))
137    if (!tr_strcmp0 (device, mnt.mnt_mountp))
138      break;
139  fclose(fp);
140  return mnt.mnt_fstype;
141#else
142  struct mntent *mnt;
143
144  fp = setmntent (_PATH_MOUNTED, "r");
145  if (fp == NULL)
146    return NULL;
147
148  while ((mnt = getmntent (fp)) != NULL)
149    if (!tr_strcmp0 (device, mnt->mnt_fsname))
150      break;
151
152  endmntent(fp);
153  return mnt ? mnt->mnt_type : NULL;
154#endif
155#else /* BSD derived systems */
156
157  int i;
158  int n;
159  struct statfs *mnt;
160
161  n = getmntinfo(&mnt, MNT_WAIT);
162  if (!n)
163    return NULL;
164
165  for (i=0; i<n; i++)
166    if (!tr_strcmp0 (device, mnt[i].f_mntfromname))
167      break;
168
169  return (i < n) ? mnt[i].f_fstypename : NULL;
170
171#endif
172}
173
174static const char *
175getblkdev (const char * path)
176{
177  char * c;
178  char * dir;
179  const char * device;
180
181  dir = tr_strdup(path);
182
183  for (;;)
184    {
185      device = getdev (dir);
186      if (device != NULL)
187        break;
188
189      c = strrchr (dir, '/');
190      if (c != NULL)
191        *c = '\0';
192      else
193         break;
194    }
195
196  tr_free (dir);
197  return device;
198}
199
200#if defined(__NetBSD__) && (__NetBSD_Version__ >= 600000000)
201#include <quota.h>
202
203static int64_t
204getquota (const char * device)
205{
206  struct quotahandle *qh;
207  struct quotakey qk;
208  struct quotaval qv;
209  int64_t limit;
210  int64_t freespace;
211  int64_t spaceused;
212
213  qh = quota_open(device);
214  if (qh == NULL) {
215    return -1;
216  }
217  qk.qk_idtype = QUOTA_IDTYPE_USER;
218  qk.qk_id = getuid();
219  qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
220  if (quota_get(qh, &qk, &qv) == -1) {
221    quota_close(qh);
222    return -1;
223  }
224  if (qv.qv_softlimit > 0) {
225    limit = qv.qv_softlimit;
226  }
227  else if (qv.qv_hardlimit > 0) {
228    limit = qv.qv_hardlimit;
229  }
230  else {
231    quota_close(qh);
232    return -1;
233  }
234  spaceused = qv.qv_usage;
235  quota_close(qh);
236
237  freespace = limit - spaceused;
238  return (freespace < 0) ? 0 : freespace;
239}
240#else
241static int64_t
242getquota (const char * device)
243{
244  struct dqblk dq;
245  int64_t limit;
246  int64_t freespace;
247  int64_t spaceused;
248
249#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
250  if (quotactl(device, QCMD(Q_GETQUOTA, USRQUOTA), getuid(), (caddr_t) &dq) == 0)
251    {
252#elif defined(__sun)
253  struct quotctl  op; 
254  int fd = open(device, O_RDONLY); 
255  if (fd < 0) 
256    return -1; 
257  op.op = Q_GETQUOTA; 
258  op.uid = getuid(); 
259  op.addr = (caddr_t) &dq; 
260  if (ioctl(fd, Q_QUOTACTL, &op) == 0)
261    {
262      close(fd);
263#else
264  if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device, getuid(), (caddr_t) &dq) == 0)
265    {
266#endif
267      if (dq.dqb_bsoftlimit > 0)
268        {
269          /* Use soft limit first */
270          limit = dq.dqb_bsoftlimit;
271        }
272      else if (dq.dqb_bhardlimit > 0)
273        {
274          limit = dq.dqb_bhardlimit;
275        }
276      else
277        {
278          /* No quota enabled for this user */
279          return -1;
280        }
281#if defined(__FreeBSD__) || defined(__OpenBSD__)
282      spaceused = (int64_t) dq.dqb_curblocks >> 1;
283#elif defined(__APPLE__)
284      spaceused = (int64_t) dq.dqb_curbytes;
285#elif defined(__UCLIBC__)
286      spaceused = (int64_t) btodb(dq.dqb_curblocks);
287#elif defined(__sun) || (_LINUX_QUOTA_VERSION < 2)
288      spaceused = (int64_t) dq.dqb_curblocks >> 1;
289#else
290      spaceused = btodb(dq.dqb_curspace);
291#endif
292      freespace = limit - spaceused;
293#ifdef __APPLE__
294      return (freespace < 0) ? 0 : freespace;
295#else
296      return (freespace < 0) ? 0 : freespace * 1024;
297#endif
298    }
299#if defined(__sun)
300  close(fd);
301#endif
302  /* something went wrong */
303  return -1;
304}
305#endif
306
307#ifdef HAVE_XQM
308static int64_t
309getxfsquota (char * device)
310{
311  int64_t limit;
312  int64_t freespace;
313  struct fs_disk_quota dq;
314
315  if (quotactl(QCMD(Q_XGETQUOTA, USRQUOTA), device, getuid(), (caddr_t) &dq) == 0)
316    {
317      if (dq.d_blk_softlimit > 0)
318        {
319          /* Use soft limit first */
320          limit = dq.d_blk_softlimit >> 1;
321        }
322      else if (dq.d_blk_hardlimit > 0)
323        {
324          limit = dq.d_blk_hardlimit >> 1;
325        }
326      else
327        {
328          /* No quota enabled for this user */
329          return -1;
330        }
331
332      freespace = limit - (dq.d_bcount >> 1);
333      return (freespace < 0) ? 0 : freespace * 1024;
334    }
335
336  /* something went wrong */
337  return -1;
338}
339#endif /* HAVE_XQM */
340#endif /* _WIN32 */
341
342static int64_t
343tr_getQuotaFreeSpace (const struct tr_device_info * info)
344{
345  int64_t ret = -1;
346
347#ifndef _WIN32
348
349  if (info->fstype && !evutil_ascii_strcasecmp(info->fstype, "xfs"))
350    {
351#ifdef HAVE_XQM
352      ret = getxfsquota (info->device);
353#endif
354    }
355  else
356    {
357      ret = getquota (info->device);
358    }
359#endif /* _WIN32 */
360
361  return ret;
362}
363
364static int64_t
365tr_getDiskFreeSpace (const char * path)
366{
367#ifdef _WIN32
368
369  uint64_t freeBytesAvailable = 0;
370  return GetDiskFreeSpaceEx (path, &freeBytesAvailable, NULL, NULL)
371    ? (int64_t)freeBytesAvailable
372    : -1;
373
374#elif defined(HAVE_STATVFS)
375
376  struct statvfs buf;
377  return statvfs(path, &buf) ? -1 : (int64_t)buf.f_bavail * (int64_t)buf.f_frsize;
378
379#else
380
381  #warning FIXME: not implemented
382  return -1;
383
384#endif
385}
386
387struct tr_device_info *
388tr_device_info_create (const char * path)
389{
390  struct tr_device_info * info;
391
392  info = tr_new0 (struct tr_device_info, 1);
393  info->path = tr_strdup (path);
394#ifndef _WIN32
395  info->device = tr_strdup (getblkdev (path));
396  info->fstype = tr_strdup (getfstype (path));
397#endif
398
399  return info;
400}
401
402void
403tr_device_info_free (struct tr_device_info * info)
404{
405  if (info != NULL)
406    {
407      tr_free (info->fstype);
408      tr_free (info->device);
409      tr_free (info->path);
410      tr_free (info);
411    }
412}
413
414int64_t
415tr_device_info_get_free_space (const struct tr_device_info * info)
416{
417  int64_t free_space;
418
419  if ((info == NULL) || (info->path == NULL))
420    {
421      errno = EINVAL;
422      free_space = -1;
423    }
424  else
425    {
426      free_space = tr_getQuotaFreeSpace (info);
427
428      if (free_space < 0)
429        free_space = tr_getDiskFreeSpace (info->path);
430    }
431
432  return free_space;
433}
434
435/***
436****
437***/
Note: See TracBrowser for help on using the repository browser.