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