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
IsCompletenull28 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", 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
UeventdDaemon(int listen_only)91 static 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
UeventdEarlyBoot(void)129 static 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
usage(const char *name)151 static 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
UeventdLogPrint(int logLevel, uint32_t domain, const char *tag, const char *fmt, va_list vargs)168 static 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
main(int argc, char *argv[])177 int 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