1// Copyright 2010 Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9//   notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above copyright
11//   notice, this list of conditions and the following disclaimer in the
12//   documentation and/or other materials provided with the distribution.
13// * Neither the name of Google Inc. nor the names of its contributors
14//   may be used to endorse or promote products derived from this software
15//   without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29#include "utils/env.hpp"
30
31#if defined(HAVE_CONFIG_H)
32#  include "config.h"
33#endif
34
35#include <cerrno>
36#include <cstdlib>
37#include <cstring>
38#include <stdexcept>
39
40#include "utils/format/macros.hpp"
41#include "utils/logging/macros.hpp"
42#include "utils/optional.ipp"
43
44using utils::none;
45using utils::optional;
46
47
48extern "C" {
49    extern char** environ;
50}
51
52
53/// Gets all environment variables.
54///
55/// \return A mapping of (name, value) pairs describing the environment
56/// variables.
57std::map< std::string, std::string >
58utils::getallenv(void)
59{
60    std::map< std::string, std::string > allenv;
61    for (char** envp = environ; *envp != NULL; envp++) {
62        const std::string oneenv = *envp;
63        const std::string::size_type pos = oneenv.find('=');
64        const std::string name = oneenv.substr(0, pos);
65        const std::string value = oneenv.substr(pos + 1);
66
67        PRE(allenv.find(name) == allenv.end());
68        allenv[name] = value;
69    }
70    return allenv;
71}
72
73
74/// Gets the value of an environment variable.
75///
76/// \param name The name of the environment variable to query.
77///
78/// \return The value of the environment variable if it is defined, or none
79/// otherwise.
80optional< std::string >
81utils::getenv(const std::string& name)
82{
83    const char* value = std::getenv(name.c_str());
84    if (value == NULL) {
85        LD(F("Environment variable '%s' is not defined") % name);
86        return none;
87    } else {
88        LD(F("Environment variable '%s' is '%s'") % name % value);
89        return utils::make_optional(std::string(value));
90    }
91}
92
93
94/// Gets the value of an environment variable with a default fallback.
95///
96/// \param name The name of the environment variable to query.
97/// \param default_value The value to return if the variable is not defined.
98///
99/// \return The value of the environment variable.
100std::string
101utils::getenv_with_default(const std::string& name,
102                           const std::string& default_value)
103{
104    const char* value = std::getenv(name.c_str());
105    if (value == NULL) {
106        LD(F("Environment variable '%s' is not defined; using default '%s'") %
107           name % default_value);
108        return default_value;
109    } else {
110        LD(F("Environment variable '%s' is '%s'") % name % value);
111        return value;
112    }
113}
114
115
116/// Sets the value of an environment variable.
117///
118/// \param name The name of the environment variable to set.
119/// \param val The value to set the environment variable to.  May be empty.
120///
121/// \throw std::runtime_error If there is an error setting the environment
122///     variable.
123void
124utils::setenv(const std::string& name, const std::string& val)
125{
126    LD(F("Setting environment variable '%s' to '%s'") % name % val);
127#if defined(HAVE_SETENV)
128    if (::setenv(name.c_str(), val.c_str(), 1) == -1) {
129        const int original_errno = errno;
130        throw std::runtime_error(F("Failed to set environment variable '%s' to "
131                                   "'%s': %s") %
132                                 name % val % std::strerror(original_errno));
133    }
134#elif defined(HAVE_PUTENV)
135    if (::putenv((F("%s=%s") % name % val).c_str()) == -1) {
136        const int original_errno = errno;
137        throw std::runtime_error(F("Failed to set environment variable '%s' to "
138                                   "'%s': %s") %
139                                 name % val % std::strerror(original_errno));
140    }
141#else
142#   error "Don't know how to set an environment variable."
143#endif
144}
145
146
147/// Unsets an environment variable.
148///
149/// \param name The name of the environment variable to unset.
150///
151/// \throw std::runtime_error If there is an error unsetting the environment
152///     variable.
153void
154utils::unsetenv(const std::string& name)
155{
156    LD(F("Unsetting environment variable '%s'") % name);
157#if defined(HAVE_UNSETENV)
158    if (::unsetenv(name.c_str()) == -1) {
159        const int original_errno = errno;
160        throw std::runtime_error(F("Failed to unset environment variable "
161                                   "'%s'") %
162                                 name % std::strerror(original_errno));
163    }
164#elif defined(HAVE_PUTENV)
165    if (::putenv((F("%s=") % name).c_str()) == -1) {
166        const int original_errno = errno;
167        throw std::runtime_error(F("Failed to unset environment variable "
168                                   "'%s'") %
169                                 name % std::strerror(original_errno));
170    }
171#else
172#   error "Don't know how to unset an environment variable."
173#endif
174}
175