libexplain  1.4.D001
libexplain/setenv_on_error.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2010-2013 Peter Miller
00004  *
00005  * This program is free software; you can redistribute it and/or modify it
00006  * under the terms of the GNU Lesser General Public License as published by
00007  * the Free Software Foundation; either version 3 of the License, or (at
00008  * your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful, but
00011  * WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
00013  * General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public License
00016  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include <libexplain/ac/errno.h>
00020 #include <libexplain/ac/stdlib.h>
00021 #include <libexplain/ac/string.h>
00022 
00023 #include <libexplain/is_efault.h>
00024 #include <libexplain/output.h>
00025 #include <libexplain/setenv.h>
00026 
00027 
00028 #ifndef HAVE_SETENV
00029 
00030 extern char **environ;
00031 
00032 
00033 static char *
00034 name_eq_value(const char *name, const char *value)
00035 {
00036     size_t          name_size;
00037     size_t          value_size;
00038     char            *p;
00039 
00040     name_size = strlen(name);
00041     value_size = strlen(value);
00042     p = malloc(name_size + 1 + value_size + 1);
00043     if (!p)
00044         return NULL;
00045     memcpy(p, name, name_size);
00046     p[name_size] = '=';
00047     memcpy(p + name_size + 1, value, value_size);
00048     p[name_size + 1 + value_size] = '\0';
00049     return p;
00050 }
00051 
00052 
00053 static int
00054 setenv(const char *name, const char *value, int overwrite)
00055 {
00056     int             save_errno;
00057     size_t          name_size;
00058     char            **ep;
00059     size_t          environ_size;
00060     char            *p;
00061     char            **new_environ;
00062 
00063     save_errno = errno;
00064     if (!name)
00065     {
00066         errno = EINVAL;
00067         return -1;
00068     }
00069     if (explain_is_efault_string(name))
00070     {
00071         errno = EFAULT;
00072         return -1;
00073     }
00074     if (value && explain_is_efault_string(value))
00075     {
00076         errno = EFAULT;
00077         return -1;
00078     }
00079     if (!*name || strchr(name, '='))
00080     {
00081         errno = EINVAL;
00082         return -1;
00083     }
00084     name_size = strlen(name);
00085     ep = environ;
00086     if (!ep)
00087     {
00088         if (!value)
00089         {
00090             errno = save_errno;
00091             return 0;
00092         }
00093         environ = malloc(sizeof(char *) * 2); /* memory leak */
00094         if (!environ)
00095         {
00096             errno = ENOMEM;
00097             return -1;
00098         }
00099         environ[0] = 0;
00100         p = name_eq_value(name, value); /* memory leak */
00101         if (!p)
00102         {
00103             errno = ENOMEM;
00104             return -1;
00105         }
00106         environ[0] = p;
00107         environ[1] = NULL;
00108         errno = save_errno;
00109         return 0;
00110     }
00111 
00112     environ_size = 0;
00113     for (; *ep; ++ep)
00114     {
00115         if (!memcmp(*ep, name, name_size) && (*ep)[name_size] == '=')
00116         {
00117             if (!value)
00118             {
00119                 char            **ep2;
00120 
00121                 ep2 = ep;
00122                 for (;;)
00123                 {
00124                     ep2[0] = ep2[1];
00125                     if (!ep2[0])
00126                         break;
00127                     ++ep2;
00128                 }
00129                 /* keep going, there could be more */
00130                 continue;
00131             }
00132 
00133             /* avoid doing anything, if possible */
00134             if (overwrite && 0 != strcmp(*ep + name_size + 1, value))
00135             {
00136                 p = name_eq_value(name, value); /* memory leak */
00137                 if (!p)
00138                 {
00139                     errno = ENOMEM;
00140                     return -1;
00141                 }
00142                 *ep = p;
00143             }
00144             errno = save_errno;
00145             return 0;
00146         }
00147         ++environ_size;
00148     }
00149     if (!value)
00150     {
00151         errno = save_errno;
00152         return 0;
00153     }
00154 
00155     new_environ = malloc(sizeof(char *) * (environ_size + 2)); /* memory leak */
00156     if (!new_environ)
00157     {
00158         errno = ENOMEM;
00159         return -1;
00160     }
00161     memcpy(new_environ, environ, sizeof(char *) * environ_size);
00162     p = name_eq_value(name, value); /* memory leak */
00163     if (!p)
00164     {
00165         free(new_environ);
00166         errno = ENOMEM;
00167         return -1;
00168     }
00169     new_environ[environ_size] = p;
00170     new_environ[environ_size + 1] = NULL;
00171     environ = new_environ; /* memory leak */
00172     errno = save_errno;
00173     return 0;
00174 }
00175 
00176 #endif
00177 
00178 int
00179 explain_setenv_on_error(const char *name, const char *value, int overwrite)
00180 {
00181     int             result;
00182 
00183     result = setenv(name, value, overwrite);
00184     if (result < 0)
00185     {
00186         int             hold_errno;
00187 
00188         hold_errno = errno;
00189         explain_output_error("%s", explain_errno_setenv(hold_errno, name,
00190             value, overwrite));
00191         errno = hold_errno;
00192     }
00193     return result;
00194 }
00195 
00196 
00197 /* vim: set ts=8 sw=4 et : */