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