github.com/schwarzm/garden-linux@v0.0.0-20150507151835-33bca2147c47/old/linux_backend/src/repquota/repquota.c (about)

     1  #include <assert.h>
     2  #include <errno.h>
     3  #include <fstab.h>
     4  #include <inttypes.h>
     5  #include <malloc.h>
     6  #include <mntent.h>
     7  #include <stdio.h>
     8  #include <stdlib.h>
     9  #include <string.h>
    10  #include <sys/quota.h>
    11  
    12  /**
    13   * Attempts to look up the device name associated with supplied mount point.
    14   *
    15   * @param dir      Mount point to look up
    16   * @param dev_name Where to place the device name. Caller must free.
    17   *
    18   * @return         0 on success
    19   *                -1 mount point not found
    20   *                -2 cannot open mtab
    21   */
    22  static int lookup_device(const char* dir, char** dev_name) {
    23    FILE* mtab                = NULL;
    24    struct mntent* mtab_entry = NULL;
    25    size_t fsname_len         = 0;
    26    int retval                = -1;
    27  
    28    assert(NULL != dir);
    29    assert(NULL != dev_name);
    30  
    31    if (NULL == (mtab = setmntent(_PATH_MOUNTED, "r"))) {
    32      return -2;
    33    }
    34  
    35    while (NULL != (mtab_entry = getmntent(mtab))) {
    36      if (!strcmp(mtab_entry->mnt_dir, dir)) {
    37        fsname_len = strlen(mtab_entry->mnt_fsname) + 1;
    38  
    39        *dev_name = malloc(fsname_len);
    40        assert(NULL != *dev_name);
    41  
    42        strncpy(*dev_name, mtab_entry->mnt_fsname, fsname_len);
    43        retval = 0;
    44        break;
    45      }
    46    }
    47  
    48    endmntent(mtab);
    49  
    50    return retval;
    51  }
    52  
    53  /**
    54   * Attempts to print a helpful error message to stderr.
    55   *
    56   * @param msg Error message to prepend.
    57   */
    58  static void print_quotactl_error(const char* msg) {
    59    assert(NULL != msg);
    60  
    61    switch (errno) {
    62      case EFAULT:
    63        fprintf(stderr, "%s: Block device invalid.\n", msg);
    64        break;
    65  
    66      case ENOENT:
    67        fprintf(stderr, "%s: Block device doesn't exist.\n", msg);
    68        break;
    69  
    70      case ENOSYS:
    71        fprintf(stderr, "%s: Kernel doesn't haven quota support.\n", msg);
    72        break;
    73  
    74      case ENOTBLK:
    75        fprintf(stderr, "%s: Not a block device.\n", msg);
    76        break;
    77  
    78      case EPERM:
    79        fprintf(stderr, "%s: Insufficient privilege.\n", msg);
    80        break;
    81  
    82      case ESRCH:
    83        fprintf(stderr, "%s: No quota for supplied user.\n", msg);
    84        break;
    85  
    86      default:
    87        perror(msg);
    88        break;
    89    }
    90  }
    91  
    92  /**
    93   * Prints relevant quota information to stdout for the supplied uid.
    94   * On failure, will attempt to print a helpful error messge to stderr.
    95   *
    96   * @param filesystem  Filesystem to report quota information for
    97   * @param uid         Uid to report quota information for
    98   *
    99   * @return            -1 on error, 0 otherwise
   100   */
   101  static int print_quota_usage(const char* filesystem, int uid) {
   102    assert(NULL != filesystem);
   103  
   104    char emsg[1024];
   105    struct dqblk quota_info;
   106  
   107    memset(&quota_info, 0, sizeof(quota_info));
   108  
   109    if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), filesystem, uid, (caddr_t) &quota_info) < 0) {
   110      sprintf(emsg, "Failed retrieving quota for uid=%d", uid);
   111      print_quotactl_error(emsg);
   112      return -1;
   113    }
   114  
   115    printf("%d ", uid);
   116  
   117    /* Block info */
   118    printf("%llu %llu %llu %llu ",
   119           (long long unsigned int) quota_info.dqb_curspace,
   120           (long long unsigned int) quota_info.dqb_bsoftlimit,
   121           (long long unsigned int) quota_info.dqb_bhardlimit,
   122           (long long unsigned int) quota_info.dqb_btime);
   123  
   124    /* Inode info */
   125    printf("%llu %llu %llu %llu\n",
   126           (long long unsigned int) quota_info.dqb_curinodes,
   127           (long long unsigned int) quota_info.dqb_isoftlimit,
   128           (long long unsigned int) quota_info.dqb_ihardlimit,
   129           (long long unsigned int) quota_info.dqb_itime);
   130  
   131    return 0;
   132  }
   133  
   134  int main(int argc, char* argv[]) {
   135    char* filesystem  = NULL;
   136    char* device_name = NULL;
   137    char** uid_strs   = NULL;
   138    int* uids         = NULL;
   139    int num_uids      = 0;
   140    int ii            = 0;
   141  
   142    if (argc < 3) {
   143      printf("Usage: report_quota [filesystem] [uid]+\n");
   144      printf("Reports quota information for the supplied uids on the given filesystem\n");
   145      printf("Format is: <uid> <bytes used> <soft> <hard> <grace> <inodes used> <soft> <hard> <grace>\n");
   146      exit(1);
   147    }
   148  
   149    filesystem = argv[1];
   150    num_uids   = argc - 2;
   151    uid_strs   = argv + 2;
   152  
   153    if (lookup_device(filesystem, &device_name) < 0) {
   154      printf("Couldn't find device for %s\n", argv[1]);
   155      exit(1);
   156    }
   157  
   158    uids = malloc(sizeof(*uids) * num_uids);
   159    assert(NULL != uids);
   160  
   161    memset(uids, 0, sizeof(*uids) * num_uids);
   162    for (ii = 0; ii < num_uids; ii++) {
   163      uids[ii] = atoi(uid_strs[ii]);
   164    }
   165  
   166    for (ii = 0; ii < num_uids; ii++) {
   167      if (print_quota_usage(device_name, uids[ii]) < 0) {
   168        exit(1);
   169      }
   170    }
   171  
   172    /* Pedantry! */
   173    free(device_name);
   174    free(uids);
   175  
   176    return 0;
   177  }