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
IsComplete()28 static 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
PollUeventdSocketTimeout(int ueventSockFd,bool ondemand)48 static 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
UeventdRetrigger(void)75 static int UeventdRetrigger(void)
76 {
77 const char *ueventdConfigs[] = {"/etc/ueventd.config", "/vendor/etc/ueventd.config",
78 "/vendor/etc/ueventd_factory.config", NULL};
79 int i = 0;
80 while (ueventdConfigs[i] != NULL) {
81 ParseUeventdConfigFile(ueventdConfigs[i++]);
82 }
83 int ueventSockFd = UeventdSocketInit();
84 if (ueventSockFd < 0) {
85 INIT_LOGE("Failed to create uevent socket!");
86 return -1;
87 }
88 RetriggerUevent(ueventSockFd, NULL, 0); // Not require boot devices
89 return 0;
90 }
91
UeventdDaemon(int listen_only)92 static int UeventdDaemon(int listen_only)
93 {
94 // start log
95 EnableInitLog(INIT_INFO);
96 const char *ueventdConfigs[] = {"/etc/ueventd.config", "/vendor/etc/ueventd.config",
97 "/vendor/etc/ueventd_factory.config", NULL};
98 int i = 0;
99 while (ueventdConfigs[i] != NULL) {
100 ParseUeventdConfigFile(ueventdConfigs[i++]);
101 }
102 bool ondemand = true;
103 int ueventSockFd = GetControlSocket("ueventd");
104 if (ueventSockFd < 0) {
105 INIT_LOGW("Failed to get uevent socket, try to create");
106 ueventSockFd = UeventdSocketInit();
107 ondemand = false;
108 }
109 if (ueventSockFd < 0) {
110 INIT_LOGE("Failed to create uevent socket!");
111 return -1;
112 }
113 if (!listen_only && access(UEVENTD_FLAG, F_OK)) {
114 INIT_LOGI("Ueventd started, trigger uevent");
115 RetriggerUevent(ueventSockFd, NULL, 0); // Not require boot devices
116 int fd = open(UEVENTD_FLAG, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
117 if (fd < 0) {
118 INIT_LOGE("Failed to create ueventd flag!");
119 return -1;
120 }
121 (void)close(fd);
122 } else {
123 INIT_LOGI("ueventd start to process uevent message");
124 ProcessUevent(ueventSockFd, NULL, 0); // Not require boot devices
125 }
126 PollUeventdSocketTimeout(ueventSockFd, ondemand);
127 CloseUeventConfig();
128 return 0;
129 }
130
UeventdEarlyBoot(void)131 static int UeventdEarlyBoot(void)
132 {
133 int ueventSockFd = UeventdSocketInit();
134 if (ueventSockFd < 0) {
135 return -1;
136 }
137
138 char *devices[] = {
139 "/dev/block/vdb",
140 "/dev/block/vdc"
141 };
142
143 RetriggerUevent(ueventSockFd, devices, 2);
144 close(ueventSockFd);
145 return 0;
146 }
147
148 #define UEVENTD_MODE_DEAMON 0
149 #define UEVENTD_MODE_EARLY_BOOT 1
150 #define UEVENTD_MODE_RETRIGGER 2
151 #define UEVENTD_MODE_LISTEN 3
152
usage(const char * name)153 static void usage(const char *name)
154 {
155 if (name == NULL || strlen(name) > PROCESS_NAME_MAX_LENGTH) {
156 return ;
157 }
158 printf("Usage: %s [OPTION]\n"
159 "Listening kernel uevent to create device node.\n"
160 "It will read configs from {/,/system,/chipset}/etc/ueventd.config.\n\n"
161 "The options may be used to set listening mode.\n"
162 " -d, --daemon working in deamon mode(default mode)\n"
163 " -b, --boot working in early booting mode, create required device nodes\n"
164 " -l, --listen listen in verbose mode\n"
165 " -r, --retrigger retrigger all uevents\n"
166 " -v, --verbose log level\n"
167 " -h, --help print this help info\n", name);
168 }
169
UeventdLogPrint(int logLevel,uint32_t domain,const char * tag,const char * fmt,va_list vargs)170 static void UeventdLogPrint(int logLevel, uint32_t domain, const char *tag, const char *fmt, va_list vargs)
171 {
172 if (logLevel < (int)GetInitLogLevel()) {
173 return;
174 }
175 vprintf(fmt, vargs);
176 printf("\n");
177 }
178
main(int argc,char * argv[])179 int main(int argc, char *argv[])
180 {
181 int opt;
182 int daemon = UEVENTD_MODE_DEAMON;
183
184 while ((opt = getopt(argc, argv, "drblv:h")) != -1) {
185 switch (opt) {
186 case 'd':
187 daemon = UEVENTD_MODE_DEAMON;
188 break;
189 case 'r':
190 SetInitCommLog(UeventdLogPrint);
191 daemon = UEVENTD_MODE_RETRIGGER;
192 break;
193 case 'b':
194 SetInitCommLog(UeventdLogPrint);
195 daemon = UEVENTD_MODE_EARLY_BOOT;
196 break;
197 case 'v':
198 EnableInitLog(atoi(optarg));
199 SetInitCommLog(UeventdLogPrint);
200 break;
201 case 'l':
202 EnableInitLog(0);
203 SetInitCommLog(UeventdLogPrint);
204 daemon = UEVENTD_MODE_LISTEN;
205 break;
206 case 'h':
207 usage(argv[0]);
208 exit(0);
209 break;
210 default: /* '?' */
211 fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\n",
212 argv[0]);
213 exit(EXIT_FAILURE);
214 }
215 }
216
217 if (daemon == UEVENTD_MODE_DEAMON) {
218 return UeventdDaemon(0);
219 } else if (daemon == UEVENTD_MODE_RETRIGGER) {
220 return UeventdRetrigger();
221 } else if (daemon == UEVENTD_MODE_LISTEN) {
222 return UeventdDaemon(1);
223 } else {
224 UeventdEarlyBoot();
225 }
226
227 return 0;
228 }
229