"Fossies" - the Fresh Open Source Software Archive

Member "quotactl-1.00/quotause/quotarept.c" (29 Sep 2005, 16799 Bytes) of package /linux/privat/old/quotactl-1.00.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "quotarept.c" see the Fossies "Dox" file reference documentation.

    1 #define _GNU_SOURCE
    2 
    3 #include <stdbool.h>
    4 #include <assert.h>
    5 #include <stdio.h>
    6 #include <string.h>
    7 #include <unistd.h>
    8 #include <stdlib.h>
    9 #include <errno.h>
   10 #include <time.h>
   11 #include <pwd.h>
   12 #include <grp.h>
   13 
   14 #include <sys/types.h>
   15 
   16 #include <giraffe/girtypes.h>
   17 #include <giraffe/fatal.h>
   18 #include <giraffe/girstring.h>
   19 #include <giraffe/mallocvar.h>
   20 #include <giraffe/cmdline_parser.h>
   21 
   22 #include "quotaio.h"
   23 #include "misc.h"
   24 
   25 
   26 struct cmdlineInfo {
   27     const char * quotaFileName;
   28 };
   29 
   30 
   31 static void
   32 parseCommandLine(int                  const argc,
   33                  char **              const argv,
   34                  struct cmdlineInfo * const cmdlineP,
   35                  const char **        const errorP) {
   36 
   37     cmdlineParser const cp = cmd_createOptionParser();
   38 
   39     const char * error;
   40 
   41     *errorP = NULL;
   42 
   43     cmd_processOptions(cp, argc, argv, &error);
   44 
   45     if (error) {
   46         casprintf(errorP, "Command syntax error.  %s", error);
   47         strfree(error);
   48     } else {
   49         if (cmd_argumentCount(cp) < 1)
   50             casprintf(errorP, "You must specify an argument: the name "
   51                       "of the quota file.");
   52         else {
   53             cmdlineP->quotaFileName = cmd_getArgument(cp, 0);
   54             if (cmd_argumentCount(cp) > 2)
   55                 casprintf(errorP,
   56                           "Extra arguments.  There is only 1 argument.  "
   57                           "You specified %u", cmd_argumentCount(cp));
   58         }
   59     }
   60     cmd_destroyOptionParser(cp);
   61 }
   62 
   63 
   64 
   65 static void
   66 freeCmdline(struct cmdlineInfo const cmdline) {
   67 
   68     strfree(cmdline.quotaFileName);
   69 }
   70 
   71 
   72 
   73 #define FL_USER 1
   74 #define FL_GROUP 2
   75 #define FL_VERBOSE 4
   76 #define FL_ALL 8        /* Dump quota files on all filesystems */
   77 #define FL_TRUNCNAMES 16    /* Truncate names to fit into the screen */
   78 #define FL_SHORTNUMS 32 /* Try to print space in appropriate units */
   79 #define FL_NONAME 64    /* Don't translate ids to names */
   80 #define FL_NOCACHE 128  /* Don't cache dquots before resolving */
   81 #define FL_NOAUTOFS 256 /* Ignore autofs mountpoints */
   82 
   83 enum rounding {ROUND_NO, ROUND_YES};
   84 
   85 static struct {
   86     /* A buffer for dquots that need to be printed out, but we're not
   87        ready to print them yet.
   88     */
   89     uint count;
   90     struct dquot dquot[1024];
   91 } dquotBuffer;
   92 
   93 /*
   94  *  Convert number to some nice short form for printing
   95  */
   96 static void
   97 number2str(unsigned long long const num,
   98            const char **      const stringP,
   99            int                const format) {
  100 
  101     char const suffix[8] = " kmgt";
  102 
  103     if (format) {
  104         int i;
  105         unsigned long long div;
  106     
  107         for (i = 4, div = 1000000000000LL; i > 0; i--, div /= 1000)
  108             if (num >= 100*div) {
  109                 casprintf(stringP, "%Lu%c", (num+div-1) / div, suffix[i]);
  110                 return;
  111             }
  112     }
  113     casprintf(stringP, "%Lu", num);
  114 }
  115 
  116 
  117 
  118 /*
  119  *  Convert uid to name
  120  */
  121 static void
  122 uid2user(uid_t         const id,
  123          const char ** const userP) {
  124 
  125     struct passwd *entry;
  126 
  127     entry = getpwuid(id);
  128 
  129     if (!entry)
  130         casprintf(userP, "#%u", (uint) id);
  131     else
  132         *userP = strdup(entry->pw_name);
  133 }
  134 
  135 
  136 
  137 /*
  138  *  Convert gid to name
  139  */
  140 static void
  141 gid2group(gid_t         const id,
  142           const char ** const groupP) {
  143 
  144     struct group *entry;
  145 
  146     entry = getgrgid(id);
  147 
  148     if (!entry)
  149         casprintf(groupP,"#%u", (uint) id);
  150     else
  151         *groupP = strdup(entry->gr_name);
  152 }
  153 
  154 
  155 
  156 /*
  157  *  Convert id to user/groupname
  158  */
  159 static void
  160 id2name(int           const id,
  161         int           const qtype,
  162         const char ** const nameP) {
  163 
  164     if (qtype == USRQUOTA)
  165         uid2user(id, nameP);
  166     else
  167         gid2group(id, nameP);
  168 }
  169 
  170 
  171 
  172 static void
  173 time2str(time_t        const time,
  174          const char ** const timeStringP,
  175          enum rounding const rounding) {
  176 
  177     if (rounding == ROUND_YES) {
  178         uint minutes, hours, days;
  179         
  180         minutes = (time + 30) / 60;  /* Rounding */
  181         hours = minutes / 60;
  182         minutes %= 60;
  183         days = hours / 24;
  184         hours %= 24;
  185         if (days >= 2)
  186             casprintf(timeStringP, "%ddays", days);
  187         else
  188             casprintf(timeStringP, "%02d:%02d", hours + days * 24, minutes);
  189     } else {
  190         uint seconds, minutes, hours, days;
  191 
  192         minutes = time / 60;
  193         seconds = time % 60;
  194         hours = minutes / 60;
  195         minutes %= 60;
  196         days = hours / 24;
  197         hours %= 24;
  198         if (seconds || (!minutes && !hours && !days))
  199             casprintf(timeStringP, "%useconds",
  200                       (uint)(seconds+minutes*60+hours*3600+days*3600*24));
  201         else if (minutes)
  202             casprintf(timeStringP, "%uminutes",
  203                      (uint)(minutes+hours*60+days*60*24));
  204         else if (hours)
  205             casprintf(timeStringP, "%uhours",
  206                       (uint)(hours+days*24));
  207         else
  208             casprintf(timeStringP, "%udays", days);
  209     }
  210 }
  211 
  212 
  213 
  214 /*
  215  * Convert time difference of seconds and current time
  216  */
  217 static void
  218 difftime2str(time_t        const timeArg,
  219              const char ** const timeStringP) {
  220 
  221     if (timeArg == 0)
  222         *timeStringP = strdup("");
  223     else { 
  224         time_t now;
  225         
  226         time(&now);
  227         if (timeArg <= now)
  228             *timeStringP = strdup("none");
  229         else
  230             time2str(timeArg - now, timeStringP, ROUND_YES);
  231     }
  232 }
  233 
  234 
  235 
  236 /*
  237  * Convert number in quota blocks to some nice short form for printing
  238  */
  239 static void
  240 space2str(qsize_t       const space,
  241           const char ** const spaceStringP,
  242           int           const format) {
  243 
  244     char const suffix[8] = " MGT";
  245     qsize_t spaceKb;
  246 
  247     spaceKb = qb2kb(space);
  248     if (format) {
  249         int i;
  250         for (i = 3; i > 0; i--)
  251             if (spaceKb >= (1ULL << (QUOTABLOCK_BITS * i)) * 100) {
  252                 casprintf(spaceStringP, "%Lu%c",
  253                           (spaceKb +
  254                            (1 << (QUOTABLOCK_BITS*i))-1)
  255                           >> (QUOTABLOCK_BITS*i), suffix[i]);
  256                 return;
  257             }
  258     }
  259     casprintf(spaceStringP, "%Lu", spaceKb);
  260 }
  261 
  262 
  263 
  264 /* Are we over soft or hard limit? */
  265 static char
  266 overlim(uint const usage,
  267         uint const softlim,
  268         uint const hardlim) {
  269 
  270     if ((usage > softlim && softlim) || (usage > hardlim && hardlim))
  271         return '+';
  272     else
  273         return '-';
  274 }
  275 
  276 
  277 
  278 #define PRINTNAMELEN 9
  279     /* Number of characters to be reserved for name on screen */
  280 
  281 /* Print one quota entry */
  282 static void
  283 print(struct dquot * const dquot,
  284       const char *   const name,
  285       uint           const flags) {
  286 
  287     const char * pname;
  288     const char * blockGrace;
  289     const char * inodeGrace;
  290     struct {
  291         const char * current;
  292         const char * soft;
  293         const char * hard;
  294     } blockQuota;
  295     struct {
  296         const char * current;
  297         const char * soft;
  298         const char * hard;
  299     } inodeQuota;
  300     
  301     struct util_dqblk * const entry = &dquot->dq_dqb;
  302 
  303     if (flags & FL_TRUNCNAMES)
  304         casprintf(&pname, "%.*s", PRINTNAMELEN, name);
  305     else
  306         pname = strdup(name);
  307 
  308     if (entry->dqb_bsoftlimit && toqb(entry->dqb_curspace) >=
  309         entry->dqb_bsoftlimit)
  310         difftime2str(entry->dqb_btime, &blockGrace);
  311     else
  312         blockGrace = strdup("");
  313 
  314     space2str(toqb(entry->dqb_curspace), &blockQuota.current,
  315               flags & FL_SHORTNUMS);
  316     space2str(entry->dqb_bsoftlimit,     &blockQuota.soft,
  317               flags & FL_SHORTNUMS);
  318     space2str(entry->dqb_bhardlimit,     &blockQuota.hard,
  319               flags & FL_SHORTNUMS);
  320 
  321     if (entry->dqb_isoftlimit && entry->dqb_curinodes >= entry->dqb_isoftlimit)
  322         difftime2str(entry->dqb_itime, &inodeGrace);
  323     else
  324         inodeGrace = strdup("");
  325 
  326     number2str(entry->dqb_curinodes,  &inodeQuota.current,
  327                flags & FL_SHORTNUMS);
  328     number2str(entry->dqb_isoftlimit, &inodeQuota.soft,
  329                flags & FL_SHORTNUMS);
  330     number2str(entry->dqb_ihardlimit, &inodeQuota.hard,
  331                flags & FL_SHORTNUMS);
  332 
  333     printf("%-9s %c%c %7s %7s %7s %6s %7s %5s %5s %6s\n",
  334            pname,
  335            overlim(qb2kb(toqb(entry->dqb_curspace)),
  336                    qb2kb(entry->dqb_bsoftlimit),
  337                    qb2kb(entry->dqb_bhardlimit)),
  338            overlim(entry->dqb_curinodes,
  339                    entry->dqb_isoftlimit,
  340                    entry->dqb_ihardlimit),
  341            blockQuota.current, blockQuota.soft, blockQuota.hard, blockGrace,
  342            inodeQuota.current, inodeQuota.soft, inodeQuota.hard, inodeGrace
  343         );
  344     
  345     strfree(inodeQuota.current);
  346     strfree(inodeQuota.soft);
  347     strfree(inodeQuota.hard);
  348     strfree(inodeGrace);
  349     strfree(blockQuota.current);
  350     strfree(blockQuota.soft);
  351     strfree(blockQuota.hard);
  352     strfree(blockGrace);
  353 
  354     strfree(pname);
  355 }
  356 
  357 
  358 
  359 
  360 static void
  361 printBufferedDquotsUser(uint const printFlags) {
  362 /*----------------------------------------------------------------------------
  363    Print all the buffered quota records that are for users that are in the
  364    user database ("passwd file").
  365 
  366    Mark each one as printed, so Caller can tell which ones remain (because
  367    they don't match any user in the user database).
  368 -----------------------------------------------------------------------------*/
  369     struct passwd * pwent;
  370 
  371     setpwent();
  372     while ((pwent = getpwent())) {
  373         unsigned int i;
  374         struct dquot * dquotP;
  375         
  376         for (i = 0;
  377              i < dquotBuffer.count &&
  378                  pwent->pw_uid != dquotBuffer.dquot[i].dq_id;
  379              ++i);
  380         dquotP = &dquotBuffer.dquot[i];
  381 
  382         if (i < dquotBuffer.count && !(dquotP->dq_flags & DQ_PRINTED)) {
  383             print(dquotP, pwent->pw_name, printFlags);
  384             dquotP->dq_flags |= DQ_PRINTED;
  385         }
  386     }
  387     endpwent();
  388 }
  389 
  390 
  391 
  392 static void
  393 printBufferedDquotsGroup(uint const printFlags) {
  394 /*----------------------------------------------------------------------------
  395    Print all the buffered quota records that are for groups that are in the
  396    group database ("group file").
  397 
  398    Mark each on as printed, so Caller can tell which ones remain (because
  399    they don't match any user in the group database).
  400 -----------------------------------------------------------------------------*/
  401     struct group * grent;
  402     
  403     setgrent();
  404     while ((grent = getgrent())) {
  405         unsigned int i;
  406         struct dquot * dquotP;
  407         
  408         for (i = 0;
  409              i < dquotBuffer.count &&
  410                  grent->gr_gid != dquotBuffer.dquot[i].dq_id;
  411              ++i);
  412 
  413         dquotP = &dquotBuffer.dquot[i];
  414 
  415         if (i < dquotBuffer.count &&
  416             !(dquotP->dq_flags & DQ_PRINTED)) {
  417             print(dquotP, grent->gr_name, printFlags);
  418             dquotP->dq_flags |= DQ_PRINTED;
  419         }
  420     }
  421     endgrent();
  422 }
  423 
  424 
  425 
  426 static void
  427 printBufferedDquotsUnnamed(uint const printFlags) {
  428 /*----------------------------------------------------------------------------
  429   Print all buffered quota records that haven't yet been printed.
  430 
  431   Don't try to attach user or group names to them.
  432 -----------------------------------------------------------------------------*/
  433     unsigned int i;
  434     
  435     for (i = 0; i < dquotBuffer.count; ++i) {
  436         struct dquot * const dquotP = &dquotBuffer.dquot[i];
  437         if (!(dquotP->dq_flags & DQ_PRINTED)) {
  438             const char * name;
  439             casprintf(&name, "#%u", dquotP->dq_id);
  440             print(dquotP, name, printFlags);
  441             strfree(name);
  442             dquotP->dq_flags |= DQ_PRINTED;
  443         }
  444     }
  445 }
  446 
  447 
  448 
  449 static void
  450 printBufferedDquots(int  const type,
  451                     uint const printFlags) {
  452 /*----------------------------------------------------------------------------
  453    Print all quota records that are in the buffer 'dquotBuffer'.
  454 
  455    Then empty the buffer.
  456 -----------------------------------------------------------------------------*/
  457     switch (type) {
  458     case USRQUOTA:
  459         printBufferedDquotsUser(printFlags);
  460         break;
  461     case GRPQUOTA:
  462         printBufferedDquotsGroup(printFlags);
  463     break;
  464     default:
  465         /* There are no other cases */
  466         assert(false);
  467     }
  468 
  469     printBufferedDquotsUnnamed(printFlags);
  470 }
  471 
  472 
  473 
  474 /* These are global variables that we sleazily pass under the table
  475    to output().  We should fix this.
  476 */
  477 static uint printFlags;
  478 static uint quotaType;
  479 
  480 static int
  481 output(struct dquot * const dquotP,
  482        const char *   const name) {
  483 /*----------------------------------------------------------------------------
  484    Print the information from quota record *dquotP.
  485 
  486    BUT: if we're to translate IDs to names (e.g. uid to username), and
  487    we're to do it in batches, then instead of printing the information,
  488    add it to the dquot buffer 'dquotBuffer' so someone else can do it
  489    later, in a more efficient batch.
  490 
  491    If that fills up the quota buffer, print out the contents of the buffer
  492    and empty it.
  493 
  494    This is a callback routine for scan_dquots().
  495 -----------------------------------------------------------------------------*/
  496     if (printFlags & FL_NONAME) {    /* We should translate names? */
  497         const char * nameDisp;
  498 
  499         casprintf(&nameDisp, "#%u", dquotP->dq_id);
  500         print(dquotP, nameDisp, printFlags);
  501         strfree(nameDisp);
  502     } else if (name || printFlags & FL_NOCACHE) {
  503         /* We shouldn't do batched id->name translations? */
  504         if (name)
  505             print(dquotP, name, printFlags);
  506         else {
  507             const char * nameDisp;
  508             
  509             id2name(dquotP->dq_id, quotaType, &nameDisp);
  510             print(dquotP, nameDisp, printFlags);
  511             strfree(nameDisp);
  512         }
  513     } else {
  514         /* Instead of printing it now, put it in the buffer so someone can
  515            print it later and batch up multiple name translations for
  516            efficiency.
  517         */
  518         memcpy(&dquotBuffer.dquot[dquotBuffer.count++], dquotP,
  519                sizeof(*dquotP));
  520         if (dquotBuffer.count >= ARRAY_SIZE(dquotBuffer.dquot)) {
  521             printBufferedDquots(quotaType, printFlags);
  522             dquotBuffer.count = 0;
  523         }
  524     }
  525     return 0;
  526 }
  527 
  528 
  529 
  530 static void
  531 report(const char *  const qfname,
  532        int           const type,
  533        int           const fmt,
  534        const char ** const errorP) {
  535 
  536     struct quota_handle * quotaFileP;
  537     const char * bgstring;
  538     const char * igstring;
  539     const char * error;
  540 
  541     new_io(OPEN_READ, qfname, type, fmt, &quotaFileP, &error);
  542     if (error) {
  543         casprintf(errorP, "Unable to initiate access to quota file.  %s",
  544                   error);
  545         strfree(error);
  546     } else {
  547         int rc;
  548 
  549         *errorP = NULL;
  550 
  551         printf("Report for %s quotas\n", type2name(type));
  552         printf("Quota file is of type %s\n", fmtnames[quotaFileP->qh_fmt]);
  553         printf("\n");
  554 
  555         time2str(quotaFileP->qh_info.dqi_bgrace, &bgstring, ROUND_YES);
  556         time2str(quotaFileP->qh_info.dqi_igrace, &igstring, ROUND_YES);
  557         printf("Block grace time: %s; Inode grace time: %s\n",
  558                bgstring, igstring);
  559         
  560         strfree(bgstring);
  561         strfree(igstring);
  562         
  563         printf("                        "
  564                "Block limits                File limits\n");
  565         printf("%-9s ** %7s %7s %7s %6s %7s %5s %5s %6s\n",
  566                (type == USRQUOTA)? "User" : "Group",
  567                "used", "soft", "hard", "grace",
  568                "used", "soft", "hard", "grace");
  569         printf("-------------------------------------"
  570                "---------------------------------\n");
  571 
  572         dquotBuffer.count = 0;  /* Start with empty buffer */
  573         printFlags = 0;
  574         quotaType = quotaFileP->qh_type;
  575         
  576         setpwent();
  577         /* There's something screwed up so that if you move the 1st setpwent()
  578            after the scan_dquots, it crashes.  Apparently a memory management
  579            problem.  Must fix this.
  580         */
  581         rc =  quotaFileP->qh_ops->scan_dquots(quotaFileP, output);
  582 
  583         if (rc < 0)
  584             printf("Failed to gather the individual quotas\n");
  585         else {
  586             printBufferedDquots(type, printFlags);
  587             if (quotaFileP->qh_ops->report) {
  588                 putchar('\n');
  589                 quotaFileP->qh_ops->report(quotaFileP,
  590                                            !!(printFlags & FL_VERBOSE));
  591                 putchar('\n');
  592             }
  593         }
  594     }
  595 }
  596 
  597 
  598 
  599 int
  600 main(int argc, char **argv) {
  601 
  602     enum quotaFileFmt const fmt = QF_VFSV0;
  603 
  604     struct cmdlineInfo cmdline;
  605     const char * error;
  606     int retval;
  607 
  608     parseCommandLine(argc, argv, &cmdline, &error);
  609     if (error)
  610         fatal("Invalid options/arguments.  %s", error);
  611 
  612     report(cmdline.quotaFileName, USRQUOTA, fmt, &error);
  613 
  614     freeCmdline(cmdline);
  615 
  616     if (error) {
  617         fprintf(stderr, "Failed.  %s\n", error);
  618         strfree(error);
  619         retval = 1;
  620     } else
  621         retval = 0;
  622 
  623     return retval;
  624 }