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

Last change on this file since 14370 was 14370, checked in by mikedld, 8 years ago

Fix a couple of ordinary and pedantic warnings

Add previously missing -Wall to warning flags in CMake. Remove -Wformat
and -Wvariadic-macros (enabled by default; latter is not meaningful in
C99 mode we use), -Wdeclaration-after-statement (again, not needed as
we use C99). Move -Wmissing-declarations to C-only flags (GCC man says
so).

Add copyrights year to crypto-utils-fallback.c.

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