1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "uevent_listener.h" 18 19#include <fcntl.h> 20#include <poll.h> 21#include <string.h> 22#include <unistd.h> 23 24#include <memory> 25 26#include <android-base/logging.h> 27#include <cutils/uevent.h> 28 29namespace android { 30namespace init { 31 32static void ParseEvent(const char* msg, Uevent* uevent) { 33 uevent->partition_num = -1; 34 uevent->major = -1; 35 uevent->minor = -1; 36 uevent->action.clear(); 37 uevent->path.clear(); 38 uevent->subsystem.clear(); 39 uevent->firmware.clear(); 40 uevent->partition_name.clear(); 41 uevent->device_name.clear(); 42 // currently ignoring SEQNUM 43 while (*msg) { 44 if (!strncmp(msg, "ACTION=", 7)) { 45 msg += 7; 46 uevent->action = msg; 47 } else if (!strncmp(msg, "DEVPATH=", 8)) { 48 msg += 8; 49 uevent->path = msg; 50 } else if (!strncmp(msg, "SUBSYSTEM=", 10)) { 51 msg += 10; 52 uevent->subsystem = msg; 53 } else if (!strncmp(msg, "FIRMWARE=", 9)) { 54 msg += 9; 55 uevent->firmware = msg; 56 } else if (!strncmp(msg, "MAJOR=", 6)) { 57 msg += 6; 58 uevent->major = atoi(msg); 59 } else if (!strncmp(msg, "MINOR=", 6)) { 60 msg += 6; 61 uevent->minor = atoi(msg); 62 } else if (!strncmp(msg, "PARTN=", 6)) { 63 msg += 6; 64 uevent->partition_num = atoi(msg); 65 } else if (!strncmp(msg, "PARTNAME=", 9)) { 66 msg += 9; 67 uevent->partition_name = msg; 68 } else if (!strncmp(msg, "DEVNAME=", 8)) { 69 msg += 8; 70 uevent->device_name = msg; 71 } 72 73 // advance to after the next \0 74 while (*msg++) 75 ; 76 } 77 78 if (LOG_UEVENTS) { 79 LOG(INFO) << "event { '" << uevent->action << "', '" << uevent->path << "', '" 80 << uevent->subsystem << "', '" << uevent->firmware << "', " << uevent->major 81 << ", " << uevent->minor << " }"; 82 } 83} 84 85UeventListener::UeventListener() { 86 // is 2MB enough? udev uses 128MB! 87 device_fd_.reset(uevent_open_socket(2 * 1024 * 1024, true)); 88 if (device_fd_ == -1) { 89 LOG(FATAL) << "Could not open uevent socket"; 90 } 91 92 fcntl(device_fd_, F_SETFL, O_NONBLOCK); 93} 94 95bool UeventListener::ReadUevent(Uevent* uevent) const { 96 char msg[UEVENT_MSG_LEN + 2]; 97 int n = uevent_kernel_multicast_recv(device_fd_, msg, UEVENT_MSG_LEN); 98 if (n <= 0) { 99 if (errno != EAGAIN && errno != EWOULDBLOCK) { 100 LOG(ERROR) << "Error reading from Uevent Fd"; 101 } 102 return false; 103 } 104 if (n >= UEVENT_MSG_LEN) { 105 LOG(ERROR) << "Uevent overflowed buffer, discarding"; 106 // Return true here even if we discard as we may have more uevents pending and we 107 // want to keep processing them. 108 return true; 109 } 110 111 msg[n] = '\0'; 112 msg[n + 1] = '\0'; 113 114 ParseEvent(msg, uevent); 115 116 return true; 117} 118 119// RegenerateUevents*() walks parts of the /sys tree and pokes the uevent files to cause the kernel 120// to regenerate device add uevents that have already happened. This is particularly useful when 121// starting ueventd, to regenerate all of the uevents that it had previously missed. 122// 123// We drain any pending events from the netlink socket every time we poke another uevent file to 124// make sure we don't overrun the socket's buffer. 125// 126 127ListenerAction UeventListener::RegenerateUeventsForDir(DIR* d, 128 const ListenerCallback& callback) const { 129 int dfd = dirfd(d); 130 131 int fd = openat(dfd, "uevent", O_WRONLY); 132 if (fd >= 0) { 133 write(fd, "add\n", 4); 134 close(fd); 135 136 Uevent uevent; 137 while (ReadUevent(&uevent)) { 138 if (callback(uevent) == ListenerAction::kStop) return ListenerAction::kStop; 139 } 140 } 141 142 dirent* de; 143 while ((de = readdir(d)) != nullptr) { 144 if (de->d_type != DT_DIR || de->d_name[0] == '.') continue; 145 146 fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY); 147 if (fd < 0) continue; 148 149 std::unique_ptr<DIR, decltype(&closedir)> d2(fdopendir(fd), closedir); 150 if (d2 == 0) { 151 close(fd); 152 } else { 153 if (RegenerateUeventsForDir(d2.get(), callback) == ListenerAction::kStop) { 154 return ListenerAction::kStop; 155 } 156 } 157 } 158 159 // default is always to continue looking for uevents 160 return ListenerAction::kContinue; 161} 162 163ListenerAction UeventListener::RegenerateUeventsForPath(const std::string& path, 164 const ListenerCallback& callback) const { 165 std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path.c_str()), closedir); 166 if (!d) return ListenerAction::kContinue; 167 168 return RegenerateUeventsForDir(d.get(), callback); 169} 170 171static const char* kRegenerationPaths[] = {"/sys/class", "/sys/block", "/sys/devices"}; 172 173void UeventListener::RegenerateUevents(const ListenerCallback& callback) const { 174 for (const auto path : kRegenerationPaths) { 175 if (RegenerateUeventsForPath(path, callback) == ListenerAction::kStop) return; 176 } 177} 178 179void UeventListener::Poll(const ListenerCallback& callback, 180 const std::optional<std::chrono::milliseconds> relative_timeout) const { 181 using namespace std::chrono; 182 183 pollfd ufd; 184 ufd.events = POLLIN; 185 ufd.fd = device_fd_; 186 187 auto start_time = steady_clock::now(); 188 189 while (true) { 190 ufd.revents = 0; 191 192 int timeout_ms = -1; 193 if (relative_timeout) { 194 auto now = steady_clock::now(); 195 auto time_elapsed = duration_cast<milliseconds>(now - start_time); 196 if (time_elapsed > *relative_timeout) return; 197 198 auto remaining_timeout = *relative_timeout - time_elapsed; 199 timeout_ms = remaining_timeout.count(); 200 } 201 202 int nr = poll(&ufd, 1, timeout_ms); 203 if (nr == 0) return; 204 if (nr < 0) { 205 PLOG(ERROR) << "poll() of uevent socket failed, continuing"; 206 continue; 207 } 208 if (ufd.revents & POLLIN) { 209 // We're non-blocking, so if we receive a poll event keep processing until 210 // we have exhausted all uevent messages. 211 Uevent uevent; 212 while (ReadUevent(&uevent)) { 213 if (callback(uevent) == ListenerAction::kStop) return; 214 } 215 } 216 } 217} 218 219} // namespace init 220} // namespace android 221