• 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 #include "init_cmds.h"
26 #include "init_param.h"
27 
28 /**
29  * Loading system parameter from /proc/cmdline by the following rules:
30  *   1) reserved cmdline with or without ohos.boot. prefix listed in CmdlineIterator
31         will be processed by the specified processor
32  *   2) cmdline not listed in CmdlineIterator but prefixed with ohos.boot will be add by default
33  *
34  *   Special cases for sn:
35  *     a) if sn value in cmdline is started with "/", it means a file to be read as parameter value
36  *     b) if sn or ohos.boot.sn are not specified, try to generate sn by GenerateSnByDefault
37  */
38 #define OHOS_CMDLINE_PARA_PREFIX        "ohos.boot."
39 #define OHOS_CMDLINE_CONST_PARA_PREFIX  "const.product."
40 #define OHOS_CMDLINE_PARA_PREFIX_LEN    10
41 #define IMPORT_PREFIX_LEN               7
42 
43 typedef struct CmdLineInfo {
44     const char *name;
45     int (*processor)(const char *name, const char *value);
46 } CmdLineInfo;
47 
48 typedef struct CmdLineInfoContainer {
49     const CmdLineInfo *cmdLineInfo;
50     size_t cmdLineInfoSize;
51 } CmdLineInfoContainer;
52 
53 typedef struct CmdLineIteratorCtx {
54     char *cmdline;
55     bool gotSn;
56 } CmdLineIteratorCtx;
57 
CommonDealFun(const char * name,const char * value)58 static int CommonDealFun(const char *name, const char *value)
59 {
60     int ret = 0;
61     PARAM_LOGV("Add param from cmdline %s %s", name, value);
62     ret = CheckParamName(name, 0);
63     PARAM_CHECK(ret == 0, return ret, "Invalid param name %s", name);
64     PARAM_LOGV("Param name %s, value %s", name, value);
65     ret = WriteParam(name, value, NULL, 0);
66     PARAM_CHECK(ret == 0, return ret, "Failed to write param %s %s", name, value);
67     return ret;
68 }
69 
ReadSnFromFile(const char * name,const char * file)70 static int ReadSnFromFile(const char *name, const char *file)
71 {
72     char *data = ReadFileData(file);
73     PARAM_CHECK(data != NULL, return -1, "Read sn from %s file failed!", file);
74 
75     int index = 0;
76     for (size_t i = 0; i < strlen(data); i++) {
77         // cancel \r\n
78         if (*(data + i) == '\r' || *(data + i) == '\n') {
79             break;
80         }
81         if (*(data + i) != ':') {
82             *(data + index) = *(data + i);
83             index++;
84         }
85     }
86     data[index] = '\0';
87     PARAM_LOGV("**** name %s, value %s", name, data);
88     int ret = WriteParam(name, data, NULL, 0);
89     free(data);
90     PARAM_CHECK(ret == 0, return ret, "Failed to write param %s", name);
91     return ret;
92 }
93 
94 #define OHOS_SN_PARAM_NAME OHOS_CMDLINE_PARA_PREFIX"sn"
95 
SnDealFun(const char * name,const char * value)96 static int SnDealFun(const char *name, const char *value)
97 {
98     int ret = CheckParamName(name, 0);
99     PARAM_CHECK(ret == 0, return ret, "Invalid name %s", name);
100     if (value != NULL && value[0] != '/') {
101         PARAM_LOGV("**** name %s, value %s", name, value);
102         ret = WriteParam(OHOS_SN_PARAM_NAME, value, NULL, 0);
103         PARAM_CHECK(ret == 0, return ret, "Failed to write param %s %s", name, value);
104         return ret;
105     }
106     if (value != NULL && value[0] == '/') {
107         ret = ReadSnFromFile(OHOS_SN_PARAM_NAME, value);
108         if (ret == 0) {
109             return ret;
110         }
111     }
112     return ret;
113 }
114 
Common2ConstDealFun(const char * name,const char * value)115 static int Common2ConstDealFun(const char *name, const char *value)
116 {
117     const char *tmpName;
118     tmpName = name;
119     if (strncmp(tmpName, OHOS_CMDLINE_PARA_PREFIX, OHOS_CMDLINE_PARA_PREFIX_LEN) == 0) {
120         tmpName = tmpName + OHOS_CMDLINE_PARA_PREFIX_LEN;
121     }
122     char fullName[PARAM_NAME_LEN_MAX];
123     int ret = snprintf_s(fullName, sizeof(fullName), sizeof(fullName) - 1,
124                          OHOS_CMDLINE_CONST_PARA_PREFIX"%s", tmpName);
125     PARAM_CHECK(ret > 0, return ret, "snprinf_s failed");
126     ret = CheckParamName(fullName, 0);
127     PARAM_CHECK(ret == 0, return ret, "Invalid name %s", name);
128     PARAM_LOGV("Param name %s, value %s", fullName, value);
129     ret = WriteParam(fullName, value, NULL, 0);
130     PARAM_CHECK(ret == 0, return ret, "Failed to write param %s %s", fullName, value);
131     return ret;
132 }
133 
MatchReserverCmdline(const NAME_VALUE_PAIR * nv,CmdLineIteratorCtx * ctx,const char * name,CmdLineInfoContainer * container)134 static int MatchReserverCmdline(const NAME_VALUE_PAIR* nv, CmdLineIteratorCtx *ctx, const char *name,
135                                 CmdLineInfoContainer *container)
136 {
137     const char* tmpName = name;
138     char fullName[PARAM_NAME_LEN_MAX];
139     int ret = 0;
140     const char* matched;
141 
142     // Matching reserved cmdlines
143     for (size_t i = 0; i < container->cmdLineInfoSize; i++) {
144         // Check exact match
145         if (strcmp(tmpName, (container->cmdLineInfo + i)->name) != 0) {
146             // Check if contains ".xxx" for compatibility
147             ret = snprintf_s(fullName, sizeof(fullName), sizeof(fullName) - 1, ".%s",
148                             (container->cmdLineInfo + i)->name);
149             matched = strstr(tmpName, fullName);
150             if (matched == NULL) {
151                 continue;
152             }
153             // Check if it is ended with pattern
154             if (matched[ret] != '\0') {
155                 continue;
156             }
157         }
158         ret = snprintf_s(fullName, sizeof(fullName), sizeof(fullName) - 1,
159                          OHOS_CMDLINE_PARA_PREFIX "%s", (container->cmdLineInfo + i)->name);
160         if (ret <= 0) {
161             continue;
162         }
163         PARAM_LOGV("proc cmdline %s matched.", fullName);
164         ret = (container->cmdLineInfo + i)->processor(fullName, nv->value);
165         if ((ret == 0) && (SnDealFun == (container->cmdLineInfo + i)->processor)) {
166             ctx->gotSn = true;
167         }
168         return PARAM_CODE_SUCCESS;
169     }
170     return PARAM_CODE_NOT_FOUND;
171 }
172 
CmdlineIterator(const NAME_VALUE_PAIR * nv,void * context)173 static void CmdlineIterator(const NAME_VALUE_PAIR *nv, void *context)
174 {
175     CmdLineIteratorCtx *ctx = (CmdLineIteratorCtx *)context;
176     char *data = (char *)ctx->cmdline;
177     static const CmdLineInfo CMDLINES[] = {
178         { "hardware", CommonDealFun },
179         { "bootgroup", CommonDealFun },
180         { "reboot_reason", CommonDealFun },
181         { "bootslots", CommonDealFun },
182         { "sn", SnDealFun },
183         { "root_package", CommonDealFun },
184         { "serialno", SnDealFun },
185         { "udid", Common2ConstDealFun },
186         { "productid", Common2ConstDealFun }
187     };
188 
189     data[nv->nameEnd - data] = '\0';
190     data[nv->valueEnd - data] = '\0';
191     PARAM_LOGV("proc cmdline: name [%s], value [%s]", nv->name, nv->value);
192 
193     // Get name without prefix
194     const char *name = nv->name;
195     if (strncmp(name, OHOS_CMDLINE_PARA_PREFIX, OHOS_CMDLINE_PARA_PREFIX_LEN) == 0) {
196         name = name + OHOS_CMDLINE_PARA_PREFIX_LEN;
197     }
198 
199     CmdLineInfoContainer container = { 0 };
200     container.cmdLineInfo = CMDLINES;
201     container.cmdLineInfoSize = ARRAY_LENGTH(CMDLINES);
202     if (MatchReserverCmdline(nv, ctx, name, &container) == 0) {
203         PARAM_LOGV("match reserver cmd line success, name: %s, value: %s", nv->name, nv->value);
204         return;
205     }
206     if (name == nv->name) {
207         return;
208     }
209 
210     // cmdline with prefix but not matched, add to param by default
211     PARAM_LOGE("add proc cmdline param %s by default.", nv->name);
212     CommonDealFun(nv->name, nv->value);
213 }
214 
GenerateSnByDefault(void)215 static void GenerateSnByDefault(void)
216 {
217     const char *snFileList [] = {
218         "/sys/block/mmcblk0/device/cid",
219         "/proc/bootdevice/cid"
220     };
221 
222     for (size_t i = 0; i < ARRAY_LENGTH(snFileList); i++) {
223         int ret = ReadSnFromFile(OHOS_CMDLINE_PARA_PREFIX "sn", snFileList[i]);
224         if (ret == 0) {
225             break;
226         }
227     }
228 }
229 
LoadParamFromCmdLine(void)230 INIT_LOCAL_API int LoadParamFromCmdLine(void)
231 {
232     CmdLineIteratorCtx ctx;
233 
234     ctx.gotSn = false;
235     ctx.cmdline = ReadFileData(BOOT_CMD_LINE);
236     PARAM_CHECK(ctx.cmdline != NULL, return -1, "Failed to read file %s", BOOT_CMD_LINE);
237 
238     IterateNameValuePairs(ctx.cmdline, CmdlineIterator, (void *)(&ctx));
239 
240     // sn is critical, it must be specified
241     if (!ctx.gotSn) {
242         PARAM_LOGE("Generate default sn now ...");
243         GenerateSnByDefault();
244     }
245 
246     free(ctx.cmdline);
247     return 0;
248 }
249 
250 /*
251  * Load parameters from files
252  */
253 
LoadSecurityLabel(const char * fileName)254 static int LoadSecurityLabel(const char *fileName)
255 {
256     ParamWorkSpace *paramSpace = GetParamWorkSpace();
257     PARAM_CHECK(paramSpace != NULL, return -1, "Invalid paramSpace");
258     PARAM_WORKSPACE_CHECK(paramSpace, return -1, "Invalid space");
259     PARAM_CHECK(fileName != NULL, return -1, "Invalid filename for load");
260 #if !(defined __LITEOS_A__ || defined __LITEOS_M__)
261     // load security label
262     ParamSecurityOps *ops = GetParamSecurityOps(PARAM_SECURITY_DAC);
263     if (ops != NULL && ops->securityGetLabel != NULL) {
264         if (ops->securityGetLabel(fileName) == PARAM_CODE_REACHED_MAX) {
265             PARAM_LOGE("Load Security Lable failed! system reboot!");
266             ExecReboot("panic");
267         };
268     }
269 #endif
270     return 0;
271 }
272 
LoadOneParam_(const uint32_t * context,const char * name,const char * value)273 static int LoadOneParam_(const uint32_t *context, const char *name, const char *value)
274 {
275     uint32_t mode = *(uint32_t *)context;
276     int ret = CheckParamName(name, 0);
277     if (ret != 0) {
278         return 0;
279     }
280 
281 #ifdef SUPPORT_PARAM_LOAD_HOOK
282     PARAM_LOAD_FILTER_CTX filter;
283 
284     // Filter by hook
285     filter.name = name;
286     filter.value = value;
287     filter.ignored = 0;
288     HookMgrExecute(GetBootStageHookMgr(), INIT_PARAM_LOAD_FILTER, (void *)&filter, NULL);
289 
290     if (filter.ignored) {
291         PARAM_LOGV("Default parameter [%s] [%s] ignored", name, value);
292         return 0;
293     }
294 #endif
295 
296     PARAM_LOGV("Add default parameter [%s] [%s]", name, value);
297     return WriteParam(name, value, NULL, mode & LOAD_PARAM_ONLY_ADD);
298 }
299 
LoadFileFromImport(char * target,uint32_t mode)300 static int LoadFileFromImport(char *target, uint32_t mode)
301 {
302     if (strstr(target, ".para.dac")) {
303         LoadSecurityLabel(target);
304     } else {
305         LoadDefaultParams(target, mode);
306     }
307     return 0;
308 }
309 
310 // Content format of .import.para is "import /dir/param.para"
311 // Use ${} to pass parameter like "import /dir/${const.product.productid}.para"
LoadParamFromImport_(char * buffer,const int buffSize,uint32_t mode)312 static int LoadParamFromImport_(char *buffer, const int buffSize, uint32_t mode)
313 {
314     int spaceCount = 0;
315     while (*(buffer + IMPORT_PREFIX_LEN + spaceCount) == ' ') {
316         spaceCount++;
317     }
318     char *target = calloc(PATH_MAX, 1);
319     PARAM_CHECK(target != NULL, return -1, "Failed to alloc memory");
320     if (strncpy_s(target, buffSize, buffer + IMPORT_PREFIX_LEN + spaceCount, buffSize) != 0) {
321         PARAM_LOGE("Failed to get value of import.");
322         free(target);
323         return -1;
324     }
325     char *tmp = NULL;
326     if ((tmp = strstr(target, "\n"))) {
327         *tmp = '\0';
328     }
329     char *tmpParamValue = calloc(PARAM_VALUE_LEN_MAX + 1, sizeof(char));
330     if (tmpParamValue == NULL) {
331         PARAM_LOGE("Failed to alloc memory");
332         free(target);
333         return -1;
334     }
335     int ret = GetParamValue(target, strlen(target), tmpParamValue, PARAM_VALUE_LEN_MAX);
336     if (ret == 0) {
337         LoadFileFromImport(tmpParamValue, mode);
338     }
339     PARAM_LOGI("Load params from import %s return %d.", tmpParamValue, ret);
340     free(tmpParamValue);
341     free(target);
342     return ret;
343 }
344 
LoadParamFromImport(const char * fileName,void * context)345 static int LoadParamFromImport(const char *fileName, void *context)
346 {
347     char realPath[PATH_MAX] = "";
348     realpath(fileName, realPath);
349     FILE *fp = fopen(realPath, "r");
350     if (fp == NULL) {
351         PARAM_LOGE("Failed to open file '%s' error:%d ", fileName, errno);
352         return -1;
353     }
354 
355     const int buffSize = PATH_MAX;
356     char *buffer = malloc(buffSize);
357     PARAM_CHECK(buffer != NULL, (void)fclose(fp);
358         return -1, "Failed to alloc memory");
359 
360     uint32_t mode = *(int *)context;
361     while (fgets(buffer, buffSize, fp) != NULL) {
362         buffer[buffSize - 1] = '\0';
363         if (!strncmp(buffer, "import ", IMPORT_PREFIX_LEN)) {
364             (void)LoadParamFromImport_(buffer, buffSize, mode);
365         }
366     }
367     (void)fclose(fp);
368     free(buffer);
369     return 0;
370 }
371 
LoadDefaultParam_(const char * fileName,uint32_t mode,const char * exclude[],uint32_t count,int (* loadOneParam)(const uint32_t *,const char *,const char *))372 static int LoadDefaultParam_(const char *fileName, uint32_t mode,
373     const char *exclude[], uint32_t count, int (*loadOneParam)(const uint32_t *, const char *, const char *))
374 {
375     uint32_t paramNum = 0;
376     char realPath[PATH_MAX] = "";
377     realpath(fileName, realPath);
378     FILE *fp = fopen(realPath, "r");
379     if (fp == NULL) {
380         PARAM_LOGE("Failed to open file '%s' error:%d ", fileName, errno);
381         return -1;
382     }
383 
384     const int buffSize = PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX + 10;  // 10 max len
385     char *buffer = malloc(buffSize);
386     PARAM_CHECK(buffer != NULL, (void)fclose(fp);
387         return -1, "Failed to alloc memory");
388 
389     while (fgets(buffer, buffSize, fp) != NULL) {
390         buffer[buffSize - 1] = '\0';
391         int ret = SplitParamString(buffer, exclude, count, loadOneParam, &mode);
392         PARAM_ONLY_CHECK(ret != PARAM_DEFAULT_PARAM_MEMORY_NOT_ENOUGH, return PARAM_DEFAULT_PARAM_MEMORY_NOT_ENOUGH);
393         PARAM_CHECK(ret == 0, continue, "Failed to set param '%s' error:%d ", buffer, ret);
394         paramNum++;
395     }
396     (void)fclose(fp);
397     free(buffer);
398     PARAM_LOGV("Load %u default parameters success from %s.", paramNum, fileName);
399     return 0;
400 }
401 
ProcessParamFile(const char * fileName,void * context)402 static int ProcessParamFile(const char *fileName, void *context)
403 {
404     static const char *exclude[] = {"ctl.", "selinux.restorecon_recursive"};
405     uint32_t mode = *(int *)context;
406     int ret = LoadDefaultParam_(fileName, mode, exclude, ARRAY_LENGTH(exclude), LoadOneParam_);
407     if (ret == PARAM_DEFAULT_PARAM_MEMORY_NOT_ENOUGH) {
408         PARAM_LOGE("default_param memory is not enough, system reboot!");
409         ExecReboot("panic");
410     }
411     return ret;
412 }
413 
LoadParamsFile(const char * fileName,bool onlyAdd)414 int LoadParamsFile(const char *fileName, bool onlyAdd)
415 {
416     return LoadDefaultParams(fileName, onlyAdd ? LOAD_PARAM_ONLY_ADD : LOAD_PARAM_NORMAL);
417 }
418 
LoadDefaultParams(const char * fileName,uint32_t mode)419 int LoadDefaultParams(const char *fileName, uint32_t mode)
420 {
421     PARAM_CHECK(fileName != NULL, return -1, "Invalid filename for load");
422     PARAM_LOGI("Load default parameters from %s.", fileName);
423     struct stat st;
424     if ((stat(fileName, &st) == 0) && !S_ISDIR(st.st_mode)) {
425         (void)ProcessParamFile(fileName, &mode);
426     } else {
427         (void)ReadFileInDir(fileName, ".para", ProcessParamFile, &mode);
428         (void)ReadFileInDir(fileName, ".para.import", LoadParamFromImport, &mode);
429     }
430 
431     // load security label
432     return LoadSecurityLabel(fileName);
433 }
434 
LoadParamFromBuild(void)435 INIT_LOCAL_API void LoadParamFromBuild(void)
436 {
437     PARAM_LOGI("load parameters from build ");
438 #ifdef INCREMENTAL_VERSION
439     if (strlen(INCREMENTAL_VERSION) > 0) {
440         WriteParam("const.product.incremental.version", INCREMENTAL_VERSION, NULL, LOAD_PARAM_NORMAL);
441     }
442 #endif
443 #ifdef BUILD_TYPE
444     if (strlen(BUILD_TYPE) > 0) {
445         WriteParam("const.product.build.type", BUILD_TYPE, NULL, LOAD_PARAM_NORMAL);
446     }
447 #endif
448 #ifdef BUILD_USER
449     if (strlen(BUILD_USER) > 0) {
450         WriteParam("const.product.build.user", BUILD_USER, NULL, LOAD_PARAM_NORMAL);
451     }
452 #endif
453 #ifdef BUILD_TIME
454     if (strlen(BUILD_TIME) > 0) {
455         WriteParam("const.product.build.date", BUILD_TIME, NULL, LOAD_PARAM_NORMAL);
456     }
457 #endif
458 #ifdef BUILD_HOST
459     if (strlen(BUILD_HOST) > 0) {
460         WriteParam("const.product.build.host", BUILD_HOST, NULL, LOAD_PARAM_NORMAL);
461     }
462 #endif
463 #ifdef BUILD_ROOTHASH
464     if (strlen(BUILD_ROOTHASH) > 0) {
465         WriteParam("const.ohos.buildroothash", BUILD_ROOTHASH, NULL, LOAD_PARAM_NORMAL);
466     }
467 #endif
468 }
469 
LoadOneParamAreaSize_(const uint32_t * context,const char * name,const char * value)470 static int LoadOneParamAreaSize_(const uint32_t *context, const char *name, const char *value)
471 {
472     uint32_t size = (uint32_t)strtoul(value, NULL, DECIMAL_BASE);
473     PARAM_LOGV("LoadOneParamAreaSize_ [%s] [%s]", name, value);
474     ParamWorkSpace *paramSpace = GetParamWorkSpace();
475     PARAM_CHECK(paramSpace != NULL && paramSpace->workSpace != NULL,
476         return -1, "Invalid workspace name %s", name);
477     WorkSpaceSize *spaceSize = GetWorkSpaceSize(GetWorkSpace(WORKSPACE_INDEX_SIZE));
478     PARAM_CHECK(spaceSize != NULL, return PARAM_CODE_ERROR, "Failed to get workspace size");
479     static char buffer[SELINUX_CONTENT_LEN] = {0};
480     int ret = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "u:object_r:%s:s0", name);
481     PARAM_CHECK(ret > 0, return PARAM_CODE_ERROR, "Failed to snprintf workspace name");
482 
483     for (uint32_t i = WORKSPACE_INDEX_BASE + 1; i < spaceSize->maxLabelIndex; i++) {
484         if (paramSpace->workSpace[i] == NULL) {
485             continue;
486         }
487         if (strcmp(paramSpace->workSpace[i]->fileName, buffer) == 0) {
488             spaceSize->spaceSize[i] = size;
489             paramSpace->workSpace[i]->spaceSize = size;
490             break;
491         }
492     }
493     return 0;
494 }
495 
LoadParamAreaSize(void)496 INIT_LOCAL_API void LoadParamAreaSize(void)
497 {
498     LoadDefaultParam_("/sys_prod/etc/param/ohos.para.size", 0, NULL, 0, LoadOneParamAreaSize_);
499     LoadDefaultParam_(PARAM_AREA_SIZE_CFG, 0, NULL, 0, LoadOneParamAreaSize_);
500 }
501