diff --git a/api/x_opengl.C b/api/x_opengl.C index bf5d662824..85e6272951 100644 --- a/api/x_opengl.C +++ b/api/x_opengl.C @@ -30,6 +30,7 @@ #include "app_ipc.h" #include "util.h" #include "filesys.h" +#include "unix_util.h" #include "boinc_gl.h" #include "boinc_glut.h" @@ -488,8 +489,7 @@ static void timer_handler(int) { case MODE_FULLSCREEN: case MODE_BLANKSCREEN: if (strlen(m.display)) { - sprintf(buf, "DISPLAY=%s", m.display); - putenv(buf); + setenv("DISPLAY",m.display,1); } set_mode(m.mode); break; diff --git a/checkin_notes b/checkin_notes index 4ea1e179d7..1344803791 100644 --- a/checkin_notes +++ b/checkin_notes @@ -3607,3 +3607,18 @@ David May 5 2008 sched_send.C html/user/ profile_rate.php + +Eric K May 6 2008 + - Added implementation of setenv() for systems without it. + - Fixed bug in x_opengl.C. On systems where putenv() adds the string to the + environment rather than copies it, the environment would end up containing + a random peice of the stack where the DISPLAY variable had been + temporarily stored. + + configure.ac + lib/ + unix_util.[Ch] + api/ + x_opengl.C + + diff --git a/configure.ac b/configure.ac index 9a6d8dec18..44ecf18665 100644 --- a/configure.ac +++ b/configure.ac @@ -445,7 +445,7 @@ AC_LANG_POP dnl Checks for library functions. AC_PROG_GCC_TRADITIONAL AC_FUNC_VPRINTF -AC_CHECK_FUNCS(alloca _alloca setpriority strlcpy strlcat strcasestr sigaction getutent setutent getisax strdup strdupa daemon stat64) +AC_CHECK_FUNCS(alloca _alloca setpriority strlcpy strlcat strcasestr sigaction getutent setutent getisax strdup strdupa daemon stat64 putenv setenv) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST diff --git a/lib/unix_util.C b/lib/unix_util.C index b62257ea9c..8defe8a877 100644 --- a/lib/unix_util.C +++ b/lib/unix_util.C @@ -19,10 +19,79 @@ #include "unix_util.h" +#ifndef HAVE_SETENV + +#include +#include +#include +#include + +static std::vector envstrings; + +// In theory setenv() is posix, but some implementations of unix +// don't have it. The implementation isn't trivial because of +// differences in how putenv() behaves on different systems. +int setenv(const char *name, const char *value, int overwrite) { + char *buf; + int rv; + // Name can't contant an equal sign. + if (strchr(name,'=')) { + errno=EINVAL; + return -1; + } + // get any existing environment string. + buf=getenv(name); + if (!buf) { + // no existing string, allocate a new one. + buf=(char *)malloc(strlen(name)+strlen(value)+2); + if (buf) envstrings.push_back(buf); + } else { + // we do have an existing string. + // Are we allowed to overwrite it? If not return success. + if (!overwrite) return 0; + // is it long enough to hold our current string? + if (strlen(buf)<(strlen(name)+strlen(value)+1)) { + // no. See if we originally allocated this string. + std::vector::iterator i=envstrings.begin(); + for (;i!=envstrings.end();i++) { + if (*i == buf) break; + } + if (i!=envstrings.end()) { + // we allocated this string. Reallocate it. + buf=(char *)realloc(buf,strlen(name)+strlen(value)+2); + *i=buf; + } else { + // someone else allocated the string. Allocate new memory. + buf=(char *)malloc(strlen(name)+strlen(value)+2); + if (buf) envstrings.push_back(buf); + } + } + } + if (!buf) { + errno=ENOMEM; + return -1; + } + sprintf(buf,"%s=%s",name,value); + rv=putenv(buf); + // Yes, there is a potential memory leak here. Some versions of operating + // systems copy the string into the environment, others make the + // existing string part of the environment. If we were to + // implement unsetenv(), it might be possible to recover some of + // this memory. But unsetenv() is even less trivial than setenv. + return rv; +} +#endif /* !HAVE_SETENV */ + #ifndef HAVE_DAEMON #include #include +#ifdef HAVE_UNISTD_H +#include +#endif + +using std::FILE; +using std::freopen; static FILE *stderr_null, *stdout_null; @@ -57,4 +126,4 @@ int daemon(int nochdir, int noclose) { return 0; } -#endif /* HAVE_DAEMON */ +#endif /* !HAVE_DAEMON */ diff --git a/lib/unix_util.h b/lib/unix_util.h index 1428330168..333dd922f9 100644 --- a/lib/unix_util.h +++ b/lib/unix_util.h @@ -25,9 +25,16 @@ #include "config.h" +#ifndef HAVE_SETENV + +extern "C" int setenv(const char *name, const char *value, int overwrite); + +#endif + + #ifndef HAVE_DAEMON -extern int daemon(int nochdir, int noclose); +extern "C" int daemon(int nochdir, int noclose); #endif /* HAVE_DAEMON */