user_config.c

Go to the documentation of this file.
00001 /*
00002 * $Id: user_config.c,v 2.5 2006/07/07 10:16:35 paul Exp $
00003 *
00004 ****************************************************************************
00005 *
00006 * LIBRARY:      user_config.c  -- Routines related to the user's GRASS 
00007 *               configuration, tmp, and miscellaneous files.
00008 *
00009 * AUTHOR(S):    Eric G. Miller <egm2@jps.net>
00010 *
00011 * PURPOSE:      Provide a set of routines for creating and accessing
00012 *               elements within the user's "rc" directory.  The directory is
00013 *               in $HOME/.grass
00014 *
00015 * COPYRIGHT:    (C) 2000 by the GRASS Development Team
00016 *
00017 *               This program is free software under the GNU General Public
00018 *               License (>=v2). Read the file COPYING that comes with GRASS
00019 *               for details.
00020 *
00021 *****************************************************************************/
00022 
00023 /* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
00024  * NOTE: As of 2001-03-25 this file is not hooked up.  It is provided as a
00025  * candidate for handling $HOME/.grass files and subdirectories.  There may
00026  * be more functionality desired (such as deletion routines, directory globs).
00027  * @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
00028 
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <assert.h>
00032 #include <unistd.h>
00033 #include <string.h>
00034 #ifndef __MINGW32__
00035 #include <pwd.h>
00036 #endif
00037 #include <sys/types.h>
00038 #include <sys/stat.h>
00039 #include <errno.h>
00040 #include <grass/gis.h>
00041 
00042 #ifdef __MINGW32__
00043 # define mkdir(name, mode) ((mkdir) (name))
00044 #endif
00045 
00046 /**************************************************************************
00047  * _make_toplevel(): make user's toplevel config directory if it doesn't
00048  * already exist.  Adjust perms to 1700. Returns the toplevel directory
00049  * path [caller must G_free ()] on success, or NULL on failure
00050  *************************************************************************/
00051 #ifndef __MINGW32__  /* TODO */
00052 static char *
00053 _make_toplevel (void)
00054 {
00055     size_t len;
00056     int status;
00057 #ifdef __MINGW32__
00058     char *defaulthomedir = "c:";
00059     char *homedir = getenv ( "HOME" );
00060 #else    
00061     uid_t me;
00062     struct passwd *my_passwd;
00063 #endif    
00064     struct stat buf;
00065     char *path;
00066 
00067     errno = 0;
00068 
00069     /* Query whatever database to get user's home dir */
00070 #ifdef __MINGW32__
00071     if ( NULL == homedir ) {
00072         homedir = defaulthomedir;
00073     }
00074     
00075     len = strlen ( homedir ) + 8; /* + "/.grass\0" */
00076     if ( NULL == ( path = G_calloc ( 1, len ) ) ) {
00077         return NULL;
00078     }
00079     sprintf ( path, "%s%s", homedir, "/.grass" );
00080 #else
00081     me = getuid();
00082     my_passwd = getpwuid (me);
00083     if (my_passwd == NULL)
00084         return NULL;
00085 
00086     len = strlen (my_passwd->pw_dir) + 8; /* + "/.grass\0" */
00087     if (NULL == (path = G_calloc (1, len)))
00088         return NULL;
00089 
00090     sprintf (path, "%s%s", my_passwd->pw_dir, "/.grass");
00091 #endif
00092 
00093     status = lstat (path, &buf);
00094 
00095     /* If errno == ENOENT, the directory doesn't exist */
00096     if (status != 0)
00097     {
00098         if (errno == ENOENT)
00099         {
00100             status = mkdir (path, S_IRWXU); /* drwx------ */ 
00101     
00102             if (status != 0)  /* mkdir failed */
00103             {
00104                 G_free (path);
00105                 return NULL;
00106             }
00107             
00108             /* override umask settings, if possible */
00109             chmod (path, S_IRWXU);
00110 
00111             /* otherwise mkdir succeeded, we're done here */
00112             return path;
00113         }
00114         
00115         /* other errors should not be defined ??? give up */
00116         G_free (path);
00117         return NULL;
00118     }
00119     /* implicit else */
00120 
00121     /* Examine the stat "buf" */
00122     /* It better be a directory */
00123     if (!S_ISDIR(buf.st_mode)) /* File, link, something else */
00124     {
00125         errno = ENOTDIR; /* element is not a directory, but should be */
00126         G_free (path);
00127         return NULL;
00128     }
00129 
00130     /* No read/write/execute ??? */
00131     if (!(
00132           (S_IRUSR & buf.st_mode) &&
00133           (S_IWUSR & buf.st_mode) &&
00134           (S_IXUSR & buf.st_mode)
00135          )
00136        )
00137     {
00138         errno = EACCES;  /* Permissions error */
00139         G_free (path);
00140         return NULL;
00141     }
00142 
00143     /* We'll assume that if the user grants greater permissions
00144      * than we would, that they know what they're doing
00145      * -- so we're done here...
00146      */
00147 
00148     return path;
00149 }
00150 
00151 
00152 /**************************************************************************
00153  * _elem_count_split: Does a couple things:
00154  * 1) Counts the number of elements in "elems"
00155  * 2) Replaces occurrences of '/' with '\0'
00156  * 3) Checks that no element begins with a '.'
00157  * 4) Checks there are no '//'
00158  *
00159  * Therefore, THE STRING THAT IS PASSED IN IS MODIFIED
00160  * Returns 0 if there are no elements, or an element
00161  * beginning with a '.' or containing a '//' is found.
00162  *************************************************************************/
00163 static int
00164 _elem_count_split (char *elems)
00165 {
00166     int i;
00167     size_t len;
00168     char *begin, *end;
00169     
00170     /* Some basic assertions */
00171     assert (elems != NULL);
00172     assert ((len = strlen(elems)) > 0);
00173     assert (*elems != '/');
00174     
00175     begin = elems;
00176     for (i = 0; begin != NULL && len > begin - elems; i++)
00177     {
00178         /* check '.' condition */
00179         if (*begin == '.')
00180             return 0;
00181         end = strchr (begin, '/');
00182         /* check '//' condition */
00183         if (end != NULL && end == begin)
00184             return 0;
00185         /* okay, change '/' into '\0' */
00186         begin = end;
00187         if (begin != NULL)
00188         {
00189             *begin = '\0';  /* begin points at '/', change it */
00190             begin++;        /* increment begin to next char */
00191         }
00192     }
00193 
00194     /* That's it */
00195     return i;
00196 }
00197     
00198 
00199 /**************************************************************************
00200  * _make_sublevels(): creates subelements as necessary from the passed
00201  * "elems" string.  It returns the full path if successful or NULL
00202  * if it fails.  "elems" must not be NULL, zero length, or have any
00203  * elements that begin with a '.' or any occurrences of '//'.
00204  *************************************************************************/
00205 static char *
00206 _make_sublevels(char *elems)
00207 {
00208     int i, status;
00209     char *cp, *path, *top, *ptr;
00210     struct stat buf;
00211 
00212     /* Get top level path */
00213     if (NULL == (top = _make_toplevel()))
00214         return NULL;
00215 
00216     /* Make a copy of elems */
00217     if (NULL == (cp = G_store (elems)))
00218     {
00219         G_free (top);
00220         return NULL;
00221     }
00222     
00223     /* Do element count, sanity checking and "splitting" */
00224     if ((i = _elem_count_split (cp)) < 1)
00225     {
00226         G_free (cp);
00227         G_free (top);
00228         return NULL;
00229     }
00230 
00231     /* Allocate our path to be large enough */
00232     if ((path = G_calloc (1, strlen(top) + strlen(elems) + 2)) == NULL)
00233     {
00234         G_free (top);
00235         G_free (cp);
00236         return NULL;
00237     }
00238     
00239     /* Now loop along adding directories if they don't exist
00240      * make sure the thing is a directory as well.
00241      * If there was a trailing '/' in the original "elem", it doesn't
00242      * make it into the returned path.
00243      */
00244     for (; i > 0; i--)
00245     {
00246         sprintf (path, "%s/%s", top, cp);
00247         errno = 0;
00248         status = lstat (path, &buf);
00249         if (status != 0)
00250         {
00251             /* the element doesn't exist */
00252             status = mkdir (path, S_IRWXU); /* drwx------ */ 
00253             if (status != 0)
00254             {
00255                 /* Some kind of problem... */
00256                 G_free (top);
00257                 G_free (cp);
00258                 return NULL;
00259             }
00260             /* override umask settings, if possible */
00261             chmod (path, S_IRWXU);
00262         }
00263         else
00264         {
00265             /* Examine the stat "buf" */
00266             /* It better be a directory */
00267             if (!S_ISDIR(buf.st_mode)) /* File, link, something else */
00268             {
00269                 errno = ENOTDIR; /* element is not a directory, but should be */
00270                 G_free (path);
00271                 return NULL;
00272             }
00273 
00274             /* No read/write/execute ??? */
00275             if (!(
00276                   (S_IRUSR & buf.st_mode) &&
00277                   (S_IWUSR & buf.st_mode) &&
00278                   (S_IXUSR & buf.st_mode)
00279                  )
00280                )
00281             {
00282                 errno = EACCES;  /* Permissions error */
00283                 G_free (path);
00284                 return NULL;
00285             }
00286 
00287             /* okay continue ... */
00288         }
00289 
00290         ptr = strchr (cp, '\0');
00291         *ptr = '/';
00292     }
00293 
00294     /* All done, free memory */
00295     G_free (top);
00296     G_free (cp);
00297 
00298     return path;
00299 }
00300 
00301     
00302 /***************************************************************************
00303  * G_rc_path:  Return the path to "element" and "item". Either can be NULL,
00304  * but not both.  If "element" is NULL, then the file is assumed to live at
00305  * the top level.  If file is NULL, then it is assumed the caller is not
00306  * interested in the file.  If the element or rc dir do not exist, they are
00307  * created.  However, the file is never checked for.
00308  **************************************************************************/
00309 char *
00310 G_rc_path (char *element, char *item)
00311 {
00312     size_t len;
00313     char *path, *ptr;
00314 
00315     assert (!(element == NULL && item == NULL));
00316 
00317     /* Simple item in top-level */
00318     if (element == NULL)
00319     {
00320         path = _make_toplevel();
00321     }
00322     else if (item == NULL)
00323     {
00324         return _make_sublevels (element);
00325     }
00326     else
00327     {
00328         path = _make_sublevels (element);
00329     }
00330    
00331 
00332     assert (*item != '.');
00333     assert (path != NULL);
00334     ptr = strchr (item, '/'); /* should not have slashes */
00335     assert (ptr == NULL);
00336     len = strlen(path) + strlen(item) + 2;
00337     if ((ptr = G_realloc (path, len)) == NULL)
00338     {
00339         G_free (path);
00340         return NULL;
00341     }
00342     path = ptr;
00343     ptr = strchr (path, '\0');
00344     sprintf (ptr, "/%s", item);
00345 
00346     return path;
00347 } /* G_rc_path */
00348        
00349 
00350 
00351 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */
00352 #endif

Generated on Wed Dec 19 14:59:06 2007 for GRASS by  doxygen 1.5.4