init: cleanup environment handling

Init keep its own copy of the environment that it uses for execve when
starting services.  This is unnecessary however as libc already has
functions that mutate the environment and the environment that init
uses is clean for starting services.  This change removes init's copy
of the environment and uses the libc functions instead.

This also makes small clean-up to the way the Service class stores
service specific environment variables.

Test: boot bullhead
Change-Id: I7c98a0b7aac9fa8f195ae33bd6a7515bb56faf78
diff --git a/init/builtins.cpp b/init/builtins.cpp
index f807343..593f718 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -159,8 +159,8 @@
 }
 
 static Result<Success> do_export(const std::vector<std::string>& args) {
-    if (!add_environment(args[1].c_str(), args[2].c_str())) {
-        return Error();
+    if (setenv(args[1].c_str(), args[2].c_str(), 1) == -1) {
+        return ErrnoError() << "setenv() failed";
     }
     return Success();
 }
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
index cc5b948..6265687 100644
--- a/init/descriptors.cpp
+++ b/init/descriptors.cpp
@@ -28,7 +28,6 @@
 #include <cutils/android_get_control_file.h>
 #include <cutils/sockets.h>
 
-#include "init.h"
 #include "util.h"
 
 namespace android {
@@ -62,7 +61,7 @@
                 [] (char& c) { c = isalnum(c) ? c : '_'; });
 
   std::string val = std::to_string(fd);
-  add_environment(publishedName.c_str(), val.c_str());
+  setenv(publishedName.c_str(), val.c_str(), 1);
 
   // make sure we don't close on exec
   fcntl(fd, F_SETFD, 0);
diff --git a/init/init.cpp b/init/init.cpp
index d0afac1..e1bd3a2 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -71,8 +71,6 @@
 
 std::string default_console = "/dev/console";
 
-const char *ENV[32];
-
 static int epoll_fd = -1;
 
 static std::unique_ptr<Timer> waiting_for_prop(nullptr);
@@ -126,38 +124,6 @@
     }
 }
 
-/* add_environment - add "key=value" to the current environment */
-int add_environment(const char *key, const char *val)
-{
-    size_t n;
-    size_t key_len = strlen(key);
-
-    /* The last environment entry is reserved to terminate the list */
-    for (n = 0; n < (arraysize(ENV) - 1); n++) {
-
-        /* Delete any existing entry for this key */
-        if (ENV[n] != NULL) {
-            size_t entry_key_len = strcspn(ENV[n], "=");
-            if ((entry_key_len == key_len) && (strncmp(ENV[n], key, entry_key_len) == 0)) {
-                free((char*)ENV[n]);
-                ENV[n] = NULL;
-            }
-        }
-
-        /* Add entry if a free slot is available */
-        if (ENV[n] == NULL) {
-            char* entry;
-            asprintf(&entry, "%s=%s", key, val);
-            ENV[n] = entry;
-            return 0;
-        }
-    }
-
-    LOG(ERROR) << "No env. room to store: '" << key << "':'" << val << "'";
-
-    return -1;
-}
-
 bool start_waiting_for_property(const char *name, const char *value)
 {
     if (waiting_for_prop) {
@@ -429,8 +395,6 @@
         install_reboot_signal_handlers();
     }
 
-    add_environment("PATH", _PATH_DEFPATH);
-
     bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
 
     if (is_first_stage) {
@@ -439,6 +403,8 @@
         // Clear the umask.
         umask(0);
 
+        clearenv();
+        setenv("PATH", _PATH_DEFPATH, 1);
         // Get the basic filesystem setup we need put together in the initramdisk
         // on / and then we'll let the rc file figure out the rest.
         mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
diff --git a/init/init.h b/init/init.h
index 50a7c83..b757c1d 100644
--- a/init/init.h
+++ b/init/init.h
@@ -30,9 +30,7 @@
 // Note: These globals are *only* valid in init, so they should not be used in ueventd,
 // watchdogd, or any files that may be included in those, such as devices.cpp and util.cpp.
 // TODO: Have an Init class and remove all globals.
-extern const char *ENV[32];
 extern std::string default_console;
-
 extern std::vector<std::string> late_import_paths;
 
 Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
@@ -43,8 +41,6 @@
 
 void register_epoll_handler(int fd, void (*fn)());
 
-int add_environment(const char* key, const char* val);
-
 bool start_waiting_for_property(const char *name, const char *value);
 
 void DumpState();
diff --git a/init/selinux.cpp b/init/selinux.cpp
index c824028..ef59164 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -48,7 +48,6 @@
 #include "selinux.h"
 
 #include <fcntl.h>
-#include <paths.h>
 #include <stdlib.h>
 #include <sys/wait.h>
 #include <unistd.h>
@@ -126,8 +125,7 @@
         }
         TEMP_FAILURE_RETRY(close(pipe_fds[1]));
 
-        const char* envp[] = {_PATH_DEFPATH, nullptr};
-        if (execve(filename, argv, (char**)envp) == -1) {
+        if (execv(filename, argv) == -1) {
             PLOG(ERROR) << "Failed to execve " << filename;
             return false;
         }
diff --git a/init/service.cpp b/init/service.cpp
index 6ab60e3..de9538f 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -147,14 +147,6 @@
     strs->push_back(nullptr);
 }
 
-ServiceEnvironmentInfo::ServiceEnvironmentInfo() {
-}
-
-ServiceEnvironmentInfo::ServiceEnvironmentInfo(const std::string& name,
-                                               const std::string& value)
-    : name(name), value(value) {
-}
-
 unsigned long Service::next_start_order_ = 1;
 bool Service::is_exec_service_running_ = false;
 
@@ -507,7 +499,7 @@
 }
 
 Result<Success> Service::ParseSetenv(const std::vector<std::string>& args) {
-    envvars_.emplace_back(args[1], args[2]);
+    environment_vars_.emplace_back(args[1], args[2]);
     return Success();
 }
 
@@ -723,8 +715,8 @@
             SetUpPidNamespace(name_);
         }
 
-        for (const auto& ei : envvars_) {
-            add_environment(ei.name.c_str(), ei.value.c_str());
+        for (const auto& [key, value] : environment_vars_) {
+            setenv(key.c_str(), value.c_str(), 1);
         }
 
         std::for_each(descriptors_.begin(), descriptors_.end(),
@@ -779,7 +771,7 @@
 
         std::vector<char*> strs;
         ExpandArgs(args_, &strs);
-        if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
+        if (execv(strs[0], (char**)&strs[0]) < 0) {
             PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
         }
 
diff --git a/init/service.h b/init/service.h
index fe85129..be173cd 100644
--- a/init/service.h
+++ b/init/service.h
@@ -57,13 +57,6 @@
 namespace android {
 namespace init {
 
-struct ServiceEnvironmentInfo {
-    ServiceEnvironmentInfo();
-    ServiceEnvironmentInfo(const std::string& name, const std::string& value);
-    std::string name;
-    std::string value;
-};
-
 class Service {
   public:
     Service(const std::string& name, const std::vector<std::string>& args);
@@ -178,7 +171,7 @@
     std::string seclabel_;
 
     std::vector<std::unique_ptr<DescriptorInfo>> descriptors_;
-    std::vector<ServiceEnvironmentInfo> envvars_;
+    std::vector<std::pair<std::string, std::string>> environment_vars_;
 
     Action onrestart_;  // Commands to execute on restart.