• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 <ctype.h>
16 #include <errno.h>
17 #include <limits.h>
18 
19 #include "param_manager.h"
20 #include "param_trie.h"
21 #ifdef SUPPORT_PARAM_LOAD_HOOK
22 #include "init_module_engine.h"
23 #endif
24 #include "securec.h"
25 
26 /**
27  * Loading system parameter from /proc/cmdline by the following rules:
28  *   1) reserved cmdline with or without ohos.boot. prefix listed in CmdlineIterator
29         will be processed by the specified processor
30  *   2) cmdline not listed in CmdlineIterator but prefixed with ohos.boot will be add by default
31  *
32  *   Special cases for sn:
33  *     a) if sn value in cmdline is started with "/", it means a file to be read as parameter value
34  *     b) if sn or ohos.boot.sn are not specified, try to generate sn by GenerateSnByDefault
35  */
36 #define OHOS_CMDLINE_PARA_PREFIX        "ohos.boot."
37 #define OHOS_CMDLINE_PARA_PREFIX_LEN    10
38 
39 typedef struct CmdLineInfo {
40     const char *name;
41     int (*processor)(const char *name, const char *value);
42 } CmdLineInfo;
43 
44 typedef struct CmdLineIteratorCtx {
45     char *cmdline;
46     bool gotSn;
47 } CmdLineIteratorCtx;
48 
CommonDealFun(const char * name,const char * value)49 static int CommonDealFun(const char *name, const char *value)
50 {
51     int ret = 0;
52     PARAM_LOGV("Add param from cmdline %s %s", name, value);
53     ret = CheckParamName(name, 0);
54     PARAM_CHECK(ret == 0, return ret, "Invalid param name %s", name);
55     PARAM_LOGV("Param name %s, value %s", name, value);
56     ret = WriteParam(name, value, NULL, 0);
57     PARAM_CHECK(ret == 0, return ret, "Failed to write param %s %s", name, value);
58     return ret;
59 }
60 
ReadSnFromFile(const char * name,const char * file)61 static int ReadSnFromFile(const char *name, const char *file)
62 {
63     char *data = ReadFileData(file);
64     PARAM_CHECK(data != NULL, return -1, "Read sn from %s file failed!", file);
65 
66     int index = 0;
67     for (size_t i = 0; i < strlen(data); i++) {
68         // cancel \r\n
69         if (*(data + i) == '\r' || *(data + i) == '\n') {
70             break;
71         }
72         if (*(data + i) != ':') {
73             *(data + index) = *(data + i);
74             index++;
75         }
76     }
77     data[index] = '\0';
78     PARAM_LOGV("**** name %s, value %s", name, data);
79     int ret = WriteParam(name, data, NULL, 0);
80     free(data);
81     PARAM_CHECK(ret == 0, return ret, "Failed to write param %s", name);
82     return ret;
83 }
84 
85 #define OHOS_SN_PARAM_NAME OHOS_CMDLINE_PARA_PREFIX"sn"
86 
SnDealFun(const char * name,const char * value)87 static int SnDealFun(const char *name, const char *value)
88 {
89     int ret = CheckParamName(name, 0);
90     PARAM_CHECK(ret == 0, return ret, "Invalid name %s", name);
91     if (value != NULL && value[0] != '/') {
92         PARAM_LOGV("**** name %s, value %s", name, value);
93         ret = WriteParam(OHOS_SN_PARAM_NAME, value, NULL, 0);
94         PARAM_CHECK(ret == 0, return ret, "Failed to write param %s %s", name, value);
95         return ret;
96     }
97     if (value != NULL && value[0] == '/') {
98         ret = ReadSnFromFile(OHOS_SN_PARAM_NAME, value);
99         if (ret == 0) {
100             return ret;
101         }
102     }
103     return ret;
104 }
105 
CmdlineIterator(const NAME_VALUE_PAIR * nv,void * context)106 static void CmdlineIterator(const NAME_VALUE_PAIR *nv, void *context)
107 {
108     int ret;
109     const char *name;
110     const char *matched;
111     char fullName[PARAM_NAME_LEN_MAX];
112     CmdLineIteratorCtx *ctx = (CmdLineIteratorCtx *)context;
113     char *data = (char *)ctx->cmdline;
114     static const CmdLineInfo CMDLINES[] = {
115         { "hardware", CommonDealFun },
116         { "bootgroup", CommonDealFun },
117         { "reboot_reason", CommonDealFun },
118         { "bootslots", CommonDealFun },
119         { "sn", SnDealFun },
120         { "root_package", CommonDealFun },
121         { "serialno", SnDealFun }
122     };
123 
124     data[nv->nameEnd - data] = '\0';
125     data[nv->valueEnd - data] = '\0';
126     PARAM_LOGV("proc cmdline: name [%s], value [%s]", nv->name, nv->value);
127 
128     // Get name without prefix
129     name = nv->name;
130     if (strncmp(name, OHOS_CMDLINE_PARA_PREFIX, OHOS_CMDLINE_PARA_PREFIX_LEN) == 0) {
131         name = name + OHOS_CMDLINE_PARA_PREFIX_LEN;
132     }
133 
134     // Matching reserved cmdlines
135     for (size_t i = 0; i < ARRAY_LENGTH(CMDLINES); i++) {
136         // Check exact match
137         if (strcmp(name, CMDLINES[i].name) != 0) {
138             // Check if contains ".xxx" for compatibility
139             ret = snprintf_s(fullName, sizeof(fullName), sizeof(fullName) - 1, ".%s", CMDLINES[i].name);
140             matched = strstr(name, fullName);
141             if (matched == NULL) {
142                 continue;
143             }
144             // Check if it is ended with pattern
145             if (matched[ret] != '\0') {
146                 continue;
147             }
148         }
149         ret = snprintf_s(fullName, sizeof(fullName), sizeof(fullName) - 1,
150             OHOS_CMDLINE_PARA_PREFIX "%s", CMDLINES[i].name);
151         if (ret <= 0) {
152             continue;
153         }
154         PARAM_LOGV("proc cmdline %s matched.", fullName);
155         ret = CMDLINES[i].processor(fullName, nv->value);
156         if ((ret == 0) && (SnDealFun == CMDLINES[i].processor)) {
157             ctx->gotSn = true;
158         }
159         return;
160     }
161 
162     if (name == nv->name) {
163         return;
164     }
165 
166     // cmdline with prefix but not matched, add to param by default
167     PARAM_LOGE("add proc cmdline param %s by default.", nv->name);
168     CommonDealFun(nv->name, nv->value);
169 }
170 
GenerateSnByDefault(void)171 static void GenerateSnByDefault(void)
172 {
173     const char *snFileList [] = {
174         "/sys/block/mmcblk0/device/cid",
175         "/proc/bootdevice/cid"
176     };
177 
178     for (size_t i = 0; i < ARRAY_LENGTH(snFileList); i++) {
179         int ret = ReadSnFromFile(OHOS_CMDLINE_PARA_PREFIX "sn", snFileList[i]);
180         if (ret == 0) {
181             break;
182         }
183     }
184 }
185 
LoadParamFromCmdLine(void)186 INIT_LOCAL_API int LoadParamFromCmdLine(void)
187 {
188     CmdLineIteratorCtx ctx;
189 
190     ctx.gotSn = false;
191     ctx.cmdline = ReadFileData(BOOT_CMD_LINE);
192     PARAM_CHECK(ctx.cmdline != NULL, return -1, "Failed to read file %s", BOOT_CMD_LINE);
193 
194     IterateNameValuePairs(ctx.cmdline, CmdlineIterator, (void *)(&ctx));
195 
196     // sn is critical, it must be specified
197     if (!ctx.gotSn) {
198         PARAM_LOGE("Generate default sn now ...");
199         GenerateSnByDefault();
200     }
201 
202     free(ctx.cmdline);
203     return 0;
204 }
205 
206 /*
207  * Load parameters from files
208  */
209 
LoadSecurityLabel(const char * fileName)210 static int LoadSecurityLabel(const char *fileName)
211 {
212     ParamWorkSpace *paramSpace = GetParamWorkSpace();
213     PARAM_CHECK(paramSpace != NULL, return -1, "Invalid paramSpace");
214     PARAM_WORKSPACE_CHECK(paramSpace, return -1, "Invalid space");
215     PARAM_CHECK(fileName != NULL, return -1, "Invalid filename for load");
216 #if !(defined __LITEOS_A__ || defined __LITEOS_M__)
217     // load security label
218     ParamSecurityOps *ops = GetParamSecurityOps(PARAM_SECURITY_DAC);
219     if (ops != NULL && ops->securityGetLabel != NULL) {
220         ops->securityGetLabel(fileName);
221     }
222 #endif
223     return 0;
224 }
225 
LoadOneParam_(const uint32_t * context,const char * name,const char * value)226 static int LoadOneParam_(const uint32_t *context, const char *name, const char *value)
227 {
228     uint32_t mode = *(uint32_t *)context;
229     int ret = CheckParamName(name, 0);
230     if (ret != 0) {
231         return 0;
232     }
233 
234 #ifdef SUPPORT_PARAM_LOAD_HOOK
235     PARAM_LOAD_FILTER_CTX filter;
236 
237     // Filter by hook
238     filter.name = name;
239     filter.value = value;
240     filter.ignored = 0;
241     HookMgrExecute(GetBootStageHookMgr(), INIT_PARAM_LOAD_FILTER, (void *)&filter, NULL);
242 
243     if (filter.ignored) {
244         PARAM_LOGV("Default parameter [%s] [%s] ignored", name, value);
245         return 0;
246     }
247 #endif
248 
249     PARAM_LOGV("Add default parameter [%s] [%s]", name, value);
250     return WriteParam(name, value, NULL, mode & LOAD_PARAM_ONLY_ADD);
251 }
252 
LoadDefaultParam_(const char * fileName,uint32_t mode,const char * exclude[],uint32_t count,int (* loadOneParam)(const uint32_t *,const char *,const char *))253 static int LoadDefaultParam_(const char *fileName, uint32_t mode,
254     const char *exclude[], uint32_t count, int (*loadOneParam)(const uint32_t *, const char *, const char *))
255 {
256     uint32_t paramNum = 0;
257     char realPath[PATH_MAX] = "";
258     realpath(fileName, realPath);
259     FILE *fp = fopen(realPath, "r");
260     if (fp == NULL) {
261         PARAM_LOGE("Failed to open file '%s' error:%d ", fileName, errno);
262         return -1;
263     }
264 
265     const int buffSize = PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX + 10;  // 10 max len
266     char *buffer = malloc(buffSize);
267     PARAM_CHECK(buffer != NULL, (void)fclose(fp);
268         return -1, "Failed to alloc memory");
269 
270     while (fgets(buffer, buffSize, fp) != NULL) {
271         buffer[buffSize - 1] = '\0';
272         int ret = SplitParamString(buffer, exclude, count, loadOneParam, &mode);
273         PARAM_CHECK(ret == 0, continue, "Failed to set param '%s' error:%d ", buffer, ret);
274         paramNum++;
275     }
276     (void)fclose(fp);
277     free(buffer);
278     PARAM_LOGV("Load %u default parameters success from %s.", paramNum, fileName);
279     return 0;
280 }
281 
ProcessParamFile(const char * fileName,void * context)282 static int ProcessParamFile(const char *fileName, void *context)
283 {
284     static const char *exclude[] = {"ctl.", "selinux.restorecon_recursive"};
285     uint32_t mode = *(int *)context;
286     return LoadDefaultParam_(fileName, mode, exclude, ARRAY_LENGTH(exclude), LoadOneParam_);
287 }
288 
LoadParamsFile(const char * fileName,bool onlyAdd)289 int LoadParamsFile(const char *fileName, bool onlyAdd)
290 {
291     return LoadDefaultParams(fileName, onlyAdd ? LOAD_PARAM_ONLY_ADD : LOAD_PARAM_NORMAL);
292 }
293 
LoadDefaultParams(const char * fileName,uint32_t mode)294 int LoadDefaultParams(const char *fileName, uint32_t mode)
295 {
296     PARAM_CHECK(fileName != NULL, return -1, "Invalid filename for load");
297     PARAM_LOGI("Load default parameters from %s.", fileName);
298     struct stat st;
299     if ((stat(fileName, &st) == 0) && !S_ISDIR(st.st_mode)) {
300         (void)ProcessParamFile(fileName, &mode);
301     } else {
302         (void)ReadFileInDir(fileName, ".para", ProcessParamFile, &mode);
303     }
304 
305     // load security label
306     return LoadSecurityLabel(fileName);
307 }
308 
LoadParamFromBuild(void)309 INIT_LOCAL_API void LoadParamFromBuild(void)
310 {
311     PARAM_LOGI("load parameters from build ");
312 #ifdef INCREMENTAL_VERSION
313     if (strlen(INCREMENTAL_VERSION) > 0) {
314         WriteParam("const.product.incremental.version", INCREMENTAL_VERSION, NULL, LOAD_PARAM_NORMAL);
315     }
316 #endif
317 #ifdef BUILD_TYPE
318     if (strlen(BUILD_TYPE) > 0) {
319         WriteParam("const.product.build.type", BUILD_TYPE, NULL, LOAD_PARAM_NORMAL);
320     }
321 #endif
322 #ifdef BUILD_USER
323     if (strlen(BUILD_USER) > 0) {
324         WriteParam("const.product.build.user", BUILD_USER, NULL, LOAD_PARAM_NORMAL);
325     }
326 #endif
327 #ifdef BUILD_TIME
328     if (strlen(BUILD_TIME) > 0) {
329         WriteParam("const.product.build.date", BUILD_TIME, NULL, LOAD_PARAM_NORMAL);
330     }
331 #endif
332 #ifdef BUILD_HOST
333     if (strlen(BUILD_HOST) > 0) {
334         WriteParam("const.product.build.host", BUILD_HOST, NULL, LOAD_PARAM_NORMAL);
335     }
336 #endif
337 #ifdef BUILD_ROOTHASH
338     if (strlen(BUILD_ROOTHASH) > 0) {
339         WriteParam("const.ohos.buildroothash", BUILD_ROOTHASH, NULL, LOAD_PARAM_NORMAL);
340     }
341 #endif
342 }
343 
LoadOneParamAreaSize_(const uint32_t * context,const char * name,const char * value)344 static int LoadOneParamAreaSize_(const uint32_t *context, const char *name, const char *value)
345 {
346     int ret = CheckParamName(name, 0);
347     if (ret != 0) {
348         return 0;
349     }
350     ret = CheckParamValue(NULL, name, value, PARAM_TYPE_INT);
351     PARAM_CHECK(ret == 0, return 0, "Invalid value %s for %s", value, name);
352     PARAM_LOGV("LoadOneParamAreaSize_ [%s] [%s]", name, value);
353     char buffer[PARAM_NAME_LEN_MAX] = {0};
354     int len = sprintf_s(buffer, sizeof(buffer), "const.%s", name);
355     PARAM_CHECK(len > 0, return 0, "Failed to format value %s for %s", value, name);
356     return AddParamEntry(WORKSPACE_INDEX_BASE, PARAM_TYPE_INT, buffer, value);
357 }
358 
LoadParamAreaSize(void)359 INIT_LOCAL_API void LoadParamAreaSize(void)
360 {
361     LoadDefaultParam_("/sys_prod/etc/param/ohos.para.size", 0, NULL, 0, LoadOneParamAreaSize_);
362     LoadDefaultParam_(PARAM_AREA_SIZE_CFG, 0, NULL, 0, LoadOneParamAreaSize_);
363 }
364