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
PollUeventdSocketTimeout(int ueventSockFd,bool ondemand)27 static void PollUeventdSocketTimeout(int ueventSockFd, bool ondemand)
28 {
29 struct pollfd pfd = {};
30 pfd.events = POLLIN;
31 pfd.fd = ueventSockFd;
32 int timeout = ondemand ? UEVENTD_POLL_TIME : -1;
33 int ret = -1;
34
35 while (1) {
36 pfd.revents = 0;
37 ret = poll(&pfd, 1, timeout);
38 if (ret == 0) {
39 INIT_LOGI("poll ueventd socket timeout, ueventd exit");
40 return;
41 } else if (ret < 0) {
42 INIT_LOGE("Failed to poll ueventd socket!");
43 return;
44 }
45 if (pfd.revents & POLLIN) {
46 ProcessUevent(ueventSockFd, NULL, 0); // Not require boot devices
47 }
48 }
49 }
50
UeventdRetrigger(void)51 static int UeventdRetrigger(void)
52 {
53 const char *ueventdConfigs[] = {"/etc/ueventd.config", "/vendor/etc/ueventd.config", NULL};
54 int i = 0;
55 while (ueventdConfigs[i] != NULL) {
56 ParseUeventdConfigFile(ueventdConfigs[i++]);
57 }
58 int ueventSockFd = UeventdSocketInit();
59 if (ueventSockFd < 0) {
60 INIT_LOGE("Failed to create uevent socket!");
61 return -1;
62 }
63 RetriggerUevent(ueventSockFd, NULL, 0); // Not require boot devices
64 return 0;
65 }
66
UeventdDaemon(int listen_only)67 static int UeventdDaemon(int listen_only)
68 {
69 // start log
70 EnableInitLog(INIT_INFO);
71 const char *ueventdConfigs[] = {"/etc/ueventd.config", "/vendor/etc/ueventd.config", NULL};
72 int i = 0;
73 while (ueventdConfigs[i] != NULL) {
74 ParseUeventdConfigFile(ueventdConfigs[i++]);
75 }
76 bool ondemand = true;
77 int ueventSockFd = GetControlSocket("ueventd");
78 if (ueventSockFd < 0) {
79 INIT_LOGW("Failed to get uevent socket, try to create");
80 ueventSockFd = UeventdSocketInit();
81 ondemand = false;
82 }
83 if (ueventSockFd < 0) {
84 INIT_LOGE("Failed to create uevent socket!");
85 return -1;
86 }
87 if (!listen_only && access(UEVENTD_FLAG, F_OK)) {
88 INIT_LOGI("Ueventd started, trigger uevent");
89 RetriggerUevent(ueventSockFd, NULL, 0); // Not require boot devices
90 int fd = open(UEVENTD_FLAG, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
91 if (fd < 0) {
92 INIT_LOGE("Failed to create ueventd flag!");
93 return -1;
94 }
95 (void)close(fd);
96 } else {
97 INIT_LOGI("ueventd start to process uevent message");
98 ProcessUevent(ueventSockFd, NULL, 0); // Not require boot devices
99 }
100 PollUeventdSocketTimeout(ueventSockFd, ondemand);
101 CloseUeventConfig();
102 return 0;
103 }
104
UeventdEarlyBoot(void)105 static int UeventdEarlyBoot(void)
106 {
107 int ueventSockFd = UeventdSocketInit();
108 if (ueventSockFd < 0) {
109 return -1;
110 }
111
112 char *devices[] = {
113 "/dev/block/vdb",
114 "/dev/block/vdc"
115 };
116
117 RetriggerUevent(ueventSockFd, devices, 2);
118 close(ueventSockFd);
119 return 0;
120 }
121
122 #define UEVENTD_MODE_DEAMON 0
123 #define UEVENTD_MODE_EARLY_BOOT 1
124 #define UEVENTD_MODE_RETRIGGER 2
125 #define UEVENTD_MODE_LISTEN 3
126
usage(const char * name)127 static void usage(const char *name)
128 {
129 printf("Usage: %s [OPTION]\n"
130 "Listening kernel uevent to create device node.\n"
131 "It will read configs from {/,/system,/chipset}/etc/ueventd.config.\n\n"
132 "The options may be used to set listening mode.\n"
133 " -d, --daemon working in deamon mode(default mode)\n"
134 " -b, --boot working in early booting mode, create required device nodes\n"
135 " -l, --listen listen in verbose mode\n"
136 " -r, --retrigger retrigger all uevents\n"
137 " -v, --verbose log level\n"
138 " -h, --help print this help info\n", name);
139 }
140
UeventdLogPrint(int logLevel,uint32_t domain,const char * tag,const char * fmt,va_list vargs)141 static void UeventdLogPrint(int logLevel, uint32_t domain, const char *tag, const char *fmt, va_list vargs)
142 {
143 if (logLevel < GetInitLogLevel()) {
144 return;
145 }
146 vprintf(fmt, vargs);
147 printf("\n");
148 }
149
main(int argc,char * argv[])150 int main(int argc, char *argv[])
151 {
152 int opt;
153 const char *config;
154 int daemon = UEVENTD_MODE_DEAMON;
155
156 while ((opt = getopt(argc, argv, "drblv:h")) != -1) {
157 switch (opt) {
158 case 'd':
159 daemon = UEVENTD_MODE_DEAMON;
160 break;
161 case 'r':
162 SetInitCommLog(UeventdLogPrint);
163 daemon = UEVENTD_MODE_RETRIGGER;
164 break;
165 case 'b':
166 SetInitCommLog(UeventdLogPrint);
167 daemon = UEVENTD_MODE_EARLY_BOOT;
168 break;
169 case 'v':
170 EnableInitLog(atoi(optarg));
171 SetInitCommLog(UeventdLogPrint);
172 break;
173 case 'l':
174 EnableInitLog(0);
175 SetInitCommLog(UeventdLogPrint);
176 daemon = UEVENTD_MODE_LISTEN;
177 break;
178 case 'h':
179 usage(argv[0]);
180 exit(0);
181 break;
182 default: /* '?' */
183 fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\n",
184 argv[0]);
185 exit(EXIT_FAILURE);
186 }
187 }
188
189 config = NULL;
190 if (optind >= argc) {
191 config = argv[optind];
192 }
193
194 if (daemon == UEVENTD_MODE_DEAMON) {
195 return UeventdDaemon(0);
196 } else if (daemon == UEVENTD_MODE_RETRIGGER) {
197 return UeventdRetrigger();
198 } else if (daemon == UEVENTD_MODE_LISTEN) {
199 return UeventdDaemon(1);
200 } else {
201 UeventdEarlyBoot();
202 }
203
204 return 0;
205 }
206