1/*
2 * Copyright (c) 2021-2022 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#include "init_param.h"
16
17#include <errno.h>
18#include <stddef.h>
19#include <string.h>
20#include <sys/socket.h>
21#include <unistd.h>
22
23#include "init_log.h"
24#include "init_utils.h"
25#include "param_atomic.h"
26#include "param_manager.h"
27#include "param_message.h"
28#include "param_security.h"
29
30#define INVALID_SOCKET (-1)
31static const uint32_t RECV_BUFFER_MAX = 5 * 1024;
32static ATOMIC_UINT32 g_requestId;
33static int g_clientFd = INVALID_SOCKET;
34static pthread_mutex_t g_clientMutex = PTHREAD_MUTEX_INITIALIZER;
35
36__attribute__((constructor)) static void ParameterInit(void)
37{
38    ATOMIC_INIT(&g_requestId, 1);
39    EnableInitLog(INIT_INFO);
40
41    PARAM_WORKSPACE_OPS ops = {0};
42    ops.updaterMode = 0;
43    ops.logFunc = InitLog;
44#ifdef PARAM_SUPPORT_SELINUX
45    ops.setfilecon = NULL;
46#endif
47    InitParamWorkSpace(1, &ops);
48
49    // modify log level
50    char logLevel[2] = {0}; // 2 is set param "persist.init.debug.loglevel" value length.
51    uint32_t len = sizeof(logLevel);
52    int ret = SystemReadParam(INIT_DEBUG_LEVEL, logLevel, &len);
53    if (ret == 0) {
54        errno = 0;
55        int level = atoi(logLevel);
56        if (errno != 0) {
57            return;
58        }
59        SetInitLogLevel((InitLogLevel)level);
60    }
61}
62
63__attribute__((destructor)) static void ParameterDeinit(void)
64{
65    if (g_clientFd != INVALID_SOCKET) {
66        close(g_clientFd);
67        g_clientFd = INVALID_SOCKET;
68    }
69    pthread_mutex_destroy(&g_clientMutex);
70}
71
72static int ProcessRecvMsg(const ParamMessage *recvMsg)
73{
74    PARAM_LOGV("ProcessRecvMsg type: %u msgId: %u name %s", recvMsg->type, recvMsg->id.msgId, recvMsg->key);
75    int result = PARAM_CODE_INVALID_PARAM;
76    switch (recvMsg->type) {
77        case MSG_SET_PARAM:
78        case MSG_SAVE_PARAM:
79            result = ((ParamResponseMessage *)recvMsg)->result;
80            break;
81        case MSG_NOTIFY_PARAM: {
82            uint32_t offset = 0;
83            ParamMsgContent *valueContent = GetNextContent(recvMsg, &offset);
84            PARAM_CHECK(valueContent != NULL, return PARAM_CODE_TIMEOUT, "Invalid msg");
85            result = 0;
86            break;
87        }
88        default:
89            break;
90    }
91    return result;
92}
93
94static int ReadMessage(int fd, char *buffer, uint32_t timeout)
95{
96    int ret = 0;
97    uint32_t diff = 0;
98    struct timespec startTime = {0};
99    (void)clock_gettime(CLOCK_MONOTONIC, &startTime);
100    do {
101        ssize_t recvLen = recv(fd, (char *)buffer, RECV_BUFFER_MAX, 0);
102        if (recvLen <= 0) {
103            PARAM_LOGE("ReadMessage failed! errno %d", errno);
104            struct timespec finishTime = {0};
105            (void)clock_gettime(CLOCK_MONOTONIC, &finishTime);
106            diff = IntervalTime(&finishTime, &startTime);
107            if (diff >= timeout) {
108                ret = PARAM_CODE_TIMEOUT;
109                break;
110            }
111            if (errno == EAGAIN || errno == EINTR) {
112                usleep(10*1000); // 10*1000 wait 10ms
113                continue;
114            }
115        }
116
117        if ((size_t)recvLen > sizeof(ParamMessage)) {
118            PARAM_LOGV("recv message len is %d", recvLen);
119            break;
120        }
121    } while (1);
122
123    if (ret != 0) {
124        PARAM_LOGE("ReadMessage errno %d diff %u timeout %d ret %d", errno, diff, timeout, ret);
125    }
126    return ret;
127}
128
129static int GetClientSocket(int timeout)
130{
131    struct timeval time = {0};
132    time.tv_sec = timeout;
133    time.tv_usec = 0;
134    int clientFd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
135    PARAM_CHECK(clientFd >= 0, return INVALID_SOCKET, "Failed to create socket");
136    int ret = ConnectServer(clientFd, CLIENT_PIPE_NAME);
137    if (ret == 0) {
138        setsockopt(clientFd, SOL_SOCKET, SO_SNDTIMEO, (char *)&time, sizeof(struct timeval));
139        setsockopt(clientFd, SOL_SOCKET, SO_RCVTIMEO, (char *)&time, sizeof(struct timeval));
140    } else {
141        close(clientFd);
142        clientFd = INVALID_SOCKET;
143    }
144    return clientFd;
145}
146
147static int StartRequest(int clientFd, ParamMessage *request, int timeout)
148{
149    errno = 0;
150    ssize_t sendLen = send(clientFd, (char *)request, request->msgSize, 0);
151    if (errno == EINVAL || errno == EACCES) {
152        PARAM_LOGE("send Message failed!");
153        return PARAM_CODE_IPC_ERROR;
154    }
155    PARAM_CHECK(sendLen >= 0, return PARAM_CODE_IPC_ERROR, "Failed to send message err: %d", errno);
156    PARAM_LOGV("sendMessage sendLen fd %d %zd", clientFd, sendLen);
157    if (timeout <= 0) {
158        return 0;
159    }
160    int ret = ReadMessage(clientFd, (char *)request, timeout);
161    if (ret == 0) {
162        ret = ProcessRecvMsg(request);
163    }
164    return ret;
165}
166
167static int SystemSetParameter_(const char *name, const char *value, int timeout)
168{
169    PARAM_CHECK(name != NULL && value != NULL, return -1, "Invalid name or value");
170    int ret = CheckParamName(name, 0);
171    PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name);
172    ret = CheckParamValue(NULL, name, value, GetParamValueType(name));
173    PARAM_CHECK(ret == 0, return ret, "Illegal param value %s", value);
174
175    size_t msgSize = sizeof(ParamMsgContent);
176    msgSize = (msgSize < RECV_BUFFER_MAX) ? RECV_BUFFER_MAX : msgSize;
177
178    ParamMessage *request = (ParamMessage *)CreateParamMessage(MSG_SET_PARAM, name, msgSize);
179    PARAM_CHECK(request != NULL, return PARAM_CODE_ERROR, "Failed to create Param Message");
180    uint32_t offset = 0;
181    ret = FillParamMsgContent(request, &offset, PARAM_VALUE, value, strlen(value));
182    PARAM_CHECK(ret == 0, free(request);
183        return PARAM_CODE_ERROR, "Failed to fill value");
184    request->msgSize = offset + sizeof(ParamMessage);
185    request->id.msgId = ATOMIC_SYNC_ADD_AND_FETCH(&g_requestId, 1, MEMORY_ORDER_RELAXED);
186
187    pthread_mutex_lock(&g_clientMutex);
188    int retryCount = 0;
189    while (retryCount < 2) { // max retry 2
190        if (g_clientFd == INVALID_SOCKET) {
191            g_clientFd = GetClientSocket(DEFAULT_PARAM_SET_TIMEOUT);
192        }
193
194        if (g_clientFd < 0) {
195            ret = PARAM_CODE_FAIL_CONNECT;
196            PARAM_LOGE("connect param server failed!");
197            break;
198        }
199        ret = StartRequest(g_clientFd, request, timeout);
200        if (ret == PARAM_CODE_IPC_ERROR) {
201            close(g_clientFd);
202            g_clientFd = INVALID_SOCKET;
203            retryCount++;
204        } else {
205            break;
206        }
207    }
208    PARAM_LOGI("SystemSetParameter name %s msgid:%d  ret: %d ", name, request->id.msgId, ret);
209    pthread_mutex_unlock(&g_clientMutex);
210    free(request);
211    return ret;
212}
213
214int SystemSetParameter(const char *name, const char *value)
215{
216    int ret = SystemSetParameter_(name, value, DEFAULT_PARAM_SET_TIMEOUT);
217    BEGET_CHECK_ONLY_ELOG(ret == 0, "SystemSetParameter failed! name is :%s, the errNum is:%d", name, ret);
218    return ret;
219}
220
221int SystemSetParameterNoWait(const char *name, const char *value)
222{
223    int ret = SystemSetParameter_(name, value, 0);
224    BEGET_CHECK_ONLY_ELOG(ret == 0, "SystemSetParameterNoWait failed! name is:%s, the errNum is:%d", name, ret);
225    return ret;
226}
227
228int SystemSaveParameters(void)
229{
230    const char *name = "persist.all";
231    size_t msgSize = RECV_BUFFER_MAX;
232    uint32_t offset = 0;
233    ParamMessage *request = (ParamMessage *)CreateParamMessage(MSG_SAVE_PARAM, name, msgSize);
234    PARAM_CHECK(request != NULL, return -1, "SystemSaveParameters failed! name is:%s, the errNum is:-1", name);
235    int ret = FillParamMsgContent(request, &offset, PARAM_VALUE, "*", 1);
236    PARAM_CHECK(ret == 0, free(request);
237        return -1, "SystemSaveParameters failed! the errNum is:-1");
238    int fd = GetClientSocket(DEFAULT_PARAM_WAIT_TIMEOUT);
239    PARAM_CHECK(fd >= 0, free(request);
240        return fd, "SystemSaveParameters failed! the errNum is:%d", ret);
241    request->msgSize = offset + sizeof(ParamMessage);
242    request->id.msgId = ATOMIC_SYNC_ADD_AND_FETCH(&g_requestId, 1, MEMORY_ORDER_RELAXED);
243    ret = StartRequest(fd, request, DEFAULT_PARAM_WAIT_TIMEOUT);
244    close(fd);
245    free(request);
246    BEGET_CHECK_ONLY_ELOG(ret == 0, "SystemSaveParameters failed! the errNum is:%d", ret);
247    return ret;
248}
249
250int SystemWaitParameter(const char *name, const char *value, int32_t timeout)
251{
252    PARAM_CHECK(name != NULL, return -1, "SystemWaitParameter failed! name is:%s, the errNum is:-1", name);
253    int ret = CheckParamName(name, 0);
254    PARAM_CHECK(ret == 0, return ret, "SystemWaitParameter failed! name is:%s, the errNum is:%d", name, ret);
255    ret = CheckParamPermission(GetParamSecurityLabel(), name, DAC_READ);
256    PARAM_CHECK(ret == 0, return ret, "SystemWaitParameter failed! name is:%s, the errNum is:%d", name, ret);
257    if (timeout <= 0) {
258        timeout = DEFAULT_PARAM_WAIT_TIMEOUT;
259    }
260    uint32_t msgSize = sizeof(ParamMessage) + sizeof(ParamMsgContent) + sizeof(ParamMsgContent) + sizeof(uint32_t);
261    msgSize = (msgSize < RECV_BUFFER_MAX) ? RECV_BUFFER_MAX : msgSize;
262    uint32_t offset = 0;
263    ParamMessage *request = NULL;
264    if (value != NULL && strlen(value) > 0) {
265        msgSize += PARAM_ALIGN(strlen(value) + 1);
266        request = (ParamMessage *)CreateParamMessage(MSG_WAIT_PARAM, name, msgSize);
267        PARAM_CHECK(request != NULL, return -1, "SystemWaitParameter failed! name is:%s, the errNum is:-1", name);
268        ret = FillParamMsgContent(request, &offset, PARAM_VALUE, value, strlen(value));
269    } else {
270        msgSize += PARAM_ALIGN(1);
271        request = (ParamMessage *)CreateParamMessage(MSG_WAIT_PARAM, name, msgSize);
272        PARAM_CHECK(request != NULL, return -1, "SystemWaitParameter failed! name is:%s, the errNum is:-1", name);
273        ret = FillParamMsgContent(request, &offset, PARAM_VALUE, "*", 1);
274    }
275    PARAM_CHECK(ret == 0, free(request);
276        return -1, "SystemWaitParameter failed! name is:%s, the errNum is:-1", name);
277    ParamMsgContent *content = (ParamMsgContent *)(request->data + offset);
278    content->type = PARAM_WAIT_TIMEOUT;
279    content->contentSize = sizeof(uint32_t);
280    *((uint32_t *)(content->content)) = timeout;
281    offset += sizeof(ParamMsgContent) + sizeof(uint32_t);
282
283    request->msgSize = offset + sizeof(ParamMessage);
284    request->id.waitId = ATOMIC_SYNC_ADD_AND_FETCH(&g_requestId, 1, MEMORY_ORDER_RELAXED);
285#ifdef STARTUP_INIT_TEST
286    timeout = 1;
287#endif
288    int fd = GetClientSocket(timeout);
289    PARAM_CHECK(fd >= 0, free(request);
290        return fd, "SystemWaitParameter failed! name is:%s, the errNum is:%d", name, ret);
291    ret = StartRequest(fd, request, timeout);
292    close(fd);
293    free(request);
294    PARAM_LOGI("SystemWaitParameter %s value %s result %d ", name, value, ret);
295    BEGET_CHECK_ONLY_ELOG(ret == 0, "SystemWaitParameter failed! name is:%s, the errNum is:%d", name, ret);
296    return ret;
297}
298
299int SystemCheckParamExist(const char *name)
300{
301    return SysCheckParamExist(name);
302}
303
304int WatchParamCheck(const char *keyprefix)
305{
306    PARAM_CHECK(keyprefix != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid keyprefix");
307    int ret = CheckParamName(keyprefix, 0);
308    PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", keyprefix);
309    ret = CheckParamPermission(GetParamSecurityLabel(), keyprefix, DAC_WATCH);
310    PARAM_CHECK(ret == 0, return ret, "Forbid to watcher parameter %s", keyprefix);
311    return 0;
312}
313
314void ResetParamSecurityLabel(void)
315{
316#ifdef RESET_CHILD_FOR_VERIFY
317    ParamWorkSpace *paramSpace = GetParamWorkSpace();
318    PARAM_CHECK(paramSpace != NULL, return, "Invalid paramSpace");
319#if !(defined __LITEOS_A__ || defined __LITEOS_M__)
320    paramSpace->securityLabel.cred.pid = getpid();
321    paramSpace->securityLabel.cred.uid = geteuid();
322    paramSpace->securityLabel.cred.gid = getegid();
323    paramSpace->flags |= WORKSPACE_FLAGS_NEED_ACCESS;
324#endif
325#endif
326    PARAM_LOGI("ResetParamSecurityLabel g_clientFd: %d ", g_clientFd);
327    pthread_mutex_lock(&g_clientMutex);
328    if (g_clientFd != INVALID_SOCKET) {
329        close(g_clientFd);
330        g_clientFd = INVALID_SOCKET;
331    }
332    pthread_mutex_unlock(&g_clientMutex);
333}
334