11b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes/*
21b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes * Copyright (C) 2015 The Android Open Source Project
31b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes *
41b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
51b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes * you may not use this file except in compliance with the License.
61b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes * You may obtain a copy of the License at
71b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes *
81b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
91b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes *
101b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes * Unless required by applicable law or agreed to in writing, software
111b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
121b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes * See the License for the specific language governing permissions and
141b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes * limitations under the License.
151b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes */
161b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes
171b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes#include "diagnose_usb.h"
181b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes
191b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes#include <errno.h>
201b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes#include <unistd.h>
211b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes
221b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes#include <string>
231b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes
241b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes#include <android-base/stringprintf.h>
251b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes
261b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes#if defined(__linux__)
271b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes#include <grp.h>
281b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes#endif
291b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes
301b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughesstatic const char kPermissionsHelpUrl[] = "http://developer.android.com/tools/device.html";
311b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes
321b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes// Returns a message describing any potential problems we find with udev, or nullptr if we can't
331b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes// find plugdev information (i.e. udev is not installed).
341b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughesstatic const char* GetUdevProblem() {
351b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes#if defined(__linux__)
361b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    errno = 0;
371b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    group* plugdev_group = getgrnam("plugdev");
381b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes
391b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    if (plugdev_group == nullptr) {
401b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes        if (errno != 0) {
411b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes            perror("failed to read plugdev group info");
421b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes        }
431b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes        // We can't give any generally useful advice here, just let the caller print the help URL.
441b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes        return nullptr;
451b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    }
461b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes
471b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    // getgroups(2) indicates that the group_member() may not check the egid so we check it
481b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    // additionally just to be sure.
491b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    if (group_member(plugdev_group->gr_gid) || getegid() == plugdev_group->gr_gid) {
501b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes        // The user is in plugdev so the problem is likely with the udev rules.
511b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes        return "verify udev rules";
521b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    }
531b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    return "udev requires plugdev group membership";
541b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes#else
551b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    return nullptr;
561b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes#endif
571b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes}
581b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes
591b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes// Short help text must be a single line, and will look something like:
601b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes//   no permissions (reason); see <URL>
611b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughesstd::string UsbNoPermissionsShortHelpText() {
621b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    std::string help_text = "no permissions";
631b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes
641b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    const char* problem = GetUdevProblem();
651b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    if (problem != nullptr) {
661b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes        help_text += android::base::StringPrintf(" (%s)", problem);
671b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    }
681b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes
691b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    return android::base::StringPrintf("%s; see [%s]", help_text.c_str(), kPermissionsHelpUrl);
701b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes}
711b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes
721b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes// Long help text can span multiple lines and should provide more detailed information.
731b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughesstd::string UsbNoPermissionsLongHelpText() {
741b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    std::string header = "insufficient permissions for device";
751b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes
761b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    const char* problem = GetUdevProblem();
771b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    if (problem != nullptr) {
781b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes        header += android::base::StringPrintf(": %s", problem);
791b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    }
801b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes
811b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes    return android::base::StringPrintf("%s.\nSee [%s] for more information.",
821b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes                                       header.c_str(), kPermissionsHelpUrl);
831b708d368f29e6053064c9cf6949ab6ebdbb7ac5Elliott Hughes}
84