1/*
2 * Copyright (c) 2024 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 <errno.h>
17#include <time.h>
18#include <unistd.h>
19
20#include "init_utils.h"
21#include "param_manager.h"
22#include "param_persist.h"
23#include "param_utils.h"
24
25// for linux, no mutex
26static ParamMutex g_saveMutex = {};
27
28static int LoadOnePersistParam_(const uint32_t *context, const char *name, const char *value)
29{
30    UNUSED(context);
31    uint32_t dataIndex = 0;
32    return WriteParam(name, value, &dataIndex, 0);
33}
34
35static void LoadPersistParam_(const char *fileName, char *buffer, uint32_t buffSize)
36{
37    FILE *fp = fopen(fileName, "r");
38    PARAM_WARNING_CHECK(fp != NULL, return, "No valid persist parameter file %s", fileName);
39
40    uint32_t paramNum = 0;
41    while (fgets(buffer, buffSize, fp) != NULL) {
42        buffer[buffSize - 1] = '\0';
43        int ret = SplitParamString(buffer, NULL, 0, LoadOnePersistParam_, NULL);
44        PARAM_CHECK(ret == 0, continue, "Failed to set param %d %s", ret, buffer);
45        paramNum++;
46    }
47    (void)fclose(fp);
48    PARAM_LOGI("LoadPersistParam from file %s paramNum %d", fileName, paramNum);
49}
50
51static int LoadPersistParam(void)
52{
53    CheckAndCreateDir(PARAM_PERSIST_SAVE_PATH);
54    const uint32_t buffSize = PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX + 10;  // 10 max len
55    char *buffer = malloc(buffSize);
56    PARAM_CHECK(buffer != NULL, return -1, "Failed to alloc");
57
58    int updaterMode = InUpdaterMode();
59    char *tmpPath = (updaterMode == 0) ? PARAM_PERSIST_SAVE_PATH : "/param/persist_parameters";
60    LoadPersistParam_(tmpPath, buffer, buffSize);
61    tmpPath = (updaterMode == 0) ? PARAM_PERSIST_SAVE_TMP_PATH : "/param/tmp_persist_parameters";
62    LoadPersistParam_(tmpPath, buffer, buffSize);
63    free(buffer);
64    return 0;
65}
66
67static int SavePersistParam(const char *name, const char *value)
68{
69    ParamMutexPend(&g_saveMutex);
70    char *path = (InUpdaterMode() == 0) ? PARAM_PERSIST_SAVE_PATH : "/param/persist_parameters";
71    FILE *fp = fopen(path, "a+");
72    int ret = -1;
73    if (fp != NULL) {
74        ret = fprintf(fp, "%s=%s\n", name, value);
75        (void)fclose(fp);
76    }
77    ParamMutexPost(&g_saveMutex);
78    if (ret <= 0) {
79        PARAM_LOGE("Failed to save persist param %s", name);
80    }
81    return ret;
82}
83
84static int BatchSavePersistParamBegin(PERSIST_SAVE_HANDLE *handle)
85{
86    ParamMutexPend(&g_saveMutex);
87    char *path = (InUpdaterMode() == 0) ? PARAM_PERSIST_SAVE_TMP_PATH : "/param/tmp_persist_parameters";
88    unlink(path);
89    FILE *fp = fopen(path, "w");
90    if (fp == NULL) {
91        ParamMutexPost(&g_saveMutex);
92        PARAM_LOGE("Open file %s fail error %d", path, errno);
93        return -1;
94    }
95    *handle = (PERSIST_SAVE_HANDLE)fp;
96    return 0;
97}
98
99static int BatchSavePersistParam(PERSIST_SAVE_HANDLE handle, const char *name, const char *value)
100{
101    FILE *fp = (FILE *)handle;
102    int ret = fprintf(fp, "%s=%s\n", name, value);
103    PARAM_LOGV("BatchSavePersistParam %s=%s", name, value);
104    return (ret > 0) ? 0 : -1;
105}
106
107static void BatchSavePersistParamEnd(PERSIST_SAVE_HANDLE handle)
108{
109    int ret;
110    FILE *fp = (FILE *)handle;
111    (void)fflush(fp);
112    (void)fsync(fileno(fp));
113    (void)fclose(fp);
114    if (InUpdaterMode() == 0) {
115        unlink(PARAM_PERSIST_SAVE_PATH);
116        ret = rename(PARAM_PERSIST_SAVE_TMP_PATH, PARAM_PERSIST_SAVE_PATH);
117    } else {
118        unlink("/param/persist_parameters");
119        ret = rename("/param/tmp_persist_parameters", "/param/persist_parameters");
120    }
121    ParamMutexPost(&g_saveMutex);
122    PARAM_CHECK(ret == 0, return, "BatchSavePersistParamEnd %s fail error %d", PARAM_PERSIST_SAVE_TMP_PATH, errno);
123}
124
125int RegisterPersistParamOps(PersistParamOps *ops)
126{
127    ParamMutexCreate(&g_saveMutex);
128    PARAM_CHECK(ops != NULL, return -1, "Invalid ops");
129    ops->save = SavePersistParam;
130    ops->load = LoadPersistParam;
131    ops->batchSaveBegin = BatchSavePersistParamBegin;
132    ops->batchSave = BatchSavePersistParam;
133    ops->batchSaveEnd = BatchSavePersistParamEnd;
134    return 0;
135}