mirror of
https://gitee.com/openharmony/startup_init
synced 2024-11-23 08:09:59 +00:00
update openharmony 1.0.1
This commit is contained in:
parent
51a1c65843
commit
459f126471
@ -1,13 +0,0 @@
|
||||
### 该问题是怎么引起的?
|
||||
|
||||
|
||||
|
||||
### 重现步骤
|
||||
|
||||
|
||||
|
||||
### 报错信息
|
||||
|
||||
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
### 相关的Issue
|
||||
|
||||
|
||||
### 原因(目的、解决的问题等)
|
||||
|
||||
|
||||
### 描述(做了什么,变更了什么)
|
||||
|
||||
|
||||
### 测试用例(新增、改动、可能影响的功能)
|
||||
|
||||
|
||||
|
||||
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +0,0 @@
|
||||
/moduletest
|
72
BUILD.gn
72
BUILD.gn
@ -1,72 +0,0 @@
|
||||
# Copyright (c) 2020 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import("//build/lite/config/component/lite_component.gni")
|
||||
|
||||
lite_component("init_lite") {
|
||||
features = [
|
||||
":init"
|
||||
]
|
||||
}
|
||||
|
||||
# feature: init
|
||||
executable("init") {
|
||||
defines = [
|
||||
"_GNU_SOURCE", #syscall function need this macro definition
|
||||
]
|
||||
|
||||
sources = [
|
||||
"src/main.c",
|
||||
"src/init_cmds.c",
|
||||
"src/init_jobs.c",
|
||||
"src/init_read_cfg.c",
|
||||
"src/init_adapter.c",
|
||||
"src/init_service.c",
|
||||
"src/init_service_manager.c",
|
||||
"src/init_signal_handler.c",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
"include",
|
||||
"//third_party/cJSON",
|
||||
"//third_party/bounds_checking_function/include",
|
||||
"//base/startup/interfaces/kits/syspara_lite",
|
||||
]
|
||||
|
||||
cflags = [
|
||||
"-Wall",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//third_party/bounds_checking_function:libsec_shared",
|
||||
"//third_party/cJSON:cjson_shared",
|
||||
"//base/startup/frameworks/syspara_lite/parameter:parameter",
|
||||
]
|
||||
|
||||
ldflags = [ ]
|
||||
|
||||
if (ohos_kernel_type == "liteos_a") {
|
||||
include_dirs += [
|
||||
"//kernel/liteos_a/syscall",
|
||||
]
|
||||
|
||||
output_name = "init"
|
||||
}
|
||||
|
||||
if (ohos_kernel_type == "linux") {
|
||||
output_name = "ohosinit"
|
||||
|
||||
ldflags += [
|
||||
"-lm",
|
||||
]
|
||||
}
|
||||
}
|
252
README.md
Normal file
252
README.md
Normal file
@ -0,0 +1,252 @@
|
||||
# init\_lite<a name="EN-US_TOPIC_0000001129033057"></a>
|
||||
|
||||
- [Introduction](#section469617221261)
|
||||
- [Directory Structure](#section15884114210197)
|
||||
- [Constraints](#section12212842173518)
|
||||
- [Usage](#section837771600)
|
||||
- [Repositories Involved](#section641143415335)
|
||||
|
||||
## Introduction<a name="section469617221261"></a>
|
||||
|
||||
The init\_lite module starts system service processes from the time the kernel loads the first user-space process to the time the first application is started. In addition to loading key system processes, the module needs to configure their permissions during the startup and keep the specified process alive after sub-processes are started. If a process exits abnormally, the module needs to restart it, and to perform system reset for a special process.
|
||||
|
||||
## Directory Structure<a name="section15884114210197"></a>
|
||||
|
||||
```
|
||||
base/startup/init_lite/ # init_lite module
|
||||
├── LICENSE
|
||||
└── services
|
||||
├── include # Header files for the init_lite module
|
||||
├── src # Source files for the init_lite module
|
||||
└── test # Source files of the test cases for the init_lite module
|
||||
└── unittest
|
||||
vendor
|
||||
└──huawei
|
||||
└──camera
|
||||
└──init_configs # init_lite configuration files (in JSON format, and deployed in /etc/init.cfg after image burning)
|
||||
```
|
||||
|
||||
## Constraints<a name="section12212842173518"></a>
|
||||
|
||||
Currently, the init\_lite module applies only to small-system devices \(reference memory ≥ 1 MB\), for example, Hi3516D V300 and Hi3518E V300.
|
||||
|
||||
## Usage<a name="section837771600"></a>
|
||||
|
||||
init divides the system startup into three phases:
|
||||
|
||||
pre-init: operations required before system services are started, for example, mounting a file system, creating a folder, and modifying permissions
|
||||
|
||||
init: operations required for starting system services.
|
||||
|
||||
post-init: operations required after system services are started.
|
||||
|
||||
In the **init.cfg** file, each of the preceding phases is represented by a job, which corresponds to a command set. The init\_lite module initializes the system by executing the commands in each job in sequence. Jobs are executed in the following sequence: pre-init \> init \> post-init. All jobs are stored in the **jobs** array in the **init.cfg** file.
|
||||
|
||||
In addition to the **jobs** array, the **init.cfg** file also provides a **services** array, which is used to store the names, executable file paths, permissions, and other attribute information of the key system services that need to be started by the init process.
|
||||
|
||||
The file is stored in **/vendor/hisilicon/hispark\_aries/init\_configs/** under **/etc/**. It is in JSON format, and its size cannot exceed 100 KB.
|
||||
|
||||
The format and content of the **init.cfg** file are as follows:
|
||||
|
||||
```
|
||||
{
|
||||
"jobs" : [{
|
||||
"name" : "pre-init",
|
||||
"cmds" : [
|
||||
"mkdir /testdir",
|
||||
"chmod 0700 /testdir",
|
||||
"chown 99 99 /testdir",
|
||||
"mkdir /testdir2",
|
||||
"mount vfat /dev/mmcblk0p0 /testdir2 noexec nosuid"
|
||||
]
|
||||
}, {
|
||||
"name" : "init",
|
||||
"cmds" : [
|
||||
"start service1",
|
||||
"start service2"
|
||||
]
|
||||
}, {
|
||||
"name" : "post-init",
|
||||
"cmds" : []
|
||||
}
|
||||
],
|
||||
"services" : [{
|
||||
"name" : "service1",
|
||||
"path" : "/bin/process1",
|
||||
"uid" : 1,
|
||||
"gid" : 1,
|
||||
"once" : 0,
|
||||
"importance" : 1,
|
||||
"caps" : [0, 1, 2, 5]
|
||||
}, {
|
||||
"name" : "service2",
|
||||
"path" : "/bin/process2",
|
||||
"uid" : 2,
|
||||
"gid" : 2,
|
||||
"once" : 1,
|
||||
"importance" : 0,
|
||||
"caps" : []
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Table 1** Job description
|
||||
|
||||
<a name="table1801509284"></a>
|
||||
<table><thead align="left"><tr id="row680703289"><th class="cellrowborder" valign="top" width="13.4%" id="mcps1.2.3.1.1"><p id="p11805012282"><a name="p11805012282"></a><a name="p11805012282"></a>Job Name</p>
|
||||
</th>
|
||||
<th class="cellrowborder" valign="top" width="86.6%" id="mcps1.2.3.1.2"><p id="p2811605289"><a name="p2811605289"></a><a name="p2811605289"></a>Description</p>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr id="row178140112810"><td class="cellrowborder" valign="top" width="13.4%" headers="mcps1.2.3.1.1 "><p id="p6811809281"><a name="p6811809281"></a><a name="p6811809281"></a>pre-init</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="86.6%" headers="mcps1.2.3.1.2 "><p id="p18115019284"><a name="p18115019284"></a><a name="p18115019284"></a>Job that is executed first. Operations (for example, creating a folder) required before the process startup are executed in this job.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row381120182817"><td class="cellrowborder" valign="top" width="13.4%" headers="mcps1.2.3.1.1 "><p id="p148116002812"><a name="p148116002812"></a><a name="p148116002812"></a>init</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="86.6%" headers="mcps1.2.3.1.2 "><p id="p14818016288"><a name="p14818016288"></a><a name="p14818016288"></a>Job that is executed in between. Operations (for example, service startup) are executed in this job.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row181100162813"><td class="cellrowborder" valign="top" width="13.4%" headers="mcps1.2.3.1.1 "><p id="p3811804281"><a name="p3811804281"></a><a name="p3811804281"></a>post-init</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="86.6%" headers="mcps1.2.3.1.2 "><p id="p18116016285"><a name="p18116016285"></a><a name="p18116016285"></a>Job that is finally executed. Operations (for example, mounting the device after the driver initialization) required after the process startup are executed in this job.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
A single job can hold a maximum of 30 commands \(only **start**, **mkdir**, **chmod**, **chown**, **mount**, and **loadcfg** are supported currently\). The command name and parameters \(128 bytes or less\) must be separated by only one space.
|
||||
|
||||
**Table 2** Commands supported by a job
|
||||
|
||||
<a name="table122681439144112"></a>
|
||||
<table><thead align="left"><tr id="row826873984116"><th class="cellrowborder" valign="top" width="10.15%" id="mcps1.2.4.1.1"><p id="p826833919412"><a name="p826833919412"></a><a name="p826833919412"></a>Command</p>
|
||||
</th>
|
||||
<th class="cellrowborder" valign="top" width="34.089999999999996%" id="mcps1.2.4.1.2"><p id="p3381142134118"><a name="p3381142134118"></a><a name="p3381142134118"></a>Format and Example</p>
|
||||
</th>
|
||||
<th class="cellrowborder" valign="top" width="55.76%" id="mcps1.2.4.1.3"><p id="p1268539154110"><a name="p1268539154110"></a><a name="p1268539154110"></a>Description</p>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr id="row142681039124116"><td class="cellrowborder" valign="top" width="10.15%" headers="mcps1.2.4.1.1 "><p id="p2083714604313"><a name="p2083714604313"></a><a name="p2083714604313"></a>mkdir</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="34.089999999999996%" headers="mcps1.2.4.1.2 "><p id="p143811842154111"><a name="p143811842154111"></a><a name="p143811842154111"></a>mkdir <em id="i59061027135319"><a name="i59061027135319"></a><a name="i59061027135319"></a>target folder</em></p>
|
||||
<p id="p4377174213435"><a name="p4377174213435"></a><a name="p4377174213435"></a>Example: mkdir /storage/myDirectory</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="55.76%" headers="mcps1.2.4.1.3 "><p id="p56817536457"><a name="p56817536457"></a><a name="p56817536457"></a>Creates a folder. <strong id="b1111653719537"><a name="b1111653719537"></a><a name="b1111653719537"></a>mkdir</strong> and the target folder must be separated by only one space.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1268133919413"><td class="cellrowborder" valign="top" width="10.15%" headers="mcps1.2.4.1.1 "><p id="p97961563461"><a name="p97961563461"></a><a name="p97961563461"></a>chmod</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="34.089999999999996%" headers="mcps1.2.4.1.2 "><p id="p20381144234118"><a name="p20381144234118"></a><a name="p20381144234118"></a>chmod <em id="i15124416538"><a name="i15124416538"></a><a name="i15124416538"></a>permission</em> <em id="i1056644195314"><a name="i1056644195314"></a><a name="i1056644195314"></a>target</em></p>
|
||||
<p id="p6334213124413"><a name="p6334213124413"></a><a name="p6334213124413"></a>Examples: chmod 0600 /storage/myFile.txt</p>
|
||||
<p id="p1748214543444"><a name="p1748214543444"></a><a name="p1748214543444"></a>chmod 0750 /storage/myDir</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="55.76%" headers="mcps1.2.4.1.3 "><p id="p2023822074614"><a name="p2023822074614"></a><a name="p2023822074614"></a>Modifies the permission, which must be in the <strong id="b8112193214139"><a name="b8112193214139"></a><a name="b8112193214139"></a>0<em id="i11455534181314"><a name="i11455534181314"></a><a name="i11455534181314"></a>xxx</em></strong> format. <strong id="b2675148175310"><a name="b2675148175310"></a><a name="b2675148175310"></a>chmod</strong>, <em id="i46798488538"><a name="i46798488538"></a><a name="i46798488538"></a>permission</em>, and <em id="i667944825318"><a name="i667944825318"></a><a name="i667944825318"></a>target</em> must be separated by only one space.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row7268143918416"><td class="cellrowborder" valign="top" width="10.15%" headers="mcps1.2.4.1.1 "><p id="p8255346174610"><a name="p8255346174610"></a><a name="p8255346174610"></a>chown</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="34.089999999999996%" headers="mcps1.2.4.1.2 "><p id="p238114423418"><a name="p238114423418"></a><a name="p238114423418"></a>chown uid gid <em id="i161565145312"><a name="i161565145312"></a><a name="i161565145312"></a>target</em></p>
|
||||
<p id="p1118592184518"><a name="p1118592184518"></a><a name="p1118592184518"></a>Example: chown 900 800 /storage/myDir</p>
|
||||
<p id="p1235374884510"><a name="p1235374884510"></a><a name="p1235374884510"></a>chown 100 100 /storage/myFile.txt</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="55.76%" headers="mcps1.2.4.1.3 "><p id="p18408185817467"><a name="p18408185817467"></a><a name="p18408185817467"></a>Modifies the owner group. <strong id="b19641958195310"><a name="b19641958195310"></a><a name="b19641958195310"></a>chown</strong>, <strong id="b15698584534"><a name="b15698584534"></a><a name="b15698584534"></a>uid</strong>, <strong id="b1692058135310"><a name="b1692058135310"></a><a name="b1692058135310"></a>gid</strong>, and <em id="i56935885316"><a name="i56935885316"></a><a name="i56935885316"></a>target</em> must be separated by only one space.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row109751379478"><td class="cellrowborder" valign="top" width="10.15%" headers="mcps1.2.4.1.1 "><p id="p1017823174717"><a name="p1017823174717"></a><a name="p1017823174717"></a>mount</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="34.089999999999996%" headers="mcps1.2.4.1.2 "><p id="p10381124244117"><a name="p10381124244117"></a><a name="p10381124244117"></a>mount fileSystemType src dst flags data</p>
|
||||
<p id="p572019493485"><a name="p572019493485"></a><a name="p572019493485"></a>Example: mount vfat /dev/mmcblk0 /sdc rw,umask=000</p>
|
||||
<p id="p7381173625313"><a name="p7381173625313"></a><a name="p7381173625313"></a>mount jffs2 /dev/mtdblock3 /storage nosuid</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="55.76%" headers="mcps1.2.4.1.3 "><p id="p11976107144710"><a name="p11976107144710"></a><a name="p11976107144710"></a>Mounts devices. Every two parameters must be separated by only one space. Currently, supported flags include <strong id="b5512525411"><a name="b5512525411"></a><a name="b5512525411"></a>nodev</strong>, <strong id="b41014514541"><a name="b41014514541"></a><a name="b41014514541"></a>noexec</strong>, <strong id="b5101152543"><a name="b5101152543"></a><a name="b5101152543"></a>nosuid</strong>, <strong id="b20103555419"><a name="b20103555419"></a><a name="b20103555419"></a>rdonly</strong>, and optionally <strong id="b41045175420"><a name="b41045175420"></a><a name="b41045175420"></a>data</strong>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1334911198482"><td class="cellrowborder" valign="top" width="10.15%" headers="mcps1.2.4.1.1 "><p id="p1214153117480"><a name="p1214153117480"></a><a name="p1214153117480"></a>start</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="34.089999999999996%" headers="mcps1.2.4.1.2 "><p id="p133816420411"><a name="p133816420411"></a><a name="p133816420411"></a>start serviceName</p>
|
||||
<p id="p2036714132541"><a name="p2036714132541"></a><a name="p2036714132541"></a>Example: start foundation</p>
|
||||
<p id="p115951820185412"><a name="p115951820185412"></a><a name="p115951820185412"></a>start shell</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="55.76%" headers="mcps1.2.4.1.3 "><p id="p4350121915488"><a name="p4350121915488"></a><a name="p4350121915488"></a>Starts services. <em id="i87951116544"><a name="i87951116544"></a><a name="i87951116544"></a>serviceName</em> must be contained in the <strong id="b379981145417"><a name="b379981145417"></a><a name="b379981145417"></a>services</strong> array.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row96921442712"><td class="cellrowborder" valign="top" width="10.15%" headers="mcps1.2.4.1.1 "><p id="p1693642018"><a name="p1693642018"></a><a name="p1693642018"></a>loadcfg</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="34.089999999999996%" headers="mcps1.2.4.1.2 "><p id="p1969364211116"><a name="p1969364211116"></a><a name="p1969364211116"></a>loadcfg filePath</p>
|
||||
<p id="p1858112368211"><a name="p1858112368211"></a><a name="p1858112368211"></a>Example: loadcfg /patch/fstab.cfg</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="55.76%" headers="mcps1.2.4.1.3 "><p id="p13986141320510"><a name="p13986141320510"></a><a name="p13986141320510"></a>Loads other <strong id="b280561515549"><a name="b280561515549"></a><a name="b280561515549"></a>.cfg</strong> files. The maximum size of the target file (only <strong id="b105471717135416"><a name="b105471717135416"></a><a name="b105471717135416"></a>/patch/fstab.cfg</strong> supported currently) is 50 KB. Each line in the <strong id="b14853122910540"><a name="b14853122910540"></a><a name="b14853122910540"></a>/patch/fstab.cfg</strong> file is a command. The command types and formats must comply with their respective requirements mentioned in this table. A maximum of 20 commands are allowed.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
**Table 3** Elements in the **services** array
|
||||
|
||||
<a name="table14737791471"></a>
|
||||
<table><thead align="left"><tr id="row273839577"><th class="cellrowborder" valign="top" width="10.37%" id="mcps1.2.3.1.1"><p id="p107382095711"><a name="p107382095711"></a><a name="p107382095711"></a>Field</p>
|
||||
</th>
|
||||
<th class="cellrowborder" valign="top" width="89.63%" id="mcps1.2.3.1.2"><p id="p17738189277"><a name="p17738189277"></a><a name="p17738189277"></a>Description</p>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr id="row17386911716"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p17384912710"><a name="p17384912710"></a><a name="p17384912710"></a>name</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p1173818913714"><a name="p1173818913714"></a><a name="p1173818913714"></a>Name of the current service. The value cannot be empty and can contain a maximum of 32 bytes.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1473810916714"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p127381991571"><a name="p127381991571"></a><a name="p127381991571"></a>path</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p1073815910717"><a name="p1073815910717"></a><a name="p1073815910717"></a>Full path (including parameters) of the executable file for the current service. This is an array. Ensure that the first element is the path of the executable file, the maximum number of elements is 20, and each element is a string that contains a maximum of 64 bytes.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row77381291271"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p77381391770"><a name="p77381391770"></a><a name="p77381391770"></a>uid</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p107387920711"><a name="p107387920711"></a><a name="p107387920711"></a>User ID (UID) of the current service process.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row127381591673"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p47388919715"><a name="p47388919715"></a><a name="p47388919715"></a>gid</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p12738691479"><a name="p12738691479"></a><a name="p12738691479"></a>Group ID (GID) of the current service process.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row188301014171116"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p183112146115"><a name="p183112146115"></a><a name="p183112146115"></a>once</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p18548317195715"><a name="p18548317195715"></a><a name="p18548317195715"></a>Whether the current service process is a one-off process.</p>
|
||||
<p id="p103571840105812"><a name="p103571840105812"></a><a name="p103571840105812"></a><strong id="b7898115614817"><a name="b7898115614817"></a><a name="b7898115614817"></a>1</strong>: The current service process is a one-off process. If the process exits, the init process does not restart it.</p>
|
||||
<p id="p5831191431116"><a name="p5831191431116"></a><a name="p5831191431116"></a><strong id="b20971155820811"><a name="b20971155820811"></a><a name="b20971155820811"></a>0</strong>: The current service process is not a one-off process. If the process exits, the init process restarts it upon receiving the SIGCHLD signal.</p>
|
||||
<p id="p378912714010"><a name="p378912714010"></a><a name="p378912714010"></a>Note: If a non-one-off process exits for five consecutive times within four minutes, the init process will no longer restart it at the fifth exit.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row386110321155"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p14861113212156"><a name="p14861113212156"></a><a name="p14861113212156"></a>importance</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p166448210816"><a name="p166448210816"></a><a name="p166448210816"></a>Whether the current service process is a key system process.</p>
|
||||
<p id="p8572182712811"><a name="p8572182712811"></a><a name="p8572182712811"></a><strong id="b72917915010"><a name="b72917915010"></a><a name="b72917915010"></a>0</strong>: The current service process is not a key system process. If it exits, the init process does not reset or restart the system.</p>
|
||||
<p id="p11861032111516"><a name="p11861032111516"></a><a name="p11861032111516"></a><strong id="b1074320101309"><a name="b1074320101309"></a><a name="b1074320101309"></a>1</strong>: The current service process is a key system process. If it exits, the init process resets and restarts the system.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1689310618179"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p108931367177"><a name="p108931367177"></a><a name="p108931367177"></a>caps</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p489313618173"><a name="p489313618173"></a><a name="p489313618173"></a>Capabilities required by the current service. They are evaluated based on the capabilities supported by the security subsystem and configured in accordance with the principle of least permission. Currently, a maximum of 100 values can be configured.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## Repositories Involved<a name="section641143415335"></a>
|
||||
|
||||
Startup Subsystem
|
||||
|
||||
hmf/startup/syspara\_lite
|
||||
|
||||
hmf/startup/appspawn\_lite
|
||||
|
||||
hmf/startup/bootstrap\_lite
|
||||
|
||||
**hmf/startup/init\_lite**
|
||||
|
256
README_zh.md
Normal file
256
README_zh.md
Normal file
@ -0,0 +1,256 @@
|
||||
# init组件<a name="ZH-CN_TOPIC_0000001129033057"></a>
|
||||
|
||||
- [简介](#section469617221261)
|
||||
- [目录](#section15884114210197)
|
||||
- [约束](#section12212842173518)
|
||||
- [使用说明](#section837771600)
|
||||
- [相关仓](#section641143415335)
|
||||
|
||||
## 简介<a name="section469617221261"></a>
|
||||
|
||||
init组件负责处理从内核加载第一个用户态进程开始,到第一个应用程序启动之间的系统服务进程启动过程。启动恢复子系统除负责加载各系统关键进程之外,还需在启动的同时设置其对应权限,并在子进程启动后对指定进程实行保活(若进程意外退出要重新启动),对于特殊进程意外退出时,启动恢复子系统还要执行系统复位操作。
|
||||
|
||||
## 目录<a name="section15884114210197"></a>
|
||||
|
||||
```
|
||||
base/startup/init_lite/ # init组件
|
||||
├── LICENSE
|
||||
└── services
|
||||
├── include # init组件头文件目录
|
||||
├── src # init组件源文件目录
|
||||
└── test # init组件测试用例源文件目录
|
||||
└── unittest
|
||||
vendor
|
||||
└──huawei
|
||||
└──camera
|
||||
└──init_configs # init配置文件目录(json格式,镜像烧写后部署于/etc/init.cfg)
|
||||
```
|
||||
|
||||
## 约束<a name="section12212842173518"></a>
|
||||
|
||||
目前支持小型系统设备(参考内存≥1MB),如Hi3516DV300、Hi3518EV300。
|
||||
|
||||
## 使用说明<a name="section837771600"></a>
|
||||
|
||||
init将系统启动分为三个阶段:
|
||||
|
||||
“pre-init”阶段:启动系统服务之前需要先执行的操作,例如挂载文件系统、创建文件夹、修改权限等
|
||||
|
||||
“init”阶段:系统服务启动阶段
|
||||
|
||||
“post-init”阶段:系统服务启动完后还需要执行的操作
|
||||
|
||||
上述每个阶段在配置文件init.cfg中都用一个job表示,每个job都对应一个命令集合,init通过依次执行每个job中的命令来完成系统初始化。job执行顺序:先执行“pre-init”,再执行“init”,最后执行“post-init”,所有job都集中放在init.cfg的jobs数组中。
|
||||
|
||||
除上述jobs数组之外,init.cfg中还有一个services数组,用于存放所有需要由init进程启动的系统关键服务的服务名、可执行文件路径、权限和其他属性信息。
|
||||
|
||||
配置文件init.cfg位于代码仓库/vendor/hisilicon/hispark\_aries/init\_configs/目录,部署在/etc/下,采用json格式,文件大小目前限制在100KB以内。
|
||||
|
||||
配置文件格式和内容说明如下所示:
|
||||
|
||||
```
|
||||
{
|
||||
"jobs" : [{
|
||||
"name" : "pre-init",
|
||||
"cmds" : [
|
||||
"mkdir /testdir",
|
||||
"chmod 0700 /testdir",
|
||||
"chown 99 99 /testdir",
|
||||
"mkdir /testdir2",
|
||||
"mount vfat /dev/mmcblk0p0 /testdir2 noexec nosuid"
|
||||
]
|
||||
}, {
|
||||
"name" : "init",
|
||||
"cmds" : [
|
||||
"start service1",
|
||||
"start service2"
|
||||
]
|
||||
}, {
|
||||
"name" : "post-init",
|
||||
"cmds" : []
|
||||
}
|
||||
],
|
||||
"services" : [{
|
||||
"name" : "service1",
|
||||
"path" : "/bin/process1",
|
||||
"uid" : 1,
|
||||
"gid" : 1,
|
||||
"once" : 0,
|
||||
"importance" : 1,
|
||||
"caps" : [0, 1, 2, 5]
|
||||
}, {
|
||||
"name" : "service2",
|
||||
"path" : "/bin/process2",
|
||||
"uid" : 2,
|
||||
"gid" : 2,
|
||||
"once" : 1,
|
||||
"importance" : 0,
|
||||
"caps" : []
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**表 1** 执行job介绍
|
||||
|
||||
<a name="table1801509284"></a>
|
||||
<table><thead align="left"><tr id="row680703289"><th class="cellrowborder" valign="top" width="13.4%" id="mcps1.2.3.1.1"><p id="p11805012282"><a name="p11805012282"></a><a name="p11805012282"></a>job名</p>
|
||||
</th>
|
||||
<th class="cellrowborder" valign="top" width="86.6%" id="mcps1.2.3.1.2"><p id="p2811605289"><a name="p2811605289"></a><a name="p2811605289"></a>说明</p>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr id="row178140112810"><td class="cellrowborder" valign="top" width="13.4%" headers="mcps1.2.3.1.1 "><p id="p6811809281"><a name="p6811809281"></a><a name="p6811809281"></a>pre-init</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="86.6%" headers="mcps1.2.3.1.2 "><p id="p18115019284"><a name="p18115019284"></a><a name="p18115019284"></a>最先执行的job,如果开发者的进程在启动之前需要首先执行一些操作(例如创建文件夹),可以把操作放到pre-init中先执行。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row381120182817"><td class="cellrowborder" valign="top" width="13.4%" headers="mcps1.2.3.1.1 "><p id="p148116002812"><a name="p148116002812"></a><a name="p148116002812"></a>init</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="86.6%" headers="mcps1.2.3.1.2 "><p id="p14818016288"><a name="p14818016288"></a><a name="p14818016288"></a>中间执行的job,例如服务启动。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row181100162813"><td class="cellrowborder" valign="top" width="13.4%" headers="mcps1.2.3.1.1 "><p id="p3811804281"><a name="p3811804281"></a><a name="p3811804281"></a>post-init</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="86.6%" headers="mcps1.2.3.1.2 "><p id="p18116016285"><a name="p18116016285"></a><a name="p18116016285"></a>最后被执行的job,如果开发者的进程在启动完成之后需要有一些处理(如驱动初始化后再挂载设备),可以把这类操作放到该job执行。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
单个job最多支持30条命令(当前仅支持start/mkdir/chmod/chown/mount/loadcfg),命令名称和后面的参数(参数长度≤128字节)之间有且只能有一个空格。
|
||||
|
||||
**表 2** 命令集说明
|
||||
|
||||
<a name="table122681439144112"></a>
|
||||
<table><thead align="left"><tr id="row826873984116"><th class="cellrowborder" valign="top" width="10.15%" id="mcps1.2.4.1.1"><p id="p826833919412"><a name="p826833919412"></a><a name="p826833919412"></a>命令</p>
|
||||
</th>
|
||||
<th class="cellrowborder" valign="top" width="34.089999999999996%" id="mcps1.2.4.1.2"><p id="p3381142134118"><a name="p3381142134118"></a><a name="p3381142134118"></a>命令格式和示例</p>
|
||||
</th>
|
||||
<th class="cellrowborder" valign="top" width="55.76%" id="mcps1.2.4.1.3"><p id="p1268539154110"><a name="p1268539154110"></a><a name="p1268539154110"></a>说明</p>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr id="row142681039124116"><td class="cellrowborder" valign="top" width="10.15%" headers="mcps1.2.4.1.1 "><p id="p2083714604313"><a name="p2083714604313"></a><a name="p2083714604313"></a>mkdir</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="34.089999999999996%" headers="mcps1.2.4.1.2 "><p id="p143811842154111"><a name="p143811842154111"></a><a name="p143811842154111"></a>mkdir 目标文件夹</p>
|
||||
<p id="p4377174213435"><a name="p4377174213435"></a><a name="p4377174213435"></a>如:mkdir /storage/myDirectory</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="55.76%" headers="mcps1.2.4.1.3 "><p id="p56817536457"><a name="p56817536457"></a><a name="p56817536457"></a>创建文件夹命令,mkdir和目标文件夹之间有且只能有一个空格。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1268133919413"><td class="cellrowborder" valign="top" width="10.15%" headers="mcps1.2.4.1.1 "><p id="p97961563461"><a name="p97961563461"></a><a name="p97961563461"></a>chmod</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="34.089999999999996%" headers="mcps1.2.4.1.2 "><p id="p20381144234118"><a name="p20381144234118"></a><a name="p20381144234118"></a>chmod 权限 目标</p>
|
||||
<p id="p6334213124413"><a name="p6334213124413"></a><a name="p6334213124413"></a>如:chmod 0600 /storage/myFile.txt</p>
|
||||
<p id="p1748214543444"><a name="p1748214543444"></a><a name="p1748214543444"></a>chmod 0750 /storage/myDir</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="55.76%" headers="mcps1.2.4.1.3 "><p id="p2023822074614"><a name="p2023822074614"></a><a name="p2023822074614"></a>修改权限命令,chmod 权限 目标 之间间隔有且仅有一个空格,权限必须为0xxx格式。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row7268143918416"><td class="cellrowborder" valign="top" width="10.15%" headers="mcps1.2.4.1.1 "><p id="p8255346174610"><a name="p8255346174610"></a><a name="p8255346174610"></a>chown</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="34.089999999999996%" headers="mcps1.2.4.1.2 "><p id="p238114423418"><a name="p238114423418"></a><a name="p238114423418"></a>chown uid gid 目标</p>
|
||||
<p id="p1118592184518"><a name="p1118592184518"></a><a name="p1118592184518"></a>如:chown 900 800 /storage/myDir</p>
|
||||
<p id="p1235374884510"><a name="p1235374884510"></a><a name="p1235374884510"></a>chown 100 100 /storage/myFile.txt</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="55.76%" headers="mcps1.2.4.1.3 "><p id="p18408185817467"><a name="p18408185817467"></a><a name="p18408185817467"></a>修改属组命令,chown uid gid 目标 之间间隔有且仅有一个空格。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row109751379478"><td class="cellrowborder" valign="top" width="10.15%" headers="mcps1.2.4.1.1 "><p id="p1017823174717"><a name="p1017823174717"></a><a name="p1017823174717"></a>mount</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="34.089999999999996%" headers="mcps1.2.4.1.2 "><p id="p10381124244117"><a name="p10381124244117"></a><a name="p10381124244117"></a>mount fileSystemType src dst flags data</p>
|
||||
<p id="p572019493485"><a name="p572019493485"></a><a name="p572019493485"></a>如:mount vfat /dev/mmcblk0 /sdc rw,umask=000</p>
|
||||
<p id="p7381173625313"><a name="p7381173625313"></a><a name="p7381173625313"></a>mount jffs2 /dev/mtdblock3 /storage nosuid</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="55.76%" headers="mcps1.2.4.1.3 "><p id="p11976107144710"><a name="p11976107144710"></a><a name="p11976107144710"></a>挂载命令,各参数之间有且仅有一个空格。flags当前仅支持nodev、noexec、nosuid、rdonly,data为可选字段。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1334911198482"><td class="cellrowborder" valign="top" width="10.15%" headers="mcps1.2.4.1.1 "><p id="p1214153117480"><a name="p1214153117480"></a><a name="p1214153117480"></a>start</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="34.089999999999996%" headers="mcps1.2.4.1.2 "><p id="p133816420411"><a name="p133816420411"></a><a name="p133816420411"></a>start serviceName</p>
|
||||
<p id="p2036714132541"><a name="p2036714132541"></a><a name="p2036714132541"></a>如:start foundation</p>
|
||||
<p id="p115951820185412"><a name="p115951820185412"></a><a name="p115951820185412"></a>start shell</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="55.76%" headers="mcps1.2.4.1.3 "><p id="p4350121915488"><a name="p4350121915488"></a><a name="p4350121915488"></a>启动服务命令,start后面跟着service名称,该service名称必须能够在services数组中找到。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row96921442712"><td class="cellrowborder" valign="top" width="10.15%" headers="mcps1.2.4.1.1 "><p id="p1693642018"><a name="p1693642018"></a><a name="p1693642018"></a>loadcfg</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="34.089999999999996%" headers="mcps1.2.4.1.2 "><p id="p1969364211116"><a name="p1969364211116"></a><a name="p1969364211116"></a>loadcfg filePath</p>
|
||||
<p id="p1858112368211"><a name="p1858112368211"></a><a name="p1858112368211"></a>如:loadcfg /patch/fstab.cfg</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="55.76%" headers="mcps1.2.4.1.3 "><p id="p13986141320510"><a name="p13986141320510"></a><a name="p13986141320510"></a>加载其他cfg文件命令。后面跟着的目标文件大小不得超过50KB,且目前仅支持加载/patch/fstab.cfg,其他文件路径和文件名均不支持。/patch/fstab.cfg文件的每一行都是一条命令,命令类型和格式必须符合本表格描述,命令条数不得超过20条。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
**表 3** service字段说明
|
||||
|
||||
<a name="table14737791471"></a>
|
||||
<table><thead align="left"><tr id="row273839577"><th class="cellrowborder" valign="top" width="10.37%" id="mcps1.2.3.1.1"><p id="p107382095711"><a name="p107382095711"></a><a name="p107382095711"></a>字段名</p>
|
||||
</th>
|
||||
<th class="cellrowborder" valign="top" width="89.63%" id="mcps1.2.3.1.2"><p id="p17738189277"><a name="p17738189277"></a><a name="p17738189277"></a>说明</p>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr id="row17386911716"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p17384912710"><a name="p17384912710"></a><a name="p17384912710"></a>name</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p1173818913714"><a name="p1173818913714"></a><a name="p1173818913714"></a>当前服务的名称,须确保非空且长度≤32字节。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1473810916714"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p127381991571"><a name="p127381991571"></a><a name="p127381991571"></a>path</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p1073815910717"><a name="p1073815910717"></a><a name="p1073815910717"></a>当前服务的可执行文件全路径和参数,数组形式。须确保第一个数组元素为可执行文件路径、数组元素个数≤20、每个元素为字符串形式以及每个字符串长度≤64字节。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row77381291271"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p77381391770"><a name="p77381391770"></a><a name="p77381391770"></a>uid</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p107387920711"><a name="p107387920711"></a><a name="p107387920711"></a>当前服务进程的uid值。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row127381591673"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p47388919715"><a name="p47388919715"></a><a name="p47388919715"></a>gid</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p12738691479"><a name="p12738691479"></a><a name="p12738691479"></a>当前服务进程的gid值。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row188301014171116"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p183112146115"><a name="p183112146115"></a><a name="p183112146115"></a>once</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p18548317195715"><a name="p18548317195715"></a><a name="p18548317195715"></a>当前服务进程是否为一次性进程:</p>
|
||||
<p id="p103571840105812"><a name="p103571840105812"></a><a name="p103571840105812"></a>1:一次性进程,当该进程退出时,init不会重新启动该服务进程</p>
|
||||
<p id="p5831191431116"><a name="p5831191431116"></a><a name="p5831191431116"></a>0 : 常驻进程,当该进程退出时,init收到SIGCHLD信号并重新启动该服务进程;</p>
|
||||
<p id="p378912714010"><a name="p378912714010"></a><a name="p378912714010"></a>注意:对于常驻进程,若在4分钟之内连续退出5次,第5次退出时init将不会再重新拉起该服务进程。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row386110321155"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p14861113212156"><a name="p14861113212156"></a><a name="p14861113212156"></a>importance</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p166448210816"><a name="p166448210816"></a><a name="p166448210816"></a>当前服务进程是否为关键系统进程:</p>
|
||||
<p id="p8572182712811"><a name="p8572182712811"></a><a name="p8572182712811"></a>0:非关键系统进程,当该进程退出时,init不会将系统复位重启;</p>
|
||||
<p id="p11861032111516"><a name="p11861032111516"></a><a name="p11861032111516"></a>1:关键系统进程,当该进程退出时,init将系统复位重启。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1689310618179"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p108931367177"><a name="p108931367177"></a><a name="p108931367177"></a>caps</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p489313618173"><a name="p489313618173"></a><a name="p489313618173"></a>当前服务所需的capability值,根据安全子系统已支持的capability,评估所需的capability,遵循最小权限原则配置(当前最多可配置100个值)。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## 相关仓<a name="section641143415335"></a>
|
||||
|
||||
启动恢复子系统
|
||||
|
||||
hmf/startup/syspara\_lite
|
||||
|
||||
hmf/startup/appspawn\_lite
|
||||
|
||||
hmf/startup/bootstrap\_lite
|
||||
|
||||
**hmf/startup/init\_lite**
|
||||
|
||||
hmf/startup/startup
|
||||
|
||||
hmf/startup/systemrestore
|
||||
|
@ -1,3 +0,0 @@
|
||||
详见:https://gitee.com/openharmony/docs/blob/master/readme/启动恢复README.md
|
||||
|
||||
see: https://gitee.com/openharmony/docs/blob/master/docs-en/readme/startup.md
|
69
services/BUILD.gn
Normal file
69
services/BUILD.gn
Normal file
@ -0,0 +1,69 @@
|
||||
# Copyright (c) 2020 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import("//build/lite/config/component/lite_component.gni")
|
||||
|
||||
lite_component("init_lite") {
|
||||
features = [ ":init" ]
|
||||
}
|
||||
|
||||
# feature: init
|
||||
executable("init") {
|
||||
defines = [
|
||||
"_GNU_SOURCE", #syscall function need this macro definition
|
||||
]
|
||||
sources = [
|
||||
"src/init_adapter.c",
|
||||
"src/init_cmds.c",
|
||||
"src/init_jobs.c",
|
||||
"src/init_read_cfg.c",
|
||||
"src/init_service.c",
|
||||
"src/init_service_manager.c",
|
||||
"src/init_signal_handler.c",
|
||||
"src/main.c",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
"include",
|
||||
"//third_party/cJSON",
|
||||
"//third_party/bounds_checking_function/include",
|
||||
"//base/startup/syspara_lite/interfaces/kits",
|
||||
]
|
||||
|
||||
cflags = [ "-Wall" ]
|
||||
|
||||
deps = [
|
||||
"//base/startup/syspara_lite/frameworks/parameter:parameter",
|
||||
"//build/lite/config/component/cJSON:cjson_shared",
|
||||
"//third_party/bounds_checking_function:libsec_shared",
|
||||
]
|
||||
|
||||
ldflags = []
|
||||
|
||||
if (ohos_kernel_type == "liteos_a") {
|
||||
include_dirs += [ "//kernel/liteos_a/syscall" ]
|
||||
}
|
||||
|
||||
if (ohos_kernel_type == "linux") {
|
||||
defines += [ "NEED_EXEC_RCS_LINUX" ]
|
||||
ldflags += [
|
||||
"-lm",
|
||||
"-lpthread",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (ohos_build_type == "debug") {
|
||||
group("unittest") {
|
||||
deps = [ "//base/startup/init_lite/services/test/unittest/common:unittest" ]
|
||||
}
|
||||
}
|
@ -29,11 +29,29 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __LINUX__
|
||||
/* Control the ambient capability set */
|
||||
#ifndef PR_CAP_AMBIENT
|
||||
#define PR_CAP_AMBIENT 47
|
||||
#endif
|
||||
#ifndef PR_CAP_AMBIENT_IS_SET
|
||||
#define PR_CAP_AMBIENT_IS_SET 1
|
||||
#endif
|
||||
#ifndef PR_CAP_AMBIENT_RAISE
|
||||
#define PR_CAP_AMBIENT_RAISE 2
|
||||
#endif
|
||||
#ifndef PR_CAP_AMBIENT_LOWER
|
||||
#define PR_CAP_AMBIENT_LOWER 3
|
||||
#endif
|
||||
#ifndef PR_CAP_AMBIENT_CLEAR_ALL
|
||||
#define PR_CAP_AMBIENT_CLEAR_ALL 4
|
||||
#endif
|
||||
extern int capset(void *a, void *b);
|
||||
#endif
|
||||
|
||||
void RebootSystem();
|
||||
int KeepCapability();
|
||||
int SetAmbientCapability(int cap);
|
||||
void ExecuteRcs();
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
0
include/init_cmds.h → services/include/init_cmds.h
Executable file → Normal file
0
include/init_cmds.h → services/include/init_cmds.h
Executable file → Normal file
0
include/init_jobs.h → services/include/init_jobs.h
Executable file → Normal file
0
include/init_jobs.h → services/include/init_jobs.h
Executable file → Normal file
0
include/init_read_cfg.h → services/include/init_read_cfg.h
Executable file → Normal file
0
include/init_read_cfg.h → services/include/init_read_cfg.h
Executable file → Normal file
@ -36,7 +36,6 @@ extern "C" {
|
||||
#define SERVICE_ATTR_IMPORTANT 0x010 // will reboot if it crash
|
||||
|
||||
#define MAX_SERVICE_NAME 32
|
||||
#define MAX_SERVICE_PATH 64
|
||||
|
||||
#define CAP_NUM 2
|
||||
|
||||
@ -51,7 +50,8 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
char name[MAX_SERVICE_NAME + 1];
|
||||
char path[MAX_SERVICE_PATH + 1];
|
||||
char** pathArgs;
|
||||
int pathArgsCnt;
|
||||
int pid;
|
||||
int crashCnt;
|
||||
time_t firstCrashTime;
|
0
include/init_service_manager.h → services/include/init_service_manager.h
Executable file → Normal file
0
include/init_service_manager.h → services/include/init_service_manager.h
Executable file → Normal file
10
include/init_signal_handler.h → services/include/init_signal_handler.h
Executable file → Normal file
10
include/init_signal_handler.h → services/include/init_signal_handler.h
Executable file → Normal file
@ -16,6 +16,11 @@
|
||||
#ifndef BASE_STARTUP_INITLITE_SIGNAL_HANDLE_H
|
||||
#define BASE_STARTUP_INITLITE_SIGNAL_HANDLE_H
|
||||
|
||||
#ifdef __LINUX__
|
||||
#include <semaphore.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
@ -23,7 +28,10 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
void SignalInitModule();
|
||||
int SignalShouldKeepAlive();
|
||||
|
||||
#ifdef __LINUX__
|
||||
void SignalRegWaitSem(pid_t waitPid, sem_t* waitSem);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
89
services/src/init_adapter.c
Normal file
89
services/src/init_adapter.c
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "init_adapter.h"
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/reboot.h>
|
||||
#ifdef __LINUX__
|
||||
#include <linux/securebits.h>
|
||||
#include "init_signal_handler.h"
|
||||
#endif
|
||||
|
||||
void RebootSystem()
|
||||
{
|
||||
int ret = reboot(RB_AUTOBOOT);
|
||||
if (ret != 0) {
|
||||
printf("[Init] reboot failed! syscall ret %d, err %d.\n", ret, errno);
|
||||
}
|
||||
}
|
||||
|
||||
int KeepCapability()
|
||||
{
|
||||
#ifdef __LINUX__
|
||||
if (prctl(PR_SET_SECUREBITS, SECBIT_NO_SETUID_FIXUP | SECBIT_NO_SETUID_FIXUP_LOCKED)) {
|
||||
printf("[Init] prctl failed\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetAmbientCapability(int cap)
|
||||
{
|
||||
#ifdef __LINUX__
|
||||
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)) {
|
||||
printf("[Init] prctl PR_CAP_AMBIENT failed\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ExecuteRcs()
|
||||
{
|
||||
#if (defined __LINUX__) && (defined NEED_EXEC_RCS_LINUX)
|
||||
pid_t retPid = fork();
|
||||
if (retPid < 0) {
|
||||
printf("[Init] ExecuteRcs, fork failed! err %d.\n", errno);
|
||||
return;
|
||||
}
|
||||
|
||||
// child process
|
||||
if (retPid == 0) {
|
||||
printf("[Init] ExecuteRcs, child process id %d.\n", getpid());
|
||||
if (execle("/bin/sh", "sh", "/etc/init.d/rcS", NULL, NULL) != 0) {
|
||||
printf("[Init] ExecuteRcs, execle failed! err %d.\n", errno);
|
||||
}
|
||||
_exit(0x7f); // 0x7f: user specified
|
||||
}
|
||||
|
||||
// init process
|
||||
sem_t sem;
|
||||
if (sem_init(&sem, 0, 0) != 0) {
|
||||
printf("[Init] ExecuteRcs, sem_init failed, err %d.\n", errno);
|
||||
return;
|
||||
}
|
||||
SignalRegWaitSem(retPid, &sem);
|
||||
|
||||
// wait until rcs process exited
|
||||
if (sem_wait(&sem) != 0) {
|
||||
printf("[Init] ExecuteRcs, sem_wait failed, err %d.\n", errno);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
142
src/init_cmds.c → services/src/init_cmds.c
Executable file → Normal file
142
src/init_cmds.c → services/src/init_cmds.c
Executable file → Normal file
@ -28,17 +28,26 @@
|
||||
#include "init_service_manager.h"
|
||||
#include "securec.h"
|
||||
|
||||
|
||||
#define MODE_LEN 4 // for chmod mode, format 0xxx
|
||||
#define DEFAULT_DIR_MODE 0755 // mkdir, default mode
|
||||
#define SPACES_CNT_IN_CMD_MAX 10 // mount, max number of spaces in cmdline
|
||||
#define SPACES_CNT_IN_CMD_MIN 2 // mount, min number of spaces in cmdline
|
||||
|
||||
#define LOADCFG_BUF_SIZE 128 // loadcfg, max buffer for one cmdline
|
||||
#define LOADCFG_MAX_FILE_LEN 51200 // loadcfg, max file size is 50K
|
||||
#define LOADCFG_MAX_LOOP 20 // loadcfg, to prevent to be trapped in infite loop
|
||||
static const char *g_supportCfg[] = {
|
||||
"/patch/fstab.cfg",
|
||||
};
|
||||
|
||||
static const char* g_supportedCmds[] = {
|
||||
"start ",
|
||||
"mkdir ",
|
||||
"chmod ",
|
||||
"chown ",
|
||||
"mount ",
|
||||
"loadcfg ",
|
||||
};
|
||||
|
||||
void ParseCmdLine(const char* cmdStr, CmdLine* resCmd)
|
||||
@ -119,19 +128,16 @@ static void DoChmod(const char* cmdContent)
|
||||
|
||||
static void DoChown(const char* cmdContent)
|
||||
{
|
||||
if (*cmdContent == ' ') {
|
||||
printf("[Init] DoChown, bad format for %s.\n", cmdContent);
|
||||
return;
|
||||
}
|
||||
// format: owner group /xxx/xxx/xxx
|
||||
size_t firstSpace = 0;
|
||||
size_t secondSpace = 0;
|
||||
size_t strLen = strlen(cmdContent);
|
||||
for (size_t i = 0; i < strLen; ++i) {
|
||||
if (cmdContent[i] != ' ') {
|
||||
continue;
|
||||
if (cmdContent[i] == ' ') {
|
||||
if (i == 0) {
|
||||
printf("[Init] DoChown, bad format for %s.\n", cmdContent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstSpace == 0) {
|
||||
firstSpace = i;
|
||||
} else {
|
||||
@ -139,6 +145,7 @@ static void DoChown(const char* cmdContent)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (secondSpace <= firstSpace || firstSpace + 1 == secondSpace || secondSpace == strLen - 1) {
|
||||
printf("[Init] DoChown, bad format for %s.\n", cmdContent);
|
||||
@ -213,36 +220,29 @@ static int GetMountFlag(unsigned long* mountflags, const char* targetStr)
|
||||
|
||||
static int CountSpaces(const char* cmdContent, size_t* spaceCnt, size_t* spacePosArr, size_t spacePosArrLen)
|
||||
{
|
||||
size_t numSpaces = 0;
|
||||
bool isSpaceTooMany = false;
|
||||
const size_t strLen = strlen(cmdContent);
|
||||
*spaceCnt = 0;
|
||||
size_t strLen = strlen(cmdContent);
|
||||
for (size_t i = 0; i < strLen; ++i) {
|
||||
if (cmdContent[i] != ' ') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (++numSpaces > spacePosArrLen) {
|
||||
isSpaceTooMany = true;
|
||||
break;
|
||||
}
|
||||
spacePosArr[numSpaces - 1] = i;
|
||||
}
|
||||
*spaceCnt = numSpaces;
|
||||
if (isSpaceTooMany) {
|
||||
if (cmdContent[i] == ' ') {
|
||||
++(*spaceCnt);
|
||||
if ((*spaceCnt) > spacePosArrLen) {
|
||||
printf("[Init] DoMount, too many spaces, bad format for %s.\n", cmdContent);
|
||||
return 0;
|
||||
}
|
||||
spacePosArr[(*spaceCnt) - 1] = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (numSpaces < SPACES_CNT_IN_CMD_MIN || // spaces count should not less than 2(at least 3 items)
|
||||
if ((*spaceCnt) < SPACES_CNT_IN_CMD_MIN || // spaces count should not less than 2(at least 3 items)
|
||||
spacePosArr[0] == 0 || // should not start with space
|
||||
spacePosArr[numSpaces - 1] == strLen - 1) { // should not end with space
|
||||
spacePosArr[(*spaceCnt) - 1] == strLen - 1) { // should not end with space
|
||||
printf("[Init] DoMount, bad format for %s.\n", cmdContent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// spaces should not be adjacent
|
||||
for (size_t i = 0; i < numSpaces - 1; ++i) {
|
||||
if (spacePosArr[i] == spacePosArr[i] + 1) {
|
||||
for (size_t i = 1; i < (*spaceCnt); ++i) {
|
||||
if (spacePosArr[i] == spacePosArr[i - 1] + 1) {
|
||||
printf("[Init] DoMount, bad format for %s.\n", cmdContent);
|
||||
return 0;
|
||||
}
|
||||
@ -263,12 +263,25 @@ static void DoMount(const char* cmdContent)
|
||||
size_t strLen = strlen(cmdContent);
|
||||
size_t indexOffset = 0;
|
||||
char* fileSysType = CopySubStr(cmdContent, 0, spacePosArr[indexOffset]);
|
||||
if (fileSysType == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
char* source = CopySubStr(cmdContent, spacePosArr[indexOffset] + 1, spacePosArr[indexOffset + 1]);
|
||||
if (source == NULL) {
|
||||
free(fileSysType);
|
||||
return;
|
||||
}
|
||||
++indexOffset;
|
||||
|
||||
// maybe only has "filesystype source target", 2 spaces
|
||||
size_t targetEndPos = (indexOffset == spaceCnt - 1) ? strLen : spacePosArr[indexOffset + 1];
|
||||
char* target = CopySubStr(cmdContent, spacePosArr[indexOffset] + 1, targetEndPos);
|
||||
if (target == NULL) {
|
||||
free(fileSysType);
|
||||
free(source);
|
||||
return;
|
||||
}
|
||||
++indexOffset;
|
||||
|
||||
// get mountflags, if fail, the rest part of string will be data
|
||||
@ -286,7 +299,6 @@ static void DoMount(const char* cmdContent)
|
||||
++indexOffset;
|
||||
}
|
||||
|
||||
if (fileSysType != NULL && source != NULL && target != NULL) {
|
||||
int mountRet;
|
||||
if (indexOffset >= spaceCnt) { // no data
|
||||
mountRet = mount(source, target, fileSysType, mountflags, NULL);
|
||||
@ -296,10 +308,7 @@ static void DoMount(const char* cmdContent)
|
||||
}
|
||||
|
||||
if (mountRet != 0) {
|
||||
printf("[Init] DoMount, failed for %s, err %d.\n", cmdContent, mountRet);
|
||||
}
|
||||
} else {
|
||||
printf("[Init] DoMount, get field failed for %s.\n", cmdContent);
|
||||
printf("[Init] DoMount, failed for %s, err %d.\n", cmdContent, errno);
|
||||
}
|
||||
|
||||
free(fileSysType);
|
||||
@ -307,6 +316,74 @@ static void DoMount(const char* cmdContent)
|
||||
free(target);
|
||||
}
|
||||
|
||||
static bool CheckValidCfg(const char *path)
|
||||
{
|
||||
size_t cfgCnt = sizeof(g_supportCfg) / sizeof(g_supportCfg[0]);
|
||||
struct stat fileStat = {0};
|
||||
|
||||
if (stat(path, &fileStat) != 0 || fileStat.st_size <= 0 || fileStat.st_size > LOADCFG_MAX_FILE_LEN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < cfgCnt; ++i) {
|
||||
if (strcmp(path, g_supportCfg[i]) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void DoLoadCfg(const char *path)
|
||||
{
|
||||
char buf[LOADCFG_BUF_SIZE] = {0};
|
||||
FILE *fp = NULL;
|
||||
size_t maxLoop = 0;
|
||||
CmdLine *cmdLine = NULL;
|
||||
int len;
|
||||
|
||||
if (path == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
printf("[Init] DoLoadCfg cfg file %s\n", path);
|
||||
if (!CheckValidCfg(path)) {
|
||||
printf("[Init] CheckCfg file %s Failed\n", path);
|
||||
return;
|
||||
}
|
||||
|
||||
fp = fopen(path, "r");
|
||||
if (fp == NULL) {
|
||||
printf("[Init] open cfg error = %d\n", errno);
|
||||
return;
|
||||
}
|
||||
|
||||
cmdLine = (CmdLine *)malloc(sizeof(CmdLine));
|
||||
if (cmdLine == NULL) {
|
||||
printf("[Init] malloc cmdline error");
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
while (fgets(buf, LOADCFG_BUF_SIZE, fp) != NULL && maxLoop < LOADCFG_MAX_LOOP) {
|
||||
maxLoop++;
|
||||
len = strlen(buf);
|
||||
if (len < 1) {
|
||||
continue;
|
||||
}
|
||||
if (buf[len - 1] == '\n') {
|
||||
buf[len - 1] = '\0'; // we replace '\n' with '\0'
|
||||
}
|
||||
(void)memset_s(cmdLine, sizeof(CmdLine), 0, sizeof(CmdLine));
|
||||
ParseCmdLine(buf, cmdLine);
|
||||
DoCmd(cmdLine);
|
||||
(void)memset_s(buf, sizeof(char) * LOADCFG_BUF_SIZE, 0, sizeof(char) * LOADCFG_BUF_SIZE);
|
||||
}
|
||||
|
||||
free(cmdLine);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void DoCmd(const CmdLine* curCmd)
|
||||
{
|
||||
if (curCmd == NULL) {
|
||||
@ -323,7 +400,10 @@ void DoCmd(const CmdLine* curCmd)
|
||||
DoChown(curCmd->cmdContent);
|
||||
} else if (strncmp(curCmd->name, "mount ", strlen("mount ")) == 0) {
|
||||
DoMount(curCmd->cmdContent);
|
||||
} else if (strncmp(curCmd->name, "loadcfg ", strlen("loadcfg ")) == 0) {
|
||||
DoLoadCfg(curCmd->cmdContent);
|
||||
} else {
|
||||
printf("[Init] DoCmd, unknown cmd name %s.\n", curCmd->name);
|
||||
}
|
||||
}
|
||||
|
9
src/init_jobs.c → services/src/init_jobs.c
Executable file → Normal file
9
src/init_jobs.c → services/src/init_jobs.c
Executable file → Normal file
@ -21,6 +21,7 @@
|
||||
#include "init_cmds.h"
|
||||
#include "securec.h"
|
||||
|
||||
|
||||
#define JOBS_ARR_NAME_IN_JSON "jobs"
|
||||
#define CMDS_ARR_NAME_IN_JSON "cmds"
|
||||
#define MAX_JOBS_COUNT 10
|
||||
@ -104,11 +105,12 @@ void ParseAllJobs(const cJSON* fileRoot)
|
||||
}
|
||||
|
||||
cJSON* jobArr = cJSON_GetObjectItemCaseSensitive(fileRoot, JOBS_ARR_NAME_IN_JSON);
|
||||
int jobArrSize = 0;
|
||||
if (cJSON_IsArray(jobArr)) {
|
||||
jobArrSize = cJSON_GetArraySize(jobArr);
|
||||
if (!cJSON_IsArray(jobArr)) {
|
||||
printf("[Init] ParseAllJobs, job item is not array!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int jobArrSize = cJSON_GetArraySize(jobArr);
|
||||
if (jobArrSize <= 0 || jobArrSize > MAX_JOBS_COUNT) {
|
||||
printf("[Init] ParseAllJobs, jobs count %d is invalid, should be positive and not exceeding %d.\n",
|
||||
jobArrSize, MAX_JOBS_COUNT);
|
||||
@ -172,3 +174,4 @@ void ReleaseAllJobs()
|
||||
g_jobs = NULL;
|
||||
g_jobCnt = 0;
|
||||
}
|
||||
|
116
src/init_read_cfg.c → services/src/init_read_cfg.c
Executable file → Normal file
116
src/init_read_cfg.c → services/src/init_read_cfg.c
Executable file → Normal file
@ -28,7 +28,10 @@
|
||||
#include "init_service_manager.h"
|
||||
#include "securec.h"
|
||||
|
||||
|
||||
static const long MAX_JSON_FILE_LEN = 102400; // max init.cfg size 100KB
|
||||
static const int MAX_PATH_ARGS_CNT = 20; // max path and args count
|
||||
static const int MAX_ONE_ARG_LEN = 64; // max length of one param/path
|
||||
#define MAX_SERVICES_CNT_IN_FILE 100
|
||||
#define MAX_CAPS_CNT_FOR_ONE_SERVICE 100
|
||||
#define UID_STR_IN_CFG "uid"
|
||||
@ -76,6 +79,11 @@ static char* ReadFileToBuf()
|
||||
static cJSON* GetArrItem(const cJSON* fileRoot, int* arrSize, const char* arrName)
|
||||
{
|
||||
cJSON* arrItem = cJSON_GetObjectItemCaseSensitive(fileRoot, arrName);
|
||||
if (!cJSON_IsArray(arrItem)) {
|
||||
printf("[Init] GetArrItem, item %s is not an array!\n", arrName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*arrSize = cJSON_GetArraySize(arrItem);
|
||||
if (*arrSize <= 0) {
|
||||
return NULL;
|
||||
@ -105,40 +113,94 @@ static int IsForbidden(const char* fieldStr)
|
||||
}
|
||||
}
|
||||
|
||||
static int GetServiceString(const cJSON* curArrItem, Service* curServ, const char* targetField, size_t maxLen)
|
||||
static void ReleaseServiceMem(Service* curServ)
|
||||
{
|
||||
char* fieldStr = cJSON_GetStringValue(cJSON_GetObjectItem(curArrItem, targetField));
|
||||
if (curServ->pathArgs != NULL) {
|
||||
for (int i = 0; i < curServ->pathArgsCnt; ++i) {
|
||||
if (curServ->pathArgs[i] != NULL) {
|
||||
free(curServ->pathArgs[i]);
|
||||
curServ->pathArgs[i] = NULL;
|
||||
}
|
||||
}
|
||||
free(curServ->pathArgs);
|
||||
curServ->pathArgs = NULL;
|
||||
}
|
||||
curServ->pathArgsCnt = 0;
|
||||
|
||||
if (curServ->servPerm.caps != NULL) {
|
||||
free(curServ->servPerm.caps);
|
||||
curServ->servPerm.caps = NULL;
|
||||
}
|
||||
curServ->servPerm.capsCnt = 0;
|
||||
}
|
||||
|
||||
static int GetServiceName(const cJSON* curArrItem, Service* curServ)
|
||||
{
|
||||
char* fieldStr = cJSON_GetStringValue(cJSON_GetObjectItem(curArrItem, "name"));
|
||||
if (fieldStr == NULL) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
size_t strLen = strlen(fieldStr);
|
||||
if (strLen == 0 || strLen > maxLen) {
|
||||
if (strLen == 0 || strLen > MAX_SERVICE_NAME) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
if (strncmp(targetField, "name", strlen("name")) == 0) {
|
||||
if (memcpy_s(curServ->name, maxLen, fieldStr, strLen) != EOK) {
|
||||
if (memcpy_s(curServ->name, MAX_SERVICE_NAME, fieldStr, strLen) != EOK) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->name[strLen] = '\0';
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
if (strncmp(targetField, "path", strlen("path")) == 0) {
|
||||
if (IsForbidden(fieldStr)) {
|
||||
printf("[Init] InitReadCfg, %s is not allowed.\n", fieldStr);
|
||||
static int GetServicePathAndArgs(const cJSON* curArrItem, Service* curServ)
|
||||
{
|
||||
cJSON* pathItem = cJSON_GetObjectItem(curArrItem, "path");
|
||||
if (!cJSON_IsArray(pathItem)) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
if (memcpy_s(curServ->path, maxLen, fieldStr, strLen) != EOK) {
|
||||
int arrSize = cJSON_GetArraySize(pathItem);
|
||||
if (arrSize <= 0 || arrSize > MAX_PATH_ARGS_CNT) { // array size invalid
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->path[strLen] = '\0';
|
||||
|
||||
curServ->pathArgs = (char**)malloc((arrSize + 1) * sizeof(char*));
|
||||
if (curServ->pathArgs == NULL) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
for (int i = 0; i < arrSize + 1; ++i) {
|
||||
curServ->pathArgs[i] = NULL;
|
||||
}
|
||||
curServ->pathArgsCnt = arrSize + 1;
|
||||
|
||||
for (int i = 0; i < arrSize; ++i) {
|
||||
char* curParam = cJSON_GetStringValue(cJSON_GetArrayItem(pathItem, i));
|
||||
if (curParam == NULL || strlen(curParam) > MAX_ONE_ARG_LEN) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
if (i == 0 && IsForbidden(curParam)) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
size_t paramLen = strlen(curParam);
|
||||
curServ->pathArgs[i] = (char*)malloc(paramLen + 1);
|
||||
if (curServ->pathArgs[i] == NULL) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
if (memcpy_s(curServ->pathArgs[i], paramLen + 1, curParam, paramLen) != EOK) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->pathArgs[i][paramLen] = '\0';
|
||||
}
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
static int GetServiceNumber(const cJSON* curArrItem, Service* curServ, const char* targetField)
|
||||
{
|
||||
@ -200,14 +262,12 @@ static int GetServiceCaps(const cJSON* curArrItem, Service* curServ)
|
||||
for (int i = 0; i < capsCnt; ++i) {
|
||||
cJSON* capJ = cJSON_GetArrayItem(filedJ, i);
|
||||
if (!cJSON_IsNumber(capJ) || cJSON_GetNumberValue(capJ) < 0) {
|
||||
free(curServ->servPerm.caps);
|
||||
curServ->servPerm.caps = NULL;
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->servPerm.caps[i] = (unsigned int)cJSON_GetNumberValue(capJ);
|
||||
if (curServ->servPerm.caps[i] > CAP_LAST_CAP && curServ->servPerm.caps[i] != FULL_CAP) {
|
||||
free(curServ->servPerm.caps);
|
||||
curServ->servPerm.caps = NULL;
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
}
|
||||
@ -244,26 +304,19 @@ static void ParseAllServices(const cJSON* fileRoot)
|
||||
|
||||
for (int i = 0; i < servArrSize; ++i) {
|
||||
cJSON* curItem = cJSON_GetArrayItem(serviceArr, i);
|
||||
if (GetServiceString(curItem, &retServices[i], "name", MAX_SERVICE_NAME) != SERVICE_SUCCESS ||
|
||||
GetServiceString(curItem, &retServices[i], "path", MAX_SERVICE_PATH) != SERVICE_SUCCESS) {
|
||||
retServices[i].attribute |= SERVICE_ATTR_INVALID;
|
||||
printf("[Init] InitReadCfg, bad string values for service %d.\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (GetServiceNumber(curItem, &retServices[i], UID_STR_IN_CFG) != SERVICE_SUCCESS ||
|
||||
if (GetServiceName(curItem, &retServices[i]) != SERVICE_SUCCESS ||
|
||||
GetServicePathAndArgs(curItem, &retServices[i]) != SERVICE_SUCCESS ||
|
||||
GetServiceNumber(curItem, &retServices[i], UID_STR_IN_CFG) != SERVICE_SUCCESS ||
|
||||
GetServiceNumber(curItem, &retServices[i], GID_STR_IN_CFG) != SERVICE_SUCCESS ||
|
||||
GetServiceNumber(curItem, &retServices[i], ONCE_STR_IN_CFG) != SERVICE_SUCCESS ||
|
||||
GetServiceNumber(curItem, &retServices[i], IMPORTANT_STR_IN_CFG) != SERVICE_SUCCESS) {
|
||||
GetServiceNumber(curItem, &retServices[i], IMPORTANT_STR_IN_CFG) != SERVICE_SUCCESS ||
|
||||
GetServiceCaps(curItem, &retServices[i]) != SERVICE_SUCCESS) {
|
||||
// release resources if it fails
|
||||
ReleaseServiceMem(&retServices[i]);
|
||||
retServices[i].attribute |= SERVICE_ATTR_INVALID;
|
||||
printf("[Init] InitReadCfg, bad number values for service %d.\n", i);
|
||||
printf("[Init] InitReadCfg, parse information for service %d failed.\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (GetServiceCaps(curItem, &retServices[i]) != SERVICE_SUCCESS) {
|
||||
retServices[i].attribute |= SERVICE_ATTR_INVALID;
|
||||
printf("[Init] InitReadCfg, bad caps values for service %d.\n", i);
|
||||
}
|
||||
}
|
||||
RegisterServices(retServices, servArrSize);
|
||||
}
|
||||
@ -301,3 +354,4 @@ void InitReadCfg()
|
||||
DoJob("post-init");
|
||||
ReleaseAllJobs();
|
||||
}
|
||||
|
43
src/init_service.c → services/src/init_service.c
Executable file → Normal file
43
src/init_service.c → services/src/init_service.c
Executable file → Normal file
@ -18,6 +18,7 @@
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
@ -32,6 +33,16 @@ static const int CRASH_TIME_LIMIT = 240;
|
||||
// maximum number of crashes within time CRASH_TIME_LIMIT for one service
|
||||
static const int CRASH_COUNT_LIMIT = 4;
|
||||
|
||||
static int SetAllAmbientCapability()
|
||||
{
|
||||
for (int i = 0; i <= CAP_LAST_CAP; ++i) {
|
||||
if (SetAmbientCapability(i) != 0) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
}
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
static int SetPerms(const Service *service)
|
||||
{
|
||||
if (KeepCapability() != 0) {
|
||||
@ -71,11 +82,24 @@ static int SetPerms(const Service *service)
|
||||
if (capset(&capHeader, capData) != 0) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
|
||||
if (service->servPerm.caps[i] == FULL_CAP) {
|
||||
return SetAllAmbientCapability();
|
||||
}
|
||||
if (SetAmbientCapability(service->servPerm.caps[i]) != 0) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
}
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
int ServiceStart(Service *service)
|
||||
{
|
||||
if (service == NULL) {
|
||||
printf("[Init] start service failed! null ptr.\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
if (service->attribute & SERVICE_ATTR_INVALID) {
|
||||
printf("[Init] start service %s invalid.\n", service->name);
|
||||
return SERVICE_FAILURE;
|
||||
@ -83,9 +107,10 @@ int ServiceStart(Service *service)
|
||||
|
||||
struct stat pathStat = {0};
|
||||
service->attribute &= (~(SERVICE_ATTR_NEED_RESTART | SERVICE_ATTR_NEED_STOP));
|
||||
if (stat(service->path, &pathStat) != 0) {
|
||||
if (stat(service->pathArgs[0], &pathStat) != 0) {
|
||||
service->attribute |= SERVICE_ATTR_INVALID;
|
||||
printf("[Init] start service %s invalid, please check %s.\n", service->name, service->path);
|
||||
printf("[Init] start service %s invalid, please check %s.\n",\
|
||||
service->name, service->pathArgs[0]);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
@ -97,9 +122,8 @@ int ServiceStart(Service *service)
|
||||
_exit(0x7f); // 0x7f: user specified
|
||||
}
|
||||
|
||||
char* argv[] = {service->name, NULL};
|
||||
char* env[] = {"LD_LIBRARY_PATH=/storage/app/libs", NULL};
|
||||
if (execve(service->path, argv, env) != 0) {
|
||||
if (execve(service->pathArgs[0], service->pathArgs, env) != 0) {
|
||||
printf("[Init] service %s execve failed! err %d.\n", service->name, errno);
|
||||
}
|
||||
_exit(0x7f); // 0x7f: user specified
|
||||
@ -115,6 +139,11 @@ int ServiceStart(Service *service)
|
||||
|
||||
int ServiceStop(Service *service)
|
||||
{
|
||||
if (service == NULL) {
|
||||
printf("[Init] stop service failed! null ptr.\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
service->attribute &= ~SERVICE_ATTR_NEED_RESTART;
|
||||
service->attribute |= SERVICE_ATTR_NEED_STOP;
|
||||
if (service->pid <= 0) {
|
||||
@ -132,6 +161,11 @@ int ServiceStop(Service *service)
|
||||
|
||||
void ServiceReap(Service *service)
|
||||
{
|
||||
if (service == NULL) {
|
||||
printf("[Init] reap service failed! null ptr.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
service->pid = -1;
|
||||
|
||||
// stopped by system-init itself, no need to restart even if it is not one-shot service
|
||||
@ -177,3 +211,4 @@ void ServiceReap(Service *service)
|
||||
|
||||
service->attribute &= (~SERVICE_ATTR_NEED_RESTART);
|
||||
}
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "init_adapter.h"
|
||||
#include "init_jobs.h"
|
||||
|
||||
static const int SLEEP_DURATION = 1;
|
||||
|
||||
// All serivce processes that init will fork+exec.
|
||||
static Service* g_services = NULL;
|
||||
@ -62,7 +61,6 @@ void StartServiceByName(const char* servName)
|
||||
printf("[Init] StartServiceByName, service %s start failed!\n", g_services[servIdx].name);
|
||||
}
|
||||
|
||||
sleep(SLEEP_DURATION);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -90,3 +88,4 @@ void ReapServiceByPID(int pid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
33
src/init_signal_handler.c → services/src/init_signal_handler.c
Executable file → Normal file
33
src/init_signal_handler.c → services/src/init_signal_handler.c
Executable file → Normal file
@ -18,21 +18,51 @@
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/wait.h>
|
||||
#ifdef __LINUX__
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#endif /* __LINUX__ */
|
||||
|
||||
#include "init_service_manager.h"
|
||||
|
||||
|
||||
#ifdef __LINUX__
|
||||
static pid_t g_waitPid = -1;
|
||||
static sem_t* g_waitSem = NULL;
|
||||
|
||||
void SignalRegWaitSem(pid_t waitPid, sem_t* waitSem)
|
||||
{
|
||||
g_waitPid = waitPid;
|
||||
g_waitSem = waitSem;
|
||||
}
|
||||
|
||||
static void CheckWaitPid(pid_t sigPID)
|
||||
{
|
||||
if (g_waitPid == sigPID && g_waitSem != NULL) {
|
||||
if (sem_post(g_waitSem) != 0) {
|
||||
printf("[Init] CheckWaitPid, sem_post failed, errno %d.\n", errno);
|
||||
}
|
||||
g_waitPid = -1;
|
||||
g_waitSem = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* __LINUX__ */
|
||||
|
||||
static void SigHandler(int sig)
|
||||
{
|
||||
switch (sig) {
|
||||
case SIGCHLD: {
|
||||
pid_t sigPID;
|
||||
int procStat = 0;
|
||||
printf("[Init] SigHandler, SIGCHLD received.\n");
|
||||
while (1) {
|
||||
sigPID = waitpid(-1, &procStat, WNOHANG);
|
||||
if (sigPID <= 0) {
|
||||
break;
|
||||
}
|
||||
printf("[Init] SigHandler, SIGCHLD received, sigPID = %d.\n", sigPID);
|
||||
#ifdef __LINUX__
|
||||
CheckWaitPid(sigPID);
|
||||
#endif /* __LINUX__ */
|
||||
ReapServiceByPID((int)sigPID);
|
||||
}
|
||||
break;
|
||||
@ -58,3 +88,4 @@ void SignalInitModule()
|
||||
sigaction(SIGCHLD, &act, NULL);
|
||||
sigaction(SIGTERM, &act, NULL);
|
||||
}
|
||||
|
118
services/src/main.c
Executable file
118
services/src/main.c
Executable file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef OHOS_DEBUG
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#endif // OHOS_DEBUG
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "init_adapter.h"
|
||||
#include "init_read_cfg.h"
|
||||
#include "init_signal_handler.h"
|
||||
#include "parameter.h"
|
||||
|
||||
static const pid_t INIT_PROCESS_PID = 1;
|
||||
|
||||
static void PrintSysInfo()
|
||||
{
|
||||
char* sysInfo = GetVersionId();
|
||||
if (sysInfo != NULL) {
|
||||
printf("[Init] %s\n", sysInfo);
|
||||
free(sysInfo);
|
||||
sysInfo = NULL;
|
||||
return;
|
||||
}
|
||||
printf("[Init] main, GetVersionId failed!\n");
|
||||
}
|
||||
|
||||
#ifdef OHOS_DEBUG
|
||||
static long TimeDiffMs(struct timespec* tmBefore, struct timespec* tmAfter)
|
||||
{
|
||||
if (tmBefore != NULL && tmAfter != NULL) {
|
||||
long timeUsed = (tmAfter->tv_sec - tmBefore->tv_sec) * 1000 + // 1 s = 1000 ms
|
||||
(tmAfter->tv_nsec - tmBefore->tv_nsec) / 1000000; // 1 ms = 1000000 ns
|
||||
return timeUsed;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif // OHOS_DEBUG
|
||||
|
||||
int main(int argc, char * const argv[])
|
||||
{
|
||||
#ifdef OHOS_DEBUG
|
||||
struct timespec tmEnter;
|
||||
if (clock_gettime(CLOCK_REALTIME, &tmEnter) != 0) {
|
||||
printf("[Init] main, enter, get time failed! err %d.\n", errno);
|
||||
}
|
||||
#endif // OHOS_DEBUG
|
||||
|
||||
if (getpid() != INIT_PROCESS_PID) {
|
||||
printf("[Init] main, current process id is %d not %d, failed!\n", getpid(), INIT_PROCESS_PID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 1. print system info
|
||||
PrintSysInfo();
|
||||
|
||||
// 2. signal register
|
||||
SignalInitModule();
|
||||
|
||||
#ifdef OHOS_DEBUG
|
||||
struct timespec tmSysInfo;
|
||||
if (clock_gettime(CLOCK_REALTIME, &tmSysInfo) != 0) {
|
||||
printf("[Init] main, after sysinfo, get time failed! err %d.\n", errno);
|
||||
}
|
||||
#endif // OHOS_DEBUG
|
||||
|
||||
// 3. execute rcs
|
||||
ExecuteRcs();
|
||||
|
||||
#ifdef OHOS_DEBUG
|
||||
struct timespec tmRcs;
|
||||
if (clock_gettime(CLOCK_REALTIME, &tmRcs) != 0) {
|
||||
printf("[Init] main, after rcs, get time failed! err %d.\n", errno);
|
||||
}
|
||||
#endif // OHOS_DEBUG
|
||||
|
||||
// 4. read configuration file and do jobs
|
||||
InitReadCfg();
|
||||
|
||||
#ifdef OHOS_DEBUG
|
||||
struct timespec tmCfg;
|
||||
if (clock_gettime(CLOCK_REALTIME, &tmCfg) != 0) {
|
||||
printf("[Init] main, after cfg, get time failed! err %d.\n", errno);
|
||||
}
|
||||
#endif // OHOS_DEBUG
|
||||
|
||||
// 5. keep process alive
|
||||
#ifdef OHOS_DEBUG
|
||||
printf("[Init] main, time used: sigInfo %ld ms, rcs %ld ms, cfg %ld ms.\n", \
|
||||
TimeDiffMs(&tmEnter, &tmSysInfo), TimeDiffMs(&tmSysInfo, &tmRcs), TimeDiffMs(&tmRcs, &tmCfg));
|
||||
#endif
|
||||
|
||||
printf("[Init] main, entering wait.\n");
|
||||
while (1) {
|
||||
// pause only returns when a signal was caught and the signal-catching function returned.
|
||||
// pause only returns -1, no need to process the return value.
|
||||
(void)pause();
|
||||
}
|
||||
return 0;
|
||||
}
|
177
services/test/LICENSE
Normal file
177
services/test/LICENSE
Normal file
@ -0,0 +1,177 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
50
services/test/unittest/common/BUILD.gn
Normal file
50
services/test/unittest/common/BUILD.gn
Normal file
@ -0,0 +1,50 @@
|
||||
# Copyright (c) 2020 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import("//build/lite/config/component/lite_component.gni")
|
||||
import("//build/lite/config/test.gni")
|
||||
|
||||
unittest("init_test") {
|
||||
output_extension = "bin"
|
||||
output_dir = "$root_out_dir/test/unittest/startup"
|
||||
ldflags = [
|
||||
"-lstdc++",
|
||||
"-lpthread",
|
||||
"-lm",
|
||||
]
|
||||
|
||||
if (storage_type == "emmc") {
|
||||
defines = [ "USE_EMMC_STORAGE" ]
|
||||
}
|
||||
|
||||
include_dirs = [ "//base/startup/init_lite/services/include" ]
|
||||
|
||||
sources = [
|
||||
"//base/startup/init_lite/services/src/init_adapter.c",
|
||||
"//base/startup/init_lite/services/src/init_cmds.c",
|
||||
"//base/startup/init_lite/services/src/init_jobs.c",
|
||||
"//base/startup/init_lite/services/src/init_service.c",
|
||||
"//base/startup/init_lite/services/src/init_service_manager.c",
|
||||
"//base/startup/init_lite/services/src/init_signal_handler.c",
|
||||
"cmd_func_test.cpp",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//base/startup/syspara_lite/frameworks/parameter:parameter",
|
||||
"//build/lite/config/component/cJSON:cjson_shared",
|
||||
"//third_party/bounds_checking_function:libsec_shared",
|
||||
]
|
||||
}
|
||||
|
||||
group("unittest") {
|
||||
deps = [ ":init_test" ]
|
||||
}
|
970
services/test/unittest/common/cmd_func_test.cpp
Normal file
970
services/test/unittest/common/cmd_func_test.cpp
Normal file
@ -0,0 +1,970 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include "cJSON.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "securec.h"
|
||||
#include "init_jobs.h"
|
||||
#include "init_service_manager.h"
|
||||
|
||||
using namespace testing::ext;
|
||||
|
||||
namespace OHOS {
|
||||
std::vector<std::string> g_supportedCmds;
|
||||
const std::string ROOT_DIR = "/storage/data/";
|
||||
const std::string TEST_DRI = ROOT_DIR + "StartInitTestDir";
|
||||
const std::string TEST_FILE = TEST_DRI + "/test.txt";
|
||||
const std::string TEST_CFG_ILLEGAL = TEST_DRI + "/illegal.cfg";
|
||||
const std::string TEST_PROC_MOUNTS = "/proc/mounts";
|
||||
const uid_t TEST_FILE_UID = 999;
|
||||
const gid_t TEST_FILE_GID = 999;
|
||||
const mode_t TEST_FILE_MODE = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
const mode_t DEFAULT_DIR_MODE = 0755;
|
||||
|
||||
// init.cfg releated
|
||||
const std::string CFG_FILE = "/etc/init.cfg";
|
||||
const std::string SERVICE_ARR_NAME_IN_JSON = "services";
|
||||
const std::string JOBS_ARR_NAME_IN_JSON = "jobs";
|
||||
const std::string CMDS_ARR_NAME_IN_JSON = "cmds";
|
||||
const uid_t CFG_FILE_UID = 0;
|
||||
const gid_t CFG_FILE_GID = 0;
|
||||
const mode_t CFG_FILE_MODE = S_IRUSR;
|
||||
const int JOBS_IN_FILE_COUNT = 3; // pre-init, init, post-init
|
||||
const int MAX_SERVICES_CNT_IN_FILE = 100;
|
||||
const int MAX_CAPS_CNT_FOR_ONE_SERVICE = 100;
|
||||
const unsigned int MAX_CAPABILITY_VALUE = 4294967295; // 0xFFFFFFFF
|
||||
const unsigned int MAX_JSON_FILE_LEN = 102400; // max init.cfg size 100KB
|
||||
const int MAX_PATH_ARGS_CNT = 20; // max path and args count
|
||||
const int MAX_ONE_ARG_LEN = 64; // max length of one param/path
|
||||
const int CAT_BUF_SIZE = 512; // standard Cat buffer size from vfs_shell_cmd
|
||||
|
||||
// job test releated
|
||||
const pid_t INVALID_PID = -1;
|
||||
const std::string PRE_INIT_DIR = ROOT_DIR + "preInitDir/";
|
||||
const std::string INIT_DIR = PRE_INIT_DIR + "initDir";
|
||||
const std::string POST_INIT_DIR = INIT_DIR + "postInitDir";
|
||||
|
||||
class StartupInitUTest : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
g_supportedCmds.push_back(std::string("start "));
|
||||
g_supportedCmds.push_back(std::string("mkdir "));
|
||||
g_supportedCmds.push_back(std::string("chmod "));
|
||||
g_supportedCmds.push_back(std::string("chown "));
|
||||
g_supportedCmds.push_back(std::string("mount "));
|
||||
g_supportedCmds.push_back(std::string("loadcfg "));
|
||||
|
||||
mode_t mode = DEFAULT_DIR_MODE;
|
||||
if (mkdir(TEST_DRI.c_str(), mode) != 0) {
|
||||
if (errno != EEXIST) {
|
||||
printf("[----------] StartupInitUTest, mkdir for %s failed, error %d.\n",\
|
||||
TEST_DRI.c_str(), errno);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FILE* testFile = fopen(TEST_FILE.c_str(), "w+");
|
||||
if (testFile == nullptr) {
|
||||
printf("[----------] StartupInitUTest, open file %s failed, error %d.\n",\
|
||||
TEST_FILE.c_str(), errno);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string writeContent = "This is a test file for startup subsystem init module.";
|
||||
if (fwrite(writeContent.c_str(), writeContent.length(), 1, testFile) != 1) {
|
||||
printf("[----------] StartupInitUTest, open file %s failed, error %d.\n", TEST_FILE.c_str(), errno);
|
||||
fclose(testFile);
|
||||
return;
|
||||
}
|
||||
fclose(testFile);
|
||||
|
||||
#ifndef USE_EMMC_STORAGE // emmc storage does not support chmod/chown
|
||||
|
||||
if (chmod(TEST_FILE.c_str(), TEST_FILE_MODE) != 0) {
|
||||
printf("[----------] StartupInitUTest, chmod for file %s failed, error %d.\n", TEST_FILE.c_str(), errno);
|
||||
return;
|
||||
}
|
||||
|
||||
if (chown(TEST_FILE.c_str(), TEST_FILE_UID, TEST_FILE_GID) != 0) {
|
||||
printf("[----------] StartupInitUTest, chown for file %s failed, error %d.\n", TEST_FILE.c_str(), errno);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif // USE_EMMC_STORAGE
|
||||
|
||||
printf("[----------] StartupInitUTest, cmd func test setup.\n");
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
if (remove(TEST_FILE.c_str()) != 0) {
|
||||
printf("[----------] StartupInitUTest, remove %s failed, error %d.\n", TEST_FILE.c_str(), errno);
|
||||
}
|
||||
|
||||
if (remove(TEST_DRI.c_str()) != 0) {
|
||||
printf("[----------] StartupInitUTest, remove %s failed, error %d.\n", TEST_DRI.c_str(), errno);
|
||||
}
|
||||
printf("[----------] StartupInitUTest, cmd func test teardown.\n");
|
||||
}
|
||||
void SetUp() {}
|
||||
void TearDown() {}
|
||||
};
|
||||
|
||||
/*
|
||||
** @tc.name: cmdFuncParseCmdTest_001
|
||||
** @tc.desc: parse function, nullptr test
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733F
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_001, TestSize.Level0)
|
||||
{
|
||||
// do not crash
|
||||
ParseCmdLine(nullptr, nullptr);
|
||||
};
|
||||
|
||||
/*
|
||||
** @tc.name: cmdFuncParseCmdTest_002
|
||||
** @tc.desc: parse function, invalid strings test
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733F
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_002, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
|
||||
ParseCmdLine(nullptr, &curCmdLine);
|
||||
EXPECT_EQ(0, strlen(curCmdLine.name));
|
||||
EXPECT_EQ(0, strlen(curCmdLine.cmdContent));
|
||||
|
||||
ParseCmdLine("", &curCmdLine);
|
||||
EXPECT_EQ(0, strlen(curCmdLine.name));
|
||||
EXPECT_EQ(0, strlen(curCmdLine.cmdContent));
|
||||
|
||||
ParseCmdLine("xxxxxxxx", &curCmdLine);
|
||||
EXPECT_EQ(0, strlen(curCmdLine.name));
|
||||
EXPECT_EQ(0, strlen(curCmdLine.cmdContent));
|
||||
|
||||
ParseCmdLine("asdnkawdqw4145a45sdqw_-+\\\\sdqwdasd", &curCmdLine);
|
||||
EXPECT_EQ(0, strlen(curCmdLine.name));
|
||||
EXPECT_EQ(0, strlen(curCmdLine.cmdContent));
|
||||
}
|
||||
|
||||
/*
|
||||
** @tc.name: cmdFuncParseCmdTest_003
|
||||
** @tc.desc: parse function, cmd content empty test
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733F
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_003, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
|
||||
for (size_t i = 0; i < g_supportedCmds.size(); ++i) {
|
||||
ParseCmdLine(g_supportedCmds[i].c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strlen(curCmdLine.name));
|
||||
EXPECT_EQ(0, strlen(curCmdLine.cmdContent));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** @tc.name: cmdFuncParseCmdTest_004
|
||||
** @tc.desc: parse function, cmd content too long test
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733F
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_004, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
|
||||
char toLongContent[MAX_CMD_CONTENT_LEN + 10];
|
||||
memset_s(toLongContent, MAX_CMD_CONTENT_LEN + 10, 'x', MAX_CMD_CONTENT_LEN + 9);
|
||||
toLongContent[MAX_CMD_CONTENT_LEN + 9] = '\0';
|
||||
for (size_t i = 0; i < g_supportedCmds.size(); ++i) {
|
||||
size_t curCmdLen = g_supportedCmds[i].length();
|
||||
char* curCmd = (char*)malloc(curCmdLen + MAX_CMD_CONTENT_LEN + 10);
|
||||
if (curCmd == nullptr) {
|
||||
printf("[----------] StartupInitUTest, cmdFuncParseCmdTest004, malloc failed.\n");
|
||||
break;
|
||||
}
|
||||
errno_t ret = memcpy_s(curCmd, curCmdLen + MAX_CMD_CONTENT_LEN + 10, \
|
||||
g_supportedCmds[i].c_str(), curCmdLen);
|
||||
errno_t ret2 = memcpy_s(curCmd + curCmdLen, MAX_CMD_CONTENT_LEN + 10, \
|
||||
toLongContent, strlen(toLongContent));
|
||||
if (ret != EOK || ret2 != EOK) {
|
||||
printf("[----------] StartupInitUTest, cmdFuncParseCmdTest004, memcpy_s failed.\n");
|
||||
free(curCmd);
|
||||
curCmd = nullptr;
|
||||
break;
|
||||
}
|
||||
curCmd[curCmdLen + MAX_CMD_CONTENT_LEN + 9] = '\0';
|
||||
|
||||
ParseCmdLine(curCmd, &curCmdLine);
|
||||
EXPECT_EQ(0, strlen(curCmdLine.name));
|
||||
EXPECT_EQ(0, strlen(curCmdLine.cmdContent));
|
||||
free(curCmd);
|
||||
curCmd = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** @tc.name: cmdFuncParseCmdTest_005
|
||||
** @tc.desc: parse function, parse success test
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733E
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_005, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
|
||||
ParseCmdLine("start InitTestService", &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp("start ", curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp("InitTestService", curCmdLine.cmdContent));
|
||||
|
||||
ParseCmdLine("mkdir InitTestDir", &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp("mkdir ", curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp("InitTestDir", curCmdLine.cmdContent));
|
||||
|
||||
ParseCmdLine("chmod 0500 /bin/InitTestBin", &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp("chmod ", curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp("0500 /bin/InitTestBin", curCmdLine.cmdContent));
|
||||
|
||||
ParseCmdLine("chown 1000 1000 /bin/InitTestBin", &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp("chown ", curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp("1000 1000 /bin/InitTestBin", curCmdLine.cmdContent));
|
||||
|
||||
ParseCmdLine("mount vfat /dev/mmcblk1 /sdcard rw,umask=000", &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp("mount ", curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp("vfat /dev/mmcblk1 /sdcard rw,umask=000", curCmdLine.cmdContent));
|
||||
};
|
||||
|
||||
/*
|
||||
** @tc.name: cmdFuncDoCmdTest_001
|
||||
** @tc.desc: do cmd function, nullptr test
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733E
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_001, TestSize.Level0)
|
||||
{
|
||||
// do not crash here
|
||||
DoCmd(nullptr);
|
||||
}
|
||||
|
||||
/*
|
||||
** @tc.name: cmdFuncDoCmdTest_002
|
||||
** @tc.desc: do cmd function, do start fail test
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733E
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_002, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
|
||||
std::string cmdStr = "start ";
|
||||
std::string cmdContentStr = "NameNotExist";
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
DoCmd(&curCmdLine);
|
||||
}
|
||||
|
||||
/*
|
||||
** @tc.name: cmdFuncDoCmdTest_003
|
||||
** @tc.desc: do cmd function, do mkdir fail test
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733E
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_003, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
|
||||
std::string cmdStr = "mkdir ";
|
||||
std::string cmdContentStr = "/DirNotExist/DirNotExist/DirNotExist";
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
DoCmd(&curCmdLine);
|
||||
|
||||
// make sure that the directory does not exist
|
||||
DIR* dirTmp = opendir(cmdContentStr.c_str());
|
||||
EXPECT_TRUE(dirTmp == nullptr);
|
||||
EXPECT_TRUE(errno == ENOENT);
|
||||
if (dirTmp != nullptr) { // just in case
|
||||
closedir(dirTmp);
|
||||
dirTmp = nullptr;
|
||||
}
|
||||
|
||||
// too many spaces, bad format
|
||||
cmdContentStr = " /storage/data/cmdFuncDoCmdTest003 ";
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
DoCmd(&curCmdLine);
|
||||
|
||||
// make sure that the directory does not exist
|
||||
dirTmp = opendir("/storage/data/cmdFuncDoCmdTest003");
|
||||
EXPECT_TRUE(dirTmp == nullptr);
|
||||
EXPECT_TRUE(errno == ENOENT);
|
||||
if (dirTmp != nullptr) { // just in case
|
||||
closedir(dirTmp);
|
||||
dirTmp = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** @tc.name: cmdFuncDoCmdTest_004
|
||||
** @tc.desc: do cmd function, do chmod fail test
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F732P
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_004, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
|
||||
std::string cmdStr = "chmod ";
|
||||
std::string cmdContentStr = "755 " + TEST_FILE; // should be 0755, wrong format here
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
DoCmd(&curCmdLine);
|
||||
|
||||
cmdContentStr = "0855 " + TEST_FILE; // should not exceed 0777, wrong format here
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
DoCmd(&curCmdLine);
|
||||
|
||||
cmdContentStr = "07b5 " + TEST_FILE; // non-digital character, wrong format here
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
DoCmd(&curCmdLine);
|
||||
|
||||
cmdContentStr = "075 " + TEST_FILE; // should be 0xxx, wrong format here
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
DoCmd(&curCmdLine);
|
||||
|
||||
cmdContentStr = "0755 " + TEST_FILE; // too many spaces, wrong format here
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
DoCmd(&curCmdLine);
|
||||
|
||||
struct stat testFileStat = {0};
|
||||
EXPECT_EQ(0, stat(TEST_FILE.c_str(), &testFileStat));
|
||||
|
||||
#ifndef USE_EMMC_STORAGE // emmc storage does not support chmod/chown
|
||||
|
||||
EXPECT_EQ(TEST_FILE_MODE, testFileStat.st_mode & TEST_FILE_MODE); // file mode is not changed
|
||||
|
||||
#endif // USE_EMMC_STORAGE
|
||||
}
|
||||
|
||||
/*
|
||||
** @tc.name: cmdFuncDoCmdTest_005
|
||||
** @tc.desc: do cmd function, do chown fail test
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F732P
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_005, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
|
||||
std::string cmdStr = "chown ";
|
||||
std::string cmdContentStr = "888 " + TEST_FILE; // uid or gid missing, wrong format here
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
DoCmd(&curCmdLine);
|
||||
|
||||
cmdContentStr = "888 888 " + TEST_FILE; // too many spaces, wrong format here
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
DoCmd(&curCmdLine);
|
||||
|
||||
cmdContentStr = "888 8b9 " + TEST_FILE; // non-digital character, wrong format here
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
DoCmd(&curCmdLine);
|
||||
|
||||
struct stat testFileStat = {0};
|
||||
EXPECT_EQ(0, stat(TEST_FILE.c_str(), &testFileStat));
|
||||
|
||||
#ifndef USE_EMMC_STORAGE // emmc storage does not support chmod/chown
|
||||
|
||||
EXPECT_EQ(testFileStat.st_uid, TEST_FILE_UID); // uid not changed
|
||||
EXPECT_EQ(testFileStat.st_gid, TEST_FILE_GID); // gid not changed
|
||||
|
||||
#endif // USE_EMMC_STORAGE
|
||||
}
|
||||
|
||||
/*
|
||||
** @tc.name: cmdFuncDoCmdTest_006
|
||||
** @tc.desc: do cmd function, do success test
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F732P
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_006, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
|
||||
// mkdir success
|
||||
std::string cmdStr = "mkdir ";
|
||||
std::string cmdContentStr = TEST_DRI + "/cmdFuncDoCmdTest006";
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
|
||||
DoCmd(&curCmdLine);
|
||||
DIR* dirTmp = opendir(cmdContentStr.c_str());
|
||||
EXPECT_TRUE(dirTmp != nullptr);
|
||||
if (dirTmp != nullptr) {
|
||||
closedir(dirTmp);
|
||||
dirTmp = nullptr;
|
||||
}
|
||||
|
||||
// delete dir
|
||||
if (remove(cmdContentStr.c_str()) != 0) {
|
||||
printf("[----------] StartupInitUTest, cmdFuncDoCmdTest006 remove %s failed, error %d.\n",\
|
||||
TEST_DRI.c_str(), errno);
|
||||
}
|
||||
|
||||
// chmod success
|
||||
cmdStr = "chmod ";
|
||||
cmdContentStr = "0440 " + TEST_FILE;
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
|
||||
#ifndef USE_EMMC_STORAGE // emmc storage does not support chmod/chown
|
||||
|
||||
DoCmd(&curCmdLine);
|
||||
struct stat testFileStat = {0};
|
||||
EXPECT_EQ(0, stat(TEST_FILE.c_str(), &testFileStat));
|
||||
mode_t targetMode = S_IRUSR | S_IRGRP;
|
||||
EXPECT_EQ(targetMode, testFileStat.st_mode & targetMode); // changed
|
||||
|
||||
#endif // USE_EMMC_STORAGE
|
||||
|
||||
// chown success
|
||||
cmdStr = "chown ";
|
||||
cmdContentStr = "888 888 " + TEST_FILE;
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
|
||||
#ifndef USE_EMMC_STORAGE // emmc storage does not support chmod/chown
|
||||
|
||||
DoCmd(&curCmdLine);
|
||||
EXPECT_EQ(0, stat(TEST_FILE.c_str(), &testFileStat));
|
||||
EXPECT_EQ(testFileStat.st_uid, 888); // changed
|
||||
EXPECT_EQ(testFileStat.st_gid, 888); // changed
|
||||
|
||||
#endif // USE_EMMC_STORAGE
|
||||
}
|
||||
|
||||
/*
|
||||
** @tc.name: cfgCheckStat_001
|
||||
** @tc.desc: init.cfg file state check
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733F
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cfgCheckStat_001, TestSize.Level0)
|
||||
{
|
||||
struct stat fileStat = {0};
|
||||
EXPECT_EQ(0, stat(CFG_FILE.c_str(), &fileStat));
|
||||
EXPECT_EQ(CFG_FILE_UID, fileStat.st_uid);
|
||||
EXPECT_EQ(CFG_FILE_GID, fileStat.st_gid);
|
||||
EXPECT_EQ(CFG_FILE_MODE, CFG_FILE_MODE & fileStat.st_mode);
|
||||
EXPECT_TRUE(fileStat.st_size > 0);
|
||||
EXPECT_TRUE(fileStat.st_size <= MAX_JSON_FILE_LEN);
|
||||
};
|
||||
|
||||
static char* ReadFileToBuf()
|
||||
{
|
||||
char* buffer = nullptr;
|
||||
FILE* fd = nullptr;
|
||||
struct stat fileStat = {0};
|
||||
(void)stat(CFG_FILE.c_str(), &fileStat);
|
||||
do {
|
||||
fd = fopen(CFG_FILE.c_str(), "r");
|
||||
if (fd == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
buffer = (char*)malloc(fileStat.st_size + 1);
|
||||
if (buffer == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (fread(buffer, fileStat.st_size, 1, fd) != 1) {
|
||||
free(buffer);
|
||||
buffer = nullptr;
|
||||
break;
|
||||
}
|
||||
buffer[fileStat.st_size] = '\0';
|
||||
} while (0);
|
||||
|
||||
if (fd != nullptr) {
|
||||
fclose(fd);
|
||||
fd = nullptr;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static cJSON* GetArrItem(const cJSON* fileRoot, int& arrSize, const std::string& arrName)
|
||||
{
|
||||
cJSON* arrItem = cJSON_GetObjectItemCaseSensitive(fileRoot, arrName.c_str());
|
||||
arrSize = cJSON_GetArraySize(arrItem);
|
||||
if (arrSize <= 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return arrItem;
|
||||
}
|
||||
|
||||
static int IsForbidden(const char* fieldStr)
|
||||
{
|
||||
size_t fieldLen = strlen(fieldStr);
|
||||
size_t forbidStrLen = strlen("/bin/sh");
|
||||
if (fieldLen == forbidStrLen) {
|
||||
if (strncmp(fieldStr, "/bin/sh", fieldLen) == 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
} else if (fieldLen > forbidStrLen) {
|
||||
// "/bin/shxxxx" is valid but "/bin/sh xxxx" is invalid
|
||||
if (strncmp(fieldStr, "/bin/sh", forbidStrLen) == 0) {
|
||||
if (fieldStr[forbidStrLen] == ' ') {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckService(const cJSON* curItem)
|
||||
{
|
||||
if (curItem == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
char* nameStr = cJSON_GetStringValue(cJSON_GetObjectItem(curItem, "name"));
|
||||
if (nameStr == nullptr) {
|
||||
EXPECT_TRUE(nameStr != nullptr);
|
||||
} else {
|
||||
EXPECT_TRUE(strlen(nameStr) > 0);
|
||||
}
|
||||
|
||||
cJSON* pathArgsItem = cJSON_GetObjectItem(curItem, "path");
|
||||
EXPECT_TRUE(cJSON_IsArray(pathArgsItem));
|
||||
|
||||
int pathArgsCnt = cJSON_GetArraySize(pathArgsItem);
|
||||
EXPECT_TRUE(pathArgsCnt > 0);
|
||||
EXPECT_TRUE(pathArgsCnt <= MAX_PATH_ARGS_CNT);
|
||||
|
||||
for (int i = 0; i < pathArgsCnt; ++i) {
|
||||
char* curParam = cJSON_GetStringValue(cJSON_GetArrayItem(pathArgsItem, i));
|
||||
EXPECT_TRUE(curParam != NULL);
|
||||
EXPECT_TRUE(strlen(curParam) > 0);
|
||||
EXPECT_TRUE(strlen(curParam) <= MAX_ONE_ARG_LEN);
|
||||
if (i == 0) {
|
||||
EXPECT_TRUE(IsForbidden(curParam) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
cJSON* filedJ = cJSON_GetObjectItem(curItem, "uid");
|
||||
EXPECT_TRUE(cJSON_IsNumber(filedJ));
|
||||
EXPECT_TRUE(cJSON_GetNumberValue(filedJ) >= 0.0);
|
||||
|
||||
filedJ = cJSON_GetObjectItem(curItem, "gid");
|
||||
EXPECT_TRUE(cJSON_IsNumber(filedJ));
|
||||
EXPECT_TRUE(cJSON_GetNumberValue(filedJ) >= 0.0);
|
||||
|
||||
filedJ = cJSON_GetObjectItem(curItem, "once");
|
||||
EXPECT_TRUE(cJSON_IsNumber(filedJ));
|
||||
|
||||
filedJ = cJSON_GetObjectItem(curItem, "importance");
|
||||
EXPECT_TRUE(cJSON_IsNumber(filedJ));
|
||||
|
||||
filedJ = cJSON_GetObjectItem(curItem, "caps");
|
||||
EXPECT_TRUE(cJSON_IsArray(filedJ));
|
||||
int capsCnt = cJSON_GetArraySize(filedJ);
|
||||
EXPECT_TRUE(capsCnt <= MAX_CAPS_CNT_FOR_ONE_SERVICE);
|
||||
for (int i = 0; i < capsCnt; ++i) {
|
||||
cJSON* capJ = cJSON_GetArrayItem(filedJ, i);
|
||||
EXPECT_TRUE(cJSON_IsNumber(capJ));
|
||||
EXPECT_TRUE(cJSON_GetNumberValue(capJ) >= 0.0);
|
||||
|
||||
// only shell can have all capabilities
|
||||
if ((unsigned int)cJSON_GetNumberValue(capJ) == MAX_CAPABILITY_VALUE) {
|
||||
if (nameStr != nullptr) {
|
||||
EXPECT_EQ(0, strcmp(nameStr, "shell"));
|
||||
}
|
||||
EXPECT_EQ(1, capsCnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckServices(const cJSON* fileRoot)
|
||||
{
|
||||
int servArrSize = 0;
|
||||
cJSON* serviceArr = GetArrItem(fileRoot, servArrSize, SERVICE_ARR_NAME_IN_JSON);
|
||||
EXPECT_TRUE(serviceArr != nullptr);
|
||||
EXPECT_TRUE(servArrSize <= MAX_SERVICES_CNT_IN_FILE);
|
||||
|
||||
for (int i = 0; i < servArrSize; ++i) {
|
||||
cJSON* curItem = cJSON_GetArrayItem(serviceArr, i);
|
||||
EXPECT_TRUE(curItem != nullptr);
|
||||
CheckService(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckCmd(const CmdLine* resCmd)
|
||||
{
|
||||
EXPECT_TRUE(strlen(resCmd->name) > 0);
|
||||
EXPECT_TRUE(strlen(resCmd->cmdContent) > 0);
|
||||
|
||||
if (strcmp("start ", resCmd->name) == 0) {
|
||||
for (size_t i = 0; i < strlen(resCmd->cmdContent); ++i) {
|
||||
EXPECT_NE(' ', resCmd->cmdContent[i]); // no spaces in service name
|
||||
}
|
||||
} else if (strcmp("mkdir ", resCmd->name) == 0) {
|
||||
for (size_t i = 0; i < strlen(resCmd->cmdContent); ++i) {
|
||||
EXPECT_NE(' ', resCmd->cmdContent[i]); // no spaces in path string
|
||||
EXPECT_NE('.', resCmd->cmdContent[i]); // no dots in path string
|
||||
}
|
||||
} else if (strcmp("chmod ", resCmd->name) == 0) {
|
||||
EXPECT_TRUE(strlen(resCmd->cmdContent) >= 6); // 0xxx x at least 6 characters
|
||||
EXPECT_EQ('0', resCmd->cmdContent[0]);
|
||||
EXPECT_EQ(' ', resCmd->cmdContent[4]); // 4 bytes, after 0xxx must be space
|
||||
for (int i = 1; i < 4; ++i) { // 4 bytes, 0xxx, xxx must be digits
|
||||
EXPECT_TRUE(resCmd->cmdContent[i] >= '0' && resCmd->cmdContent[i] <= '7');
|
||||
}
|
||||
for (size_t i = 5; i < strlen(resCmd->cmdContent); ++i) { // target starts from index 5
|
||||
EXPECT_NE(' ', resCmd->cmdContent[i]); // no spaces allowed
|
||||
EXPECT_NE('.', resCmd->cmdContent[i]); // no dots allowed
|
||||
}
|
||||
} else if (strcmp("chown ", resCmd->name) == 0) {
|
||||
EXPECT_TRUE(strlen(resCmd->cmdContent) >= 5); // x y z at least 5 characters
|
||||
EXPECT_NE(' ', resCmd->cmdContent[0]); // should not start with space
|
||||
EXPECT_NE(' ', resCmd->cmdContent[strlen(resCmd->cmdContent) - 1]); // should not end with space
|
||||
size_t spacePos = 0;
|
||||
size_t spaceCnt = 0;
|
||||
for (size_t i = 1; i < strlen(resCmd->cmdContent); ++i) {
|
||||
if (resCmd->cmdContent[i] == ' ') {
|
||||
++spaceCnt;
|
||||
if (spacePos != 0) {
|
||||
EXPECT_NE(spacePos + 1, i); // consecutive spaces should not appear
|
||||
}
|
||||
spacePos = i;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(spaceCnt, 2); // 2 spaces allowed in cmd content
|
||||
} else if (strcmp("mount ", resCmd->name) == 0) {
|
||||
EXPECT_NE(' ', resCmd->cmdContent[0]); // should not start with space
|
||||
} else if (strcmp("loadcfg ", resCmd->name) == 0) {
|
||||
EXPECT_NE(' ', resCmd->cmdContent[0]); // should not start with space
|
||||
} else { // unknown cmd
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckJob(const cJSON* jobItem)
|
||||
{
|
||||
if (jobItem == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON* cmdsItem = cJSON_GetObjectItem(jobItem, CMDS_ARR_NAME_IN_JSON.c_str());
|
||||
EXPECT_TRUE(cmdsItem != nullptr);
|
||||
EXPECT_TRUE(cJSON_IsArray(cmdsItem));
|
||||
|
||||
int cmdLinesCnt = cJSON_GetArraySize(cmdsItem);
|
||||
EXPECT_TRUE(cmdLinesCnt <= MAX_CMD_CNT_IN_ONE_JOB);
|
||||
|
||||
for (int i = 0; i < cmdLinesCnt; ++i) {
|
||||
char* cmdLineStr = cJSON_GetStringValue(cJSON_GetArrayItem(cmdsItem, i));
|
||||
EXPECT_TRUE(cmdLineStr != nullptr);
|
||||
EXPECT_TRUE(strlen(cmdLineStr) > 0);
|
||||
|
||||
CmdLine resCmd;
|
||||
(void)memset_s(&resCmd, sizeof(resCmd), 0, sizeof(resCmd));
|
||||
ParseCmdLine(cmdLineStr, &resCmd);
|
||||
CheckCmd(&resCmd);
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckJobs(const cJSON* fileRoot)
|
||||
{
|
||||
int jobArrSize = 0;
|
||||
cJSON* jobArr = GetArrItem(fileRoot, jobArrSize, JOBS_ARR_NAME_IN_JSON);
|
||||
EXPECT_TRUE(jobArr != nullptr);
|
||||
EXPECT_TRUE(jobArrSize == JOBS_IN_FILE_COUNT);
|
||||
|
||||
bool findPreInit = false;
|
||||
bool findInit = false;
|
||||
bool findPostInit = false;
|
||||
for (int i = 0; i < jobArrSize; ++i) {
|
||||
cJSON* jobItem = cJSON_GetArrayItem(jobArr, i);
|
||||
EXPECT_TRUE(jobItem != nullptr);
|
||||
char* jobNameStr = cJSON_GetStringValue(cJSON_GetObjectItem(jobItem, "name"));
|
||||
EXPECT_TRUE(jobNameStr != nullptr);
|
||||
if (strcmp(jobNameStr, "pre-init") == 0) {
|
||||
findPreInit = true;
|
||||
} else if (strcmp(jobNameStr, "init") == 0) {
|
||||
findInit = true;
|
||||
} else if (strcmp(jobNameStr, "post-init") == 0) {
|
||||
findPostInit = true;
|
||||
} else {
|
||||
EXPECT_TRUE(false); // unknown job name
|
||||
continue;
|
||||
}
|
||||
|
||||
CheckJob(jobItem);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(findPreInit && findInit && findPostInit);
|
||||
}
|
||||
|
||||
/*
|
||||
** @tc.name: cfgCheckContent_001
|
||||
** @tc.desc: init.cfg file content check
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733F
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cfgCheckContent_001, TestSize.Level0)
|
||||
{
|
||||
char* fileBuf = ReadFileToBuf();
|
||||
if (fileBuf == nullptr) {
|
||||
EXPECT_TRUE(fileBuf != nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON* fileRoot = cJSON_Parse(fileBuf);
|
||||
free(fileBuf);
|
||||
fileBuf = nullptr;
|
||||
|
||||
EXPECT_TRUE(fileRoot != nullptr);
|
||||
|
||||
CheckServices(fileRoot);
|
||||
CheckJobs(fileRoot);
|
||||
cJSON_Delete(fileRoot);
|
||||
fileRoot = nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* @tc.name: CreateIllegalCfg
|
||||
* @tc.desc: Create illegal Config file for testing
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: AR000F861Q
|
||||
*/
|
||||
static void CreateIllegalCfg()
|
||||
{
|
||||
FILE* testCfgFile = fopen(TEST_CFG_ILLEGAL.c_str(), "w+");
|
||||
if (testCfgFile == nullptr) {
|
||||
printf("[----------] StartupInitUTest, open file %s failed, error %d.\n", TEST_CFG_ILLEGAL.c_str(), errno);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string writeContent = "mount zpfs /patch/etc:/etc /etc";
|
||||
if (fwrite(writeContent.c_str(), writeContent.length(), 1, testCfgFile) != 1) {
|
||||
printf("[----------] StartupInitUTest, open file %s failed, error %d.\n", TEST_CFG_ILLEGAL.c_str(), errno);
|
||||
fclose(testCfgFile);
|
||||
return;
|
||||
}
|
||||
|
||||
fclose(testCfgFile);
|
||||
}
|
||||
|
||||
/*
|
||||
* @tc.name: cmdFuncDoLoadCfgTest_001
|
||||
* @tc.desc: parse function, parse success test
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: AR000F861Q
|
||||
*/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_001, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
|
||||
ParseCmdLine("loadcfg /patch/fstab.cfg", &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp("loadcfg ", curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp("/patch/fstab.cfg", curCmdLine.cmdContent));
|
||||
};
|
||||
|
||||
/*
|
||||
* @tc.name: cmdFuncDoLoadCfgTest_002
|
||||
* @tc.desc: fstab.cfg file fail test
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: AR000F861Q
|
||||
*/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_002, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
std::string cmdStr = "loadcfg ";
|
||||
std::string cmdContentStr = "/patch/file_not_exist.cfg";
|
||||
struct stat testCfgStat = {0};
|
||||
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
stat(cmdContentStr.c_str(), &testCfgStat);
|
||||
EXPECT_TRUE(testCfgStat.st_size == 0);
|
||||
DoCmd(&curCmdLine);
|
||||
|
||||
cmdContentStr = TEST_CFG_ILLEGAL;
|
||||
CreateIllegalCfg();
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
EXPECT_EQ(0, stat(cmdContentStr.c_str(), &testCfgStat));
|
||||
EXPECT_TRUE(testCfgStat.st_size > 0);
|
||||
DoCmd(&curCmdLine);
|
||||
|
||||
// remove tmp file
|
||||
if (remove(TEST_CFG_ILLEGAL.c_str()) != 0) {
|
||||
printf("[----------] StartupInitUTest, remove %s failed, error %d.\n",\
|
||||
TEST_CFG_ILLEGAL.c_str(), errno);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @tc.name: cmdFuncDoLoadCfgTest_003
|
||||
* @tc.desc: fstab.cfg file success test
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: AR000F861Q
|
||||
*/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_003, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
std::string cmdStr = "loadcfg ";
|
||||
std::string cmdContentStr = "/patch/fstab.cfg";
|
||||
char buf[CAT_BUF_SIZE] = {0};
|
||||
struct stat testCfgStat = {0};
|
||||
FILE* fd = nullptr;
|
||||
size_t size;
|
||||
bool hasZpfs = false;
|
||||
|
||||
ParseCmdLine((cmdStr + cmdContentStr).c_str(), &curCmdLine);
|
||||
EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name));
|
||||
EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent));
|
||||
|
||||
DoCmd(&curCmdLine);
|
||||
|
||||
stat(cmdContentStr.c_str(), &testCfgStat);
|
||||
if (testCfgStat.st_size > 0) {
|
||||
fd = fopen(TEST_PROC_MOUNTS.c_str(), "r");
|
||||
|
||||
if (fd == nullptr) {
|
||||
EXPECT_TRUE(fd != nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
size = fread(buf, 1, CAT_BUF_SIZE, fd);
|
||||
if (size < 0) {
|
||||
EXPECT_TRUE(size >= 0);
|
||||
break;
|
||||
}
|
||||
if (strstr(buf, "zpfs") != nullptr) {
|
||||
hasZpfs = true;
|
||||
break;
|
||||
}
|
||||
} while (size > 0);
|
||||
EXPECT_TRUE(hasZpfs == true);
|
||||
fclose(fd);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @tc.name: cmdJobTest_001
|
||||
* @tc.desc: job functions test
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: AR000F733F
|
||||
*/
|
||||
HWTEST_F(StartupInitUTest, cmdJobTest_001, TestSize.Level0)
|
||||
{
|
||||
// functions do not crash
|
||||
ParseAllJobs(nullptr);
|
||||
DoJob(nullptr);
|
||||
DoJob("job name does not exist");
|
||||
ReleaseAllJobs();
|
||||
RegisterServices(nullptr, 0);
|
||||
StartServiceByName("service name does not exist");
|
||||
StopAllServices();
|
||||
ReapServiceByPID(INVALID_PID);
|
||||
ServiceReap(nullptr);
|
||||
EXPECT_NE(0, ServiceStart(nullptr));
|
||||
EXPECT_NE(0, ServiceStop(nullptr));
|
||||
}
|
||||
|
||||
/*
|
||||
* @tc.name: cmdJobTest_002
|
||||
* @tc.desc: job functions test
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: AR000F733F
|
||||
*/
|
||||
HWTEST_F(StartupInitUTest, cmdJobTest_002, TestSize.Level0)
|
||||
{
|
||||
std::string cfgJson = "{\"jobs\":[{\"name\":\"pre-init\",\"cmds\":[\"mkdir " +
|
||||
PRE_INIT_DIR + "\"]},{\"name\":\"init\",\"cmds\":[\"mkdir " + INIT_DIR +
|
||||
"\"]},{\"name\":\"post-init\",\"cmds\":[\"mkdir " + POST_INIT_DIR + "\"]}]}";
|
||||
cJSON* jobItem = cJSON_Parse(cfgJson.c_str());
|
||||
EXPECT_NE(nullptr, jobItem);
|
||||
if (jobItem == nullptr) {
|
||||
printf("[----------] StartupInitUTest, job test, parse %s failed.\n", cfgJson.c_str());
|
||||
return;
|
||||
}
|
||||
ParseAllJobs(jobItem);
|
||||
DoJob("pre-init");
|
||||
DoJob("init");
|
||||
DoJob("post-init");
|
||||
|
||||
// check if dir exists
|
||||
struct stat postDirStat = {0};
|
||||
EXPECT_EQ(0, stat(POST_INIT_DIR.c_str(), &postDirStat));
|
||||
|
||||
// release resource
|
||||
cJSON_Delete(jobItem);
|
||||
if (remove(POST_INIT_DIR.c_str()) != 0 ||
|
||||
remove(INIT_DIR.c_str()) != 0 ||
|
||||
remove(PRE_INIT_DIR.c_str()) != 0) {
|
||||
printf("[----------] StartupInitUTest, job test, remove failed, error %d.\n", errno);
|
||||
}
|
||||
ReleaseAllJobs();
|
||||
}
|
||||
} // namespace OHOS
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "init_adapter.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/prctl.h>
|
||||
#ifdef __LINUX__
|
||||
#include <sys/reboot.h>
|
||||
#else
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
void RebootSystem()
|
||||
{
|
||||
#ifdef __LINUX__
|
||||
int ret = reboot(RB_DISABLE_CAD);
|
||||
#else
|
||||
int ret = syscall(__NR_shellexec, "reset", "reset");
|
||||
#endif
|
||||
if (ret != 0) {
|
||||
printf("[Init] reboot failed! syscall ret %d, err %d.\n", ret, errno);
|
||||
}
|
||||
}
|
||||
|
||||
int KeepCapability()
|
||||
{
|
||||
#ifdef __LINUX__
|
||||
if (prctl(PR_SET_KEEPCAPS, 1)) {
|
||||
printf("[Init] prctl failed\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
55
src/main.c
55
src/main.c
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "init_read_cfg.h"
|
||||
#include "init_signal_handler.h"
|
||||
#include "parameter.h"
|
||||
|
||||
static void PrintSysInfo()
|
||||
{
|
||||
char* sysInfo = GetVersionId();
|
||||
if (sysInfo != NULL) {
|
||||
printf("[Init] %s\n", sysInfo);
|
||||
free(sysInfo);
|
||||
sysInfo = NULL;
|
||||
return;
|
||||
}
|
||||
printf("[Init] main, GetVersionId failed!\n");
|
||||
}
|
||||
|
||||
int main(int argc, char * const argv[])
|
||||
{
|
||||
// 1. print system info
|
||||
PrintSysInfo();
|
||||
|
||||
// 2. signal register
|
||||
SignalInitModule();
|
||||
|
||||
// 3. read configuration file and do jobs
|
||||
InitReadCfg();
|
||||
|
||||
// 4. keep process alive
|
||||
printf("[Init] main, entering wait.\n");
|
||||
while (1) {
|
||||
// pause only returns when a signal was caught and the signal-catching function returned.
|
||||
// pause only returns -1, no need to process the return value.
|
||||
(void)pause();
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user