Improve udev failure diagnostics.

A couple of folks had trouble understanding the existing message.

Before:

  8XV7N15917000596	no permissions (udev requires plugdev group membership); see [http://developer.android.com/tools/device.html]

After:

  8XV7N15917000596	no permissions (user buttmunch is not in the plugdev group); see [http://developer.android.com/tools/device.html]

This also fixes a libusb regression where we wouldn't show anything for
devices where we don't have permissions.

Bug: http://b/37707122
Test: ran "adb devices" as user buttmunch
Change-Id: I2fcd735ff4178145432b532a6e4dc8c93b2743fd
diff --git a/diagnose_usb.cpp b/diagnose_usb.cpp
index 0f067b0..9f721bf 100644
--- a/diagnose_usb.cpp
+++ b/diagnose_usb.cpp
@@ -25,13 +25,14 @@
 
 #if defined(__linux__)
 #include <grp.h>
+#include <pwd.h>
 #endif
 
 static const char kPermissionsHelpUrl[] = "http://developer.android.com/tools/device.html";
 
-// Returns a message describing any potential problems we find with udev, or nullptr if we can't
-// find plugdev information (i.e. udev is not installed).
-static const char* GetUdevProblem() {
+// Returns a message describing any potential problems we find with udev, or an empty string if we
+// can't find plugdev information (i.e. udev is not installed).
+static std::string GetUdevProblem() {
 #if defined(__linux__)
     errno = 0;
     group* plugdev_group = getgrnam("plugdev");
@@ -41,43 +42,45 @@
             perror("failed to read plugdev group info");
         }
         // We can't give any generally useful advice here, just let the caller print the help URL.
-        return nullptr;
+        return "";
     }
 
-    // getgroups(2) indicates that the group_member() may not check the egid so we check it
+    // getgroups(2) indicates that the GNU group_member(3) may not check the egid so we check it
     // additionally just to be sure.
     if (group_member(plugdev_group->gr_gid) || getegid() == plugdev_group->gr_gid) {
         // The user is in plugdev so the problem is likely with the udev rules.
-        return "verify udev rules";
+        return "user in plugdev group; are your udev rules wrong?";
     }
-    return "udev requires plugdev group membership";
+    passwd* pwd = getpwuid(getuid());
+    return android::base::StringPrintf("user %s is not in the plugdev group",
+                                       pwd ? pwd->pw_name : "?");
 #else
-    return nullptr;
+    return "";
 #endif
 }
 
 // Short help text must be a single line, and will look something like:
-//   no permissions (reason); see <URL>
+//
+//   no permissions (reason); see [URL]
 std::string UsbNoPermissionsShortHelpText() {
     std::string help_text = "no permissions";
 
-    const char* problem = GetUdevProblem();
-    if (problem != nullptr) {
-        help_text += android::base::StringPrintf(" (%s)", problem);
-    }
+    std::string problem(GetUdevProblem());
+    if (!problem.empty()) help_text += " (" + problem + ")";
 
     return android::base::StringPrintf("%s; see [%s]", help_text.c_str(), kPermissionsHelpUrl);
 }
 
-// Long help text can span multiple lines and should provide more detailed information.
+// Long help text can span multiple lines but doesn't currently provide more detailed information:
+//
+//   insufficient permissions for device: reason
+//   See [URL] for more information
 std::string UsbNoPermissionsLongHelpText() {
     std::string header = "insufficient permissions for device";
 
-    const char* problem = GetUdevProblem();
-    if (problem != nullptr) {
-        header += android::base::StringPrintf(": %s", problem);
-    }
+    std::string problem(GetUdevProblem());
+    if (!problem.empty()) header += ": " + problem;
 
-    return android::base::StringPrintf("%s.\nSee [%s] for more information.",
-                                       header.c_str(), kPermissionsHelpUrl);
+    return android::base::StringPrintf("%s\nSee [%s] for more information", header.c_str(),
+                                       kPermissionsHelpUrl);
 }