home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2083 / groupio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  9.7 KB  |  539 lines

  1. /*
  2.  * Copyright 1990, John F. Haugh II
  3.  * An unpublished work.
  4.  * All rights reserved.
  5.  *
  6.  * Use, duplication, and disclosure prohibited without
  7.  * the express written permission of the author.
  8.  *
  9.  *    This file implements a transaction oriented group database
  10.  *    library.  The group file is updated one entry at a time.
  11.  *    After each transaction the file must be logically closed and
  12.  *    transferred to the existing group file.  The sequence of
  13.  *    events is
  14.  *
  15.  *    gr_lock                -- lock group file
  16.  *    gr_open                -- logically open group file
  17.  *    while transaction to process
  18.  *        gr_(locate,update,remove) -- perform transaction
  19.  *    done
  20.  *    gr_close            -- commit transactions
  21.  *    gr_unlock            -- remove group lock
  22.  */
  23.  
  24. #include <sys/stat.h>
  25. #include <fcntl.h>
  26. #include <errno.h>
  27. #include <grp.h>
  28. #include <stdio.h>
  29.  
  30. #ifndef    lint
  31. static    char    sccsid[] = "@(#)groupio.c    3.2 22:14:38 11/16/90";
  32. #endif
  33.  
  34. static    int    islocked;
  35. static    int    isopen;
  36. static    int    open_modes;
  37. static    FILE    *grfp;
  38.  
  39. struct    gr_file_entry {
  40.     char    *grf_line;
  41.     int    grf_changed;
  42.     struct    group    *grf_entry;
  43.     struct    gr_file_entry *grf_next;
  44. };
  45.  
  46. static    struct    gr_file_entry    *grf_head;
  47. static    struct    gr_file_entry    *grf_tail;
  48. static    struct    gr_file_entry    *grf_cursor;
  49. static    int    gr_changed;
  50.  
  51. #define    GR_LOCK    "/etc/group.lock"
  52. #define    GR_TEMP "/etc/grp.%d"
  53. #define    GROUP    "/etc/group"
  54. #define    OGROUP    "/etc/group-"
  55.  
  56. extern    char    *strdup();
  57. extern    struct    group    *sgetgrent();
  58.  
  59. /*
  60.  * gr_dup - duplicate a group file entry
  61.  *
  62.  *    gr_dup() accepts a pointer to a group file entry and
  63.  *    returns a pointer to a group file entry in allocated
  64.  *    memory.
  65.  */
  66.  
  67. static struct group *
  68. gr_dup (grent)
  69. struct    group    *grent;
  70. {
  71.     struct    group    *gr;
  72.     int    i;
  73.  
  74.     if (! (gr = (struct group *) malloc (sizeof *gr)))
  75.         return 0;
  76.  
  77.     if ((gr->gr_name = strdup (grent->gr_name)) == 0 ||
  78.             (gr->gr_passwd = strdup (grent->gr_passwd)) == 0)
  79.         return 0;
  80.  
  81.     for (i = 0;grent->gr_mem[i];i++)
  82.         ;
  83.  
  84.     gr->gr_mem = (char **) malloc (sizeof (char *) * (i + 1));
  85.     for (i = 0;grent->gr_mem[i];i++)
  86.         if (! (gr->gr_mem[i] = strdup (grent->gr_mem[i])))
  87.             return 0;
  88.  
  89.     gr->gr_mem[i] = 0;
  90.     gr->gr_gid = grent->gr_gid;
  91.  
  92.     return gr;
  93. }
  94.  
  95. /*
  96.  * gr_free - free a dynamically allocated group file entry
  97.  *
  98.  *    gr_free() frees up the memory which was allocated for the
  99.  *    pointed to entry.
  100.  */
  101.  
  102. static void
  103. gr_free (grent)
  104. struct    group    *grent;
  105. {
  106.     int    i;
  107.  
  108.     free (grent->gr_name);
  109.     free (grent->gr_passwd);
  110.  
  111.     for (i = 0;grent->gr_mem[i];i++)
  112.         free (grent->gr_mem[i]);
  113.  
  114.     free (grent->gr_mem);
  115. }
  116.  
  117. /*
  118.  * gr_lock - lock a group file
  119.  *
  120.  *    gr_lock() encapsulates the lock operation.  it returns
  121.  *    TRUE or FALSE depending on the group file being
  122.  *    properly locked.  the lock is set by creating a semaphore
  123.  *    file, GR_LOCK.
  124.  */
  125.  
  126. int
  127. gr_lock ()
  128. {
  129.     int    fd;
  130.     int    pid;
  131.     int    len;
  132.     char    file[BUFSIZ];
  133.     char    buf[32];
  134.     struct    stat    sb;
  135.  
  136.     if (islocked)
  137.         return 1;
  138.  
  139.     /*
  140.      * Create a lock file which can be switched into place
  141.      */
  142.  
  143.     sprintf (file, GR_TEMP, getpid ());
  144.     if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
  145.         return 0;
  146.  
  147.     sprintf (buf, "%d", getpid ());
  148.     if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
  149.         (void) close (fd);
  150.         (void) unlink (file);
  151.         return 0;
  152.     }
  153.     close (fd);
  154.  
  155.     /*
  156.      * Simple case first -
  157.      *    Link fails (in a sane environment ...) if the target
  158.      *    exists already.  So we try to switch in a new lock
  159.      *    file.  If that succeeds, we assume we have the only
  160.      *    valid lock.  Needs work for NFS where this assumption
  161.      *    may not hold.  The simple hack is to check the link
  162.      *    count on the source file, which should be 2 iff the
  163.      *    link =really= worked.
  164.      */
  165.  
  166.     if (link (file, GR_LOCK) == 0) {
  167.         if (stat (file, &sb) != 0)
  168.             return 0;
  169.  
  170.         if (sb.st_nlink != 2)
  171.             return 0;
  172.  
  173.         (void) unlink (file);
  174.         islocked = 1;
  175.         return 1;
  176.     }
  177.  
  178.     /*
  179.      * Invalid lock test -
  180.      *    Open the lock file and see if the lock is valid.
  181.      *    The PID of the lock file is checked, and if the PID
  182.      *    is not valid, the lock file is removed.  If the unlink
  183.      *    of the lock file fails, it should mean that someone
  184.      *    else is executing this code.  They will get success,
  185.      *    and we will fail.
  186.      */
  187.  
  188.     if ((fd = open (GR_LOCK, O_RDWR)) == -1 ||
  189.             (len = read (fd, buf, BUFSIZ)) <= 0) {
  190.         errno = EINVAL;
  191.         return 0;
  192.     }
  193.     buf[len] = '\0';
  194.     if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
  195.         errno = EINVAL;
  196.         return 0;
  197.     }
  198.     if (kill (pid, 0) == 0)  {
  199.         errno = EEXIST;
  200.         return 0;
  201.     }
  202.     if (unlink (GR_LOCK)) {
  203.         (void) close (fd);
  204.         (void) unlink (file);
  205.  
  206.         return 0;
  207.     }
  208.  
  209.     /*
  210.      * Re-try lock -
  211.      *    The invalid lock has now been removed and I should
  212.      *    be able to acquire a lock for myself just fine.  If
  213.      *    this fails there will be no retry.  The link count
  214.      *    test here makes certain someone executing the previous
  215.      *    block of code didn't just remove the lock we just
  216.      *    linked to.
  217.      */
  218.  
  219.     if (link (file, GR_LOCK) == 0) {
  220.         if (stat (file, &sb) != 0)
  221.             return 0;
  222.  
  223.         if (sb.st_nlink != 2)
  224.             return 0;
  225.  
  226.         (void) unlink (file);
  227.         islocked = 1;
  228.         return 1;
  229.     }
  230.     (void) unlink (file);
  231.     return 0;
  232. }
  233.  
  234. /*
  235.  * gr_unlock - logically unlock a group file
  236.  *
  237.  *    gr_unlock() removes the lock which was set by an earlier
  238.  *    invocation of gr_lock().
  239.  */
  240.  
  241. int
  242. gr_unlock ()
  243. {
  244.     if (islocked) {
  245.         if (isopen) {
  246.             open_modes = O_RDONLY;
  247.             gr_close ();
  248.         }
  249.         unlink (GR_LOCK);
  250.         islocked = 0;
  251.         return 1;
  252.     } else
  253.         return 0;
  254. }
  255.  
  256. /*
  257.  * gr_open - open a group file
  258.  *
  259.  *    gr_open() encapsulates the open operation.  it returns
  260.  *    TRUE or FALSE depending on the group file being
  261.  *    properly opened.
  262.  */
  263.  
  264. int
  265. gr_open (mode)
  266. int    mode;
  267. {
  268.     char    buf[8192];
  269.     struct    gr_file_entry    *grf;
  270.     struct    group    *grent;
  271.  
  272.     if (isopen || (mode != O_RDONLY && mode != O_RDWR))
  273.         return 0;
  274.  
  275.     if (mode != O_RDONLY && ! islocked)
  276.         return 0;
  277.  
  278.     if ((grfp = fopen (GROUP, mode == O_RDONLY ? "r":"r+")) == 0)
  279.         return 0;
  280.  
  281.     grf_head = grf_tail = grf_cursor = 0;
  282.     gr_changed = 0;
  283.  
  284.     while (fgets (buf, sizeof buf, grfp) != (char *) 0) {
  285.         if (! (grf = (struct gr_file_entry *) malloc (sizeof *grf)))
  286.             return 0;
  287.  
  288.         grf->grf_changed = 0;
  289.         grf->grf_line = strdup (buf);
  290.         if ((grent = sgetgrent (buf)) && ! (grent = gr_dup (grent)))
  291.             return 0;
  292.  
  293.         grf->grf_entry = grent;
  294.  
  295.         if (grf_head == 0) {
  296.             grf_head = grf_tail = grf;
  297.             grf->grf_next = 0;
  298.         } else {
  299.             grf_tail->grf_next = grf;
  300.             grf->grf_next = 0;
  301.             grf_tail = grf;
  302.         }
  303.     }
  304.     isopen++;
  305.     open_modes = mode;
  306.  
  307.     return 1;
  308. }
  309.  
  310. /*
  311.  * gr_close - close the group file
  312.  *
  313.  *    gr_close() outputs any modified group file entries and
  314.  *    frees any allocated memory.
  315.  */
  316.  
  317. int
  318. gr_close ()
  319. {
  320.     int    fd;
  321.     int    mask;
  322.     int    c;
  323.     int    i;
  324.     int    errors = 0;
  325.     FILE    *bkfp;
  326.     struct    gr_file_entry *grf;
  327.     struct    gr_file_entry *ogrf;
  328.  
  329.     if (! isopen) {
  330.         errno = EINVAL;
  331.         return 0;
  332.     }
  333.     if (open_modes == O_RDWR && gr_changed) {
  334.         mask = umask (0222);
  335.         if ((bkfp = fopen (OGROUP, "w")) == 0) {
  336.             umask (mask);
  337.             return 0;
  338.         }
  339.         umask (mask);
  340.  
  341.         rewind (grfp);
  342.         while ((c = getc (grfp)) != EOF) {
  343.             if (putc (c, bkfp) == EOF) {
  344.                 fclose (bkfp);
  345.                 return 0;
  346.             }
  347.         }
  348.         if (fclose (bkfp))
  349.             return 0;
  350.  
  351.         isopen = 0;
  352.         (void) fclose (grfp);
  353.  
  354.         mask = umask (0222);
  355.         if (! (grfp = fopen (GROUP, "w"))) {
  356.             umask (mask);
  357.             return 0;
  358.         }
  359.         umask (mask);
  360.  
  361.         for (grf = grf_head;errors == 0 && grf;grf = grf->grf_next) {
  362.             if (grf->grf_changed) {
  363.                 if (putgrent (grf->grf_entry, grfp))
  364.                     errors++;
  365.             } else {
  366.                 if (fputs (grf->grf_line, grfp) == EOF)
  367.                     errors++;
  368.             }
  369.         }
  370.         if (fflush (grfp))
  371.             errors++;
  372.  
  373.         if (errors) {
  374.             unlink (GROUP);
  375.             link (OGROUP, GROUP);
  376.             unlink (OGROUP);
  377.             return 0;
  378.         }
  379.     }
  380.     if (fclose (grfp))
  381.         return 0;
  382.  
  383.     grfp = 0;
  384.  
  385.     while (grf_head != 0) {
  386.         grf = grf_head;
  387.         grf_head = grf->grf_next;
  388.  
  389.         if (grf->grf_entry) {
  390.             gr_free (grf->grf_entry);
  391.             free (grf->grf_entry);
  392.         }
  393.         if (grf->grf_line)
  394.             free (grf->grf_line);
  395.  
  396.         free (grf);
  397.     }
  398.     grf_tail = 0;
  399.     return 1;
  400. }
  401.  
  402. int
  403. gr_update (grent)
  404. struct    group    *grent;
  405. {
  406.     struct    gr_file_entry    *grf;
  407.     struct    group    *ngr;
  408.  
  409.     if (! isopen || open_modes == O_RDONLY) {
  410.         errno = EINVAL;
  411.         return 0;
  412.     }
  413.     for (grf = grf_head;grf != 0;grf = grf->grf_next) {
  414.         if (grf->grf_entry == 0)
  415.             continue;
  416.  
  417.         if (strcmp (grent->gr_name, grf->grf_entry->gr_name) != 0)
  418.             continue;
  419.  
  420.         if (! (ngr = gr_dup (grent)))
  421.             return 0;
  422.         else {
  423.             gr_free (grf->grf_entry);
  424.             *(grf->grf_entry) = *ngr;
  425.         }
  426.         grf->grf_changed = 1;
  427.         grf_cursor = grf;
  428.         return gr_changed = 1;
  429.     }
  430.     grf = (struct gr_file_entry *) malloc (sizeof *grf);
  431.     if (! (grf->grf_entry = gr_dup (grent)))
  432.         return 0;
  433.  
  434.     grf->grf_changed = 1;
  435.     grf->grf_next = 0;
  436.     grf->grf_line = 0;
  437.  
  438.     if (grf_tail)
  439.         grf_tail->grf_next = grf;
  440.  
  441.     if (! grf_head)
  442.         grf_head = grf;
  443.  
  444.     grf_tail = grf;
  445.  
  446.     return gr_changed = 1;
  447. }
  448.  
  449. int
  450. gr_remove (name)
  451. char    *name;
  452. {
  453.     struct    gr_file_entry    *grf;
  454.     struct    gr_file_entry    *ogrf;
  455.  
  456.     if (! isopen || open_modes == O_RDONLY) {
  457.         errno = EINVAL;
  458.         return 0;
  459.     }
  460.     for (ogrf = 0, grf = grf_head;grf != 0;
  461.             ogrf = grf, grf = grf->grf_next) {
  462.         if (! grf->grf_entry)
  463.             continue;
  464.  
  465.         if (strcmp (name, grf->grf_entry->gr_name) != 0)
  466.             continue;
  467.  
  468.         if (grf == grf_cursor)
  469.             grf_cursor = ogrf;
  470.  
  471.         if (ogrf != 0)
  472.             ogrf->grf_next = grf->grf_next;
  473.         else
  474.             grf_head = grf->grf_next;
  475.  
  476.         if (grf == grf_tail)
  477.             grf_tail = ogrf;
  478.  
  479.         return gr_changed = 1;
  480.     }
  481.     errno = ENOENT;
  482.     return 0;
  483. }
  484.  
  485. struct group *
  486. gr_locate (name)
  487. char    *name;
  488. {
  489.     struct    gr_file_entry    *grf;
  490.  
  491.     if (! isopen) {
  492.         errno = EINVAL;
  493.         return 0;
  494.     }
  495.     for (grf = grf_head;grf != 0;grf = grf->grf_next) {
  496.         if (grf->grf_entry == 0)
  497.             continue;
  498.  
  499.         if (strcmp (name, grf->grf_entry->gr_name) == 0) {
  500.             grf_cursor = grf;
  501.             return grf->grf_entry;
  502.         }
  503.     }
  504.     errno = ENOENT;
  505.     return 0;
  506. }
  507.  
  508. int
  509. gr_rewind ()
  510. {
  511.     if (! isopen) {
  512.         errno = EINVAL;
  513.         return 0;
  514.     }
  515.     grf_cursor = 0;
  516.     return 1;
  517. }
  518.  
  519. struct group *
  520. gr_next ()
  521. {
  522.     if (! isopen) {
  523.         errno = EINVAL;
  524.         return 0;
  525.     }
  526.     if (grf_cursor == 0)
  527.         grf_cursor = grf_head;
  528.     else
  529.         grf_cursor = grf_cursor->grf_next;
  530.  
  531.     while (grf_cursor) {
  532.         if (grf_cursor->grf_entry)
  533.             return grf_cursor->grf_entry;
  534.  
  535.         grf_cursor = grf_cursor->grf_next;
  536.     }
  537.     return 0;
  538. }
  539.