1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include <limits.h> 17#include <poll.h> 18#include <unistd.h> 19#include <stdbool.h> 20#include "ueventd.h" 21#include "ueventd_read_cfg.h" 22#include "ueventd_socket.h" 23#define INIT_LOG_TAG "ueventd" 24#include "init_log.h" 25#include "init_socket.h" 26#include "parameter.h" 27 28static bool IsComplete() 29{ 30 static bool complete = false; 31 if (complete) { 32 return true; 33 } 34 char enable[8] = {0}; 35 int ret = GetParameter("bootevent.boot.completed", "", enable, sizeof(enable)); 36 if (ret != 0) { 37 INIT_LOGE("Failed to get param value"); 38 return false; 39 } 40 if (strcmp(enable, "true") == 0) { 41 INIT_LOGI("boot completed"); 42 complete = true; 43 return true; 44 } 45 return false; 46} 47 48static void PollUeventdSocketTimeout(int ueventSockFd, bool ondemand) 49{ 50 struct pollfd pfd = {}; 51 pfd.events = POLLIN; 52 pfd.fd = ueventSockFd; 53 int timeout = ondemand ? UEVENTD_POLL_TIME : -1; 54 int ret = -1; 55 56 while (1) { 57 pfd.revents = 0; 58 ret = poll(&pfd, 1, timeout); 59 if (ret == 0) { 60 if (IsComplete()) { 61 INIT_LOGI("poll ueventd socket timeout, ueventd exit"); 62 return; 63 } 64 INIT_LOGI("poll ueventd socket timeout, but init not complete"); 65 } else if (ret < 0) { 66 INIT_LOGE("Failed to poll ueventd socket!"); 67 return; 68 } 69 if (pfd.revents & (POLLIN | POLLERR)) { 70 ProcessUevent(ueventSockFd, NULL, 0); // Not require boot devices 71 } 72 } 73} 74 75static int UeventdRetrigger(void) 76{ 77 const char *ueventdConfigs[] = {"/etc/ueventd.config", "/vendor/etc/ueventd.config", NULL}; 78 int i = 0; 79 while (ueventdConfigs[i] != NULL) { 80 ParseUeventdConfigFile(ueventdConfigs[i++]); 81 } 82 int ueventSockFd = UeventdSocketInit(); 83 if (ueventSockFd < 0) { 84 INIT_LOGE("Failed to create uevent socket!"); 85 return -1; 86 } 87 RetriggerUevent(ueventSockFd, NULL, 0); // Not require boot devices 88 return 0; 89} 90 91static int UeventdDaemon(int listen_only) 92{ 93 // start log 94 EnableInitLog(INIT_INFO); 95 const char *ueventdConfigs[] = {"/etc/ueventd.config", "/vendor/etc/ueventd.config", NULL}; 96 int i = 0; 97 while (ueventdConfigs[i] != NULL) { 98 ParseUeventdConfigFile(ueventdConfigs[i++]); 99 } 100 bool ondemand = true; 101 int ueventSockFd = GetControlSocket("ueventd"); 102 if (ueventSockFd < 0) { 103 INIT_LOGW("Failed to get uevent socket, try to create"); 104 ueventSockFd = UeventdSocketInit(); 105 ondemand = false; 106 } 107 if (ueventSockFd < 0) { 108 INIT_LOGE("Failed to create uevent socket!"); 109 return -1; 110 } 111 if (!listen_only && access(UEVENTD_FLAG, F_OK)) { 112 INIT_LOGI("Ueventd started, trigger uevent"); 113 RetriggerUevent(ueventSockFd, NULL, 0); // Not require boot devices 114 int fd = open(UEVENTD_FLAG, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 115 if (fd < 0) { 116 INIT_LOGE("Failed to create ueventd flag!"); 117 return -1; 118 } 119 (void)close(fd); 120 } else { 121 INIT_LOGI("ueventd start to process uevent message"); 122 ProcessUevent(ueventSockFd, NULL, 0); // Not require boot devices 123 } 124 PollUeventdSocketTimeout(ueventSockFd, ondemand); 125 CloseUeventConfig(); 126 return 0; 127} 128 129static int UeventdEarlyBoot(void) 130{ 131 int ueventSockFd = UeventdSocketInit(); 132 if (ueventSockFd < 0) { 133 return -1; 134 } 135 136 char *devices[] = { 137 "/dev/block/vdb", 138 "/dev/block/vdc" 139 }; 140 141 RetriggerUevent(ueventSockFd, devices, 2); 142 close(ueventSockFd); 143 return 0; 144} 145 146#define UEVENTD_MODE_DEAMON 0 147#define UEVENTD_MODE_EARLY_BOOT 1 148#define UEVENTD_MODE_RETRIGGER 2 149#define UEVENTD_MODE_LISTEN 3 150 151static void usage(const char *name) 152{ 153 if (name == NULL || strlen(name) > PROCESS_NAME_MAX_LENGTH) { 154 return ; 155 } 156 printf("Usage: %s [OPTION]\n" 157 "Listening kernel uevent to create device node.\n" 158 "It will read configs from {/,/system,/chipset}/etc/ueventd.config.\n\n" 159 "The options may be used to set listening mode.\n" 160 " -d, --daemon working in deamon mode(default mode)\n" 161 " -b, --boot working in early booting mode, create required device nodes\n" 162 " -l, --listen listen in verbose mode\n" 163 " -r, --retrigger retrigger all uevents\n" 164 " -v, --verbose log level\n" 165 " -h, --help print this help info\n", name); 166} 167 168static void UeventdLogPrint(int logLevel, uint32_t domain, const char *tag, const char *fmt, va_list vargs) 169{ 170 if (logLevel < (int)GetInitLogLevel()) { 171 return; 172 } 173 vprintf(fmt, vargs); 174 printf("\n"); 175} 176 177int main(int argc, char *argv[]) 178{ 179 int opt; 180 int daemon = UEVENTD_MODE_DEAMON; 181 182 while ((opt = getopt(argc, argv, "drblv:h")) != -1) { 183 switch (opt) { 184 case 'd': 185 daemon = UEVENTD_MODE_DEAMON; 186 break; 187 case 'r': 188 SetInitCommLog(UeventdLogPrint); 189 daemon = UEVENTD_MODE_RETRIGGER; 190 break; 191 case 'b': 192 SetInitCommLog(UeventdLogPrint); 193 daemon = UEVENTD_MODE_EARLY_BOOT; 194 break; 195 case 'v': 196 EnableInitLog(atoi(optarg)); 197 SetInitCommLog(UeventdLogPrint); 198 break; 199 case 'l': 200 EnableInitLog(0); 201 SetInitCommLog(UeventdLogPrint); 202 daemon = UEVENTD_MODE_LISTEN; 203 break; 204 case 'h': 205 usage(argv[0]); 206 exit(0); 207 break; 208 default: /* '?' */ 209 fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\n", 210 argv[0]); 211 exit(EXIT_FAILURE); 212 } 213 } 214 215 if (daemon == UEVENTD_MODE_DEAMON) { 216 return UeventdDaemon(0); 217 } else if (daemon == UEVENTD_MODE_RETRIGGER) { 218 return UeventdRetrigger(); 219 } else if (daemon == UEVENTD_MODE_LISTEN) { 220 return UeventdDaemon(1); 221 } else { 222 UeventdEarlyBoot(); 223 } 224 225 return 0; 226} 227