1/*
2* Copyright (c) 2021 Huawei Device Co., Ltd.
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7*     http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14*/
15
16#include "service_control.h"
17
18#include <errno.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include "beget_ext.h"
24#include "init_utils.h"
25#include "init_param.h"
26#include "parameter.h"
27#include "securec.h"
28
29static int StartProcess(const char *name, const char *extArgv[], int extArgc)
30{
31    BEGET_ERROR_CHECK(name != NULL, return -1, "Service name is null.");
32    int extraArg = 0;
33    if ((extArgv != NULL) && (extArgc > 0)) {
34        BEGET_LOGI("Start service by extra args");
35        extraArg = 1;
36    }
37    int ret = 0;
38    if (extraArg == 1) {
39        unsigned int len = 0;
40        for (int i = 0; i < extArgc; i++) {
41            len += strlen(extArgv[i]);
42        }
43        len += strlen(name) + extArgc + 1;
44        char *nameValue = (char *)calloc(len, sizeof(char));
45        BEGET_ERROR_CHECK(nameValue != NULL, return -1, "Failed calloc err=%d", errno);
46
47        ret = strncat_s(nameValue, len, name, strlen(name));
48        if (ret != 0) {
49            free(nameValue);
50            BEGET_LOGE("Failed to cat name");
51            return -1;
52        }
53        for (int j = 0; j < extArgc; j++) {
54            ret = strncat_s(nameValue, len, "|", 1);
55            if (ret == 0) {
56                ret = strncat_s(nameValue, len, extArgv[j], strlen(extArgv[j]));
57            }
58            if (ret != 0) {
59                free(nameValue);
60                BEGET_LOGE("Failed to cat name");
61                return -1;
62            }
63        }
64        ret = SystemSetParameter("ohos.ctl.start", nameValue);
65        free(nameValue);
66    } else {
67        ret = SystemSetParameter("ohos.ctl.start", name);
68    }
69    return ret;
70}
71
72static int StopProcess(const char *serviceName)
73{
74    BEGET_ERROR_CHECK(serviceName != NULL, return -1, "Service name is null.");
75    return SystemSetParameter("ohos.ctl.stop", serviceName);
76}
77
78static int GetCurrentServiceStatus(const char *serviceName, ServiceStatus *status)
79{
80    char paramName[PARAM_NAME_LEN_MAX] = {0};
81    if (snprintf_s(paramName, PARAM_NAME_LEN_MAX, PARAM_NAME_LEN_MAX - 1,
82        "%s.%s", STARTUP_SERVICE_CTL, serviceName) == -1) {
83        BEGET_LOGE("Failed snprintf_s err=%d", errno);
84        return -1;
85    }
86    uint32_t value = GetUintParameter(paramName, SERVICE_IDLE);
87    *status = (ServiceStatus)value;
88    return 0;
89}
90
91static int RestartProcess(const char *serviceName, const char *extArgv[], int extArgc)
92{
93    BEGET_ERROR_CHECK(serviceName != NULL, return -1, "Service name is null.");
94    ServiceStatus status = SERVICE_IDLE;
95    if (GetCurrentServiceStatus(serviceName, &status) != 0) {
96        BEGET_LOGE("Get service status failed.\n");
97        return -1;
98    }
99    BEGET_LOGE("Process service %s status: %d ", serviceName, status);
100    if (status == SERVICE_STARTED || status == SERVICE_READY) {
101        if (StopProcess(serviceName) != 0) {
102            BEGET_LOGE("Stop service %s failed", serviceName);
103            return -1;
104        }
105        if (ServiceWaitForStatus(serviceName, SERVICE_STOPPED, DEFAULT_PARAM_WAIT_TIMEOUT) != 0) {
106            BEGET_LOGE("Failed wait service %s stopped", serviceName);
107            return -1;
108        }
109        if (StartProcess(serviceName, extArgv, extArgc) != 0) {
110            BEGET_LOGE("Start service %s failed", serviceName);
111            return -1;
112        }
113    } else if (status != SERVICE_STARTING) {
114        if (StartProcess(serviceName, extArgv, extArgc) != 0) {
115            BEGET_LOGE("Start service %s failed", serviceName);
116            return -1;
117        }
118    }
119    return 0;
120}
121
122int ServiceControlWithExtra(const char *serviceName, int action, const char *extArgv[], int extArgc)
123{
124    BEGET_ERROR_CHECK(serviceName != NULL, return -1, "Service name is null.");
125    int ret = 0;
126    switch (action) {
127        case START:
128            ret = StartProcess(serviceName, extArgv, extArgc);
129            break;
130        case STOP:
131            ret = StopProcess(serviceName);
132            break;
133        case RESTART:
134            ret = RestartProcess(serviceName, extArgv, extArgc);
135            break;
136        default:
137            BEGET_LOGE("Set service %s action %d error", serviceName, action);
138            ret = -1;
139            break;
140    }
141    return ret;
142}
143
144int ServiceControl(const char *serviceName, int action)
145{
146    BEGET_ERROR_CHECK(serviceName != NULL, return -1, "Service name is null.");
147    int ret = ServiceControlWithExtra(serviceName, action, NULL, 0);
148    return ret;
149}
150
151static int GetProcessInfo(const char *serviceName, char *nameBuffer, char *valueBuffer, ServiceStatus status)
152{
153    if (snprintf_s(nameBuffer, PARAM_NAME_LEN_MAX, PARAM_NAME_LEN_MAX - 1, "%s.%s",
154        STARTUP_SERVICE_CTL, serviceName) == -1) {
155        BEGET_LOGE("Failed snprintf_s err=%d", errno);
156        return -1;
157    }
158    if (snprintf_s(valueBuffer, MAX_INT_LEN, MAX_INT_LEN - 1, "%d", (int)status) == -1) {
159        BEGET_LOGE("Failed snprintf_s err=%d", errno);
160        return -1;
161    }
162    return 0;
163}
164
165int ServiceWaitForStatus(const char *serviceName, ServiceStatus status, int waitTimeout)
166{
167    BEGET_ERROR_CHECK(serviceName != NULL, return -1, "Service name is null.");
168    BEGET_ERROR_CHECK(waitTimeout >= 0, return -1, "Invalid timeout.");
169    char paramName[PARAM_NAME_LEN_MAX] = {0};
170    char value[MAX_INT_LEN] = {0};
171    int ret = GetProcessInfo(serviceName, paramName, value, status);
172    BEGET_ERROR_CHECK(ret == 0, return -1, "Failed to get param info.");
173    return (SystemWaitParameter(paramName, value, waitTimeout) != 0) ? -1 : 0;
174}
175
176int ServiceSetReady(const char *serviceName)
177{
178    BEGET_ERROR_CHECK(serviceName != NULL, return -1, "Service name is null.");
179    char paramName[PARAM_NAME_LEN_MAX] = {0};
180    char value[MAX_INT_LEN] = {0};
181    int ret = GetProcessInfo(serviceName, paramName, value, SERVICE_READY);
182    BEGET_ERROR_CHECK(ret == 0, return -1, "Failed to get param info.");
183    return SystemSetParameter(paramName, value);
184}
185
186int StartServiceByTimer(const char *serviceName, uint64_t timeout)
187{
188    BEGET_ERROR_CHECK(serviceName != NULL, return -1, "Service name is null.");
189    if (timeout == 0) {
190        // start service immediately.
191        return ServiceControl(serviceName, START);
192    }
193    // restrict timeout value, not too long.
194    char value[PARAM_VALUE_LEN_MAX] = {};
195    if (snprintf_s(value, PARAM_NAME_LEN_MAX, PARAM_NAME_LEN_MAX - 1, "%s|%lld", serviceName, timeout) == -1) {
196        BEGET_LOGE("Failed to build parameter value");
197        return -1;
198    }
199    return SystemSetParameter("ohos.servicectrl.timer_start", value);
200}
201
202int StopServiceTimer(const char *serviceName)
203{
204    BEGET_ERROR_CHECK(serviceName != NULL, return -1, "Service name is null.");
205    return SystemSetParameter("ohos.servicectrl.timer_stop", serviceName);
206}
207