Multiple consoles

This CL allows enabling of multiple consoles. A service can be
mapped to a specific console by providing the optional argument,
IE "tty0", to "console" service attribute as follows:

service fbconsole /system/bin/sh
    class core
    console tty0
    disabled
    user shell
    group shell log readproc
    seclabel u:r:shell:s0

Bug: None
Change-Id: I3b24e7f6848bbe5c6475f11334c04ec536e6af88
Tracked-On: https://jira01.devtools.intel.com/browse/BP-289
Signed-off-by: Viorel Suman <viorel.suman@intel.com>
diff --git a/init/init.cpp b/init/init.cpp
index bac27df..9b7d108 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -74,8 +74,7 @@
 
 static char qemu[32];
 
-int have_console;
-std::string console_name = "/dev/console";
+std::string default_console = "/dev/console";
 static time_t process_needs_restart;
 
 const char *ENV[32];
@@ -300,36 +299,8 @@
 {
     std::string console = property_get("ro.boot.console");
     if (!console.empty()) {
-        console_name = "/dev/" + console;
+        default_console = "/dev/" + console;
     }
-
-    int fd = open(console_name.c_str(), O_RDWR | O_CLOEXEC);
-    if (fd >= 0)
-        have_console = 1;
-    close(fd);
-
-    fd = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
-    if (fd >= 0) {
-        const char *msg;
-            msg = "\n"
-        "\n"
-        "\n"
-        "\n"
-        "\n"
-        "\n"
-        "\n"  // console is 40 cols x 30 lines
-        "\n"
-        "\n"
-        "\n"
-        "\n"
-        "\n"
-        "\n"
-        "\n"
-        "             A N D R O I D ";
-        write(fd, msg, strlen(msg));
-        close(fd);
-    }
-
     return 0;
 }
 
diff --git a/init/init.h b/init/init.h
index b6a095b..0019337 100644
--- a/init/init.h
+++ b/init/init.h
@@ -26,8 +26,7 @@
 
 extern const char *ENV[32];
 extern bool waiting_for_exec;
-extern int have_console;
-extern std::string console_name;
+extern std::string default_console;
 extern struct selabel_handle *sehandle;
 extern struct selabel_handle *sehandle_prop;
 
diff --git a/init/readme.txt b/init/readme.txt
index ef85ccf..aa372eb 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -115,6 +115,13 @@
 Options are modifiers to services.  They affect how and when init
 runs the service.
 
+console [<console>]
+  This service needs a console. The optional second parameter chooses a
+  specific console instead of the default. The default "/dev/console" can
+  be changed by setting the "androidboot.console" kernel parameter. In
+  all cases the leading "/dev/" should be omitted, so "/dev/tty0" would be
+  specified as just "console tty0".
+
 critical
   This is a device-critical service. If it exits more than four times in
   four minutes, the device will reboot into recovery mode.
diff --git a/init/service.cpp b/init/service.cpp
index bdecc32..e509f46 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -172,6 +172,7 @@
 
 bool Service::HandleConsole(const std::vector<std::string>& args, std::string* err) {
     flags_ |= SVC_CONSOLE;
+    console_ = args.size() > 1 ? "/dev/" + args[1] : "";
     return true;
 }
 
@@ -282,7 +283,7 @@
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
     static const Map option_handlers = {
         {"class",       {1,     1,    &Service::HandleClass}},
-        {"console",     {0,     0,    &Service::HandleConsole}},
+        {"console",     {0,     1,    &Service::HandleConsole}},
         {"critical",    {0,     0,    &Service::HandleCritical}},
         {"disabled",    {0,     0,    &Service::HandleDisabled}},
         {"group",       {1,     NR_SVC_SUPP_GIDS + 1, &Service::HandleGroup}},
@@ -329,10 +330,18 @@
     }
 
     bool needs_console = (flags_ & SVC_CONSOLE);
-    if (needs_console && !have_console) {
-        ERROR("service '%s' requires console\n", name_.c_str());
-        flags_ |= SVC_DISABLED;
-        return false;
+    if (needs_console) {
+        if (console_.empty()) {
+            console_ = default_console;
+        }
+
+        bool have_console = (open(console_.c_str(), O_RDWR | O_CLOEXEC) != -1);
+        if (!have_console) {
+            ERROR("service '%s' couldn't open console '%s': %s\n",
+                  name_.c_str(), console_.c_str(), strerror(errno));
+            flags_ |= SVC_DISABLED;
+            return false;
+        }
     }
 
     struct stat sb;
@@ -606,10 +615,8 @@
 }
 
 void Service::OpenConsole() const {
-    int fd;
-    if ((fd = open(console_name.c_str(), O_RDWR)) < 0) {
-        fd = open("/dev/null", O_RDWR);
-    }
+    int fd = open(console_.c_str(), O_RDWR);
+    if (fd == -1) fd = open("/dev/null", O_RDWR);
     ioctl(fd, TIOCSCTTY, 0);
     dup2(fd, 0);
     dup2(fd, 1);
diff --git a/init/service.h b/init/service.h
index 35abde9..b003ca0 100644
--- a/init/service.h
+++ b/init/service.h
@@ -129,6 +129,7 @@
 
     std::string name_;
     std::string classname_;
+    std::string console_;
 
     unsigned flags_;
     pid_t pid_;