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 <ctype.h>
17#include <errno.h>
18#include <fcntl.h>
19#include <time.h>
20#include <unistd.h>
21
22#include "init_utils.h"
23#include "param_manager.h"
24#include "param_persist.h"
25#include "param_utils.h"
26#include "securec.h"
27#include "utils_file.h"
28
29// for linux, no mutex
30static ParamMutex g_saveMutex = {0};
31#ifdef PARAM_SUPPORT_POSIX
32#define MODE_READ O_RDONLY
33#define MODE_APPEND (O_RDWR | O_CREAT | O_APPEND)
34#define MODE_CREATE (O_RDWR | O_CREAT | O_TRUNC)
35#else
36#define MODE_READ O_RDONLY_FS
37#define MODE_APPEND (O_RDWR_FS | O_CREAT_FS | O_APPEND_FS)
38#define MODE_CREATE (O_RDWR_FS | O_CREAT_FS | O_TRUNC_FS)
39#endif
40
41static int ParamFileOpen(const char* path, int oflag, int mode)
42{
43#ifdef PARAM_SUPPORT_POSIX
44    return open(path, oflag, mode);
45#else
46    return UtilsFileOpen(path, oflag, mode);
47#endif
48}
49
50static int ParamFileClose(int fd)
51{
52#ifdef PARAM_SUPPORT_POSIX
53    return close(fd);
54#else
55    return UtilsFileClose(fd);
56#endif
57}
58
59static int ParamFileRead(int fd, char* buf, unsigned int len)
60{
61#ifdef PARAM_SUPPORT_POSIX
62    return read(fd, buf, len);
63#else
64    return UtilsFileRead(fd, buf, len);
65#endif
66}
67
68static int ParamFileWrite(int fd, const char* buf, unsigned int len)
69{
70#ifdef PARAM_SUPPORT_POSIX
71    return write(fd, buf, len);
72#else
73    return UtilsFileWrite(fd, buf, len);
74#endif
75}
76
77static int ParamFileDelete(const char* path)
78{
79#ifdef PARAM_SUPPORT_POSIX
80    return unlink(path);
81#else
82    return UtilsFileDelete(path);
83#endif
84}
85
86static int ParamFileStat(const char* path, unsigned int* fileSize)
87{
88#ifdef PARAM_SUPPORT_POSIX
89    int fd = open(path, O_RDONLY);
90    if (fd < 0) {
91        return -1;
92    }
93	*fileSize = lseek(fd, 0, SEEK_END);
94    lseek(fd, 0, SEEK_SET);
95    close(fd);
96    return 0;
97#else
98    return UtilsFileStat(path, fileSize);
99#endif
100}
101
102static void ParamFileSync(int ft)
103{
104#ifdef PARAM_SUPPORT_POSIX
105    fsync(ft);
106#else
107    (void)ft;
108#endif
109}
110
111static int LoadOnePersistParam_(const uint32_t *context, const char *name, const char *value)
112{
113    (void)context;
114    uint32_t dataIndex = 0;
115    int ret = WriteParam(name, value, &dataIndex, 0);
116    PARAM_CHECK(ret == 0, return ret, "Failed to write param %d name:%s %s", ret, name, value);
117    return 0;
118}
119
120static int LoadPersistParam(void)
121{
122    const char *path = PARAM_PERSIST_SAVE_TMP_PATH;
123    CheckAndCreateDir(path);
124    char *buffer = NULL;
125    int fd = -1;
126    uint32_t paramNum = 0;
127    do {
128        fd = ParamFileOpen(path, MODE_READ, 0);
129        if (fd < 0) {
130            path = PARAM_PERSIST_SAVE_PATH;
131            fd = ParamFileOpen(path, MODE_READ, 0);
132            PARAM_LOGI("LoadPersistParam open file %s", path);
133        }
134        PARAM_CHECK(fd >= 0, break, "No valid persist parameter file %s", path);
135        // read file
136        uint32_t fileSize = 0;
137        int ret = ParamFileStat(path, &fileSize);
138        PARAM_CHECK(ret == 0, break, "Failed to get file state %s", path);
139        buffer = calloc(fileSize, sizeof(char));
140        PARAM_CHECK(buffer != NULL, break, "Failed to get file");
141        ret = ParamFileRead(fd, buffer, fileSize);
142        PARAM_CHECK(ret >= 0, break, "Failed to read file %s", path);
143
144        uint32_t currLen = 0;
145        char *tmp = buffer;
146        while (currLen < fileSize) {
147            if (buffer[currLen] == '\n') { // split line
148                buffer[currLen] = '\0';
149                ret = SplitParamString(tmp, NULL, 0, LoadOnePersistParam_, NULL);
150                PARAM_CHECK(ret == 0, continue, "Failed to set param %d %s", ret, buffer);
151                paramNum++;
152                if (currLen + 1 >= fileSize) {
153                    break;
154                }
155                tmp = buffer + currLen + 1;
156            }
157            currLen++;
158        }
159    } while (0);
160    if (fd > 0) {
161        ParamFileClose(fd);
162    }
163    if (buffer != NULL) {
164        free(buffer);
165    }
166    PARAM_LOGI("LoadPersistParam paramNum %d", paramNum);
167    return 0;
168}
169
170static int PersistWrite(int fd, const char *name, const char *value)
171{
172    int ret = ParamFileWrite(fd, name, strlen(name));
173    if (ret <= 0) {
174        PARAM_LOGE("Failed to save persist param %s", name);
175    }
176    ret = ParamFileWrite(fd, "=", strlen("="));
177    if (ret <= 0) {
178        PARAM_LOGE("Failed to save persist param %s", name);
179    }
180    ret = ParamFileWrite(fd, value, strlen(value));
181    if (ret <= 0) {
182        PARAM_LOGE("Failed to save persist param %s", name);
183    }
184    ret = ParamFileWrite(fd, "\n", strlen("\n"));
185    if (ret <= 0) {
186        PARAM_LOGE("Failed to save persist param %s", name);
187    }
188    return 0;
189}
190
191static int SavePersistParam(const char *name, const char *value)
192{
193    ParamMutexPend(&g_saveMutex);
194    int ret = -1;
195    int fd = ParamFileOpen(PARAM_PERSIST_SAVE_PATH, MODE_APPEND, 0);
196    if (fd > 0) {
197        ret = PersistWrite(fd, name, value);
198        ParamFileSync(fd);
199        ParamFileClose(fd);
200    }
201    if (ret != 0) {
202        PARAM_LOGE("SavePersistParam %s errno %d", name, errno);
203    }
204    ParamMutexPost(&g_saveMutex);
205    return ret;
206}
207
208static int BatchSavePersistParamBegin(PERSIST_SAVE_HANDLE *handle)
209{
210    ParamMutexPend(&g_saveMutex);
211    int fd = ParamFileOpen(PARAM_PERSIST_SAVE_PATH, MODE_CREATE, 0);
212    if (fd < 0) {
213        ParamMutexPost(&g_saveMutex);
214        PARAM_LOGE("Open file %s fail error %d", PARAM_PERSIST_SAVE_PATH, errno);
215        return -1;
216    }
217    *handle = (PERSIST_SAVE_HANDLE)fd;
218    return 0;
219}
220
221static int BatchSavePersistParam(PERSIST_SAVE_HANDLE handle, const char *name, const char *value)
222{
223    int fd = (int)handle;
224    int ret = PersistWrite(fd, name, value);
225    PARAM_CHECK(ret == 0, return -1, "Failed to write param %s", name);
226    PARAM_LOGV("BatchSavePersistParam %s=%s", name, value);
227    return 0;
228}
229
230static void BatchSavePersistParamEnd(PERSIST_SAVE_HANDLE handle)
231{
232    int ret;
233    int fd = (int)handle;
234    ParamFileSync(fd);
235    ret = ParamFileClose(fd);
236    ParamMutexPost(&g_saveMutex);
237    PARAM_CHECK(ret == 0, return, "BatchSavePersistParamEnd fail error %d", errno);
238}
239
240int RegisterPersistParamOps(PersistParamOps *ops)
241{
242    ParamMutexCreate(&g_saveMutex);
243    PARAM_CHECK(ops != NULL, return -1, "Invalid ops");
244    ops->save = SavePersistParam;
245    ops->load = LoadPersistParam;
246    ops->batchSaveBegin = BatchSavePersistParamBegin;
247    ops->batchSave = BatchSavePersistParam;
248    ops->batchSaveEnd = BatchSavePersistParamEnd;
249    return 0;
250}
251