xref: /base/startup/init/ueventd/ueventd_main.c (revision d9f0492f)
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
28static 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
48static 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
75static 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
91static 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
129static 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
151static 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
168static 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
177int 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