1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include <stdio.h>
16#include <stdlib.h>
17#include <signal.h>
18
19#include "appspawn.h"
20#include "appspawn_utils.h"
21
22#include "devicedebug_base.h"
23#include "devicedebug_kill.h"
24#include "cJSON.h"
25
26#ifdef __cplusplus
27extern "C" {
28#endif
29
30#define DEVICEDEBUG_KILL_CMD_NUM 4
31#define DEVICEDEBUG_KILL_CMD_SIGNAL_INDEX 2
32#define DEVICEDEBUG_KILL_CMD_PID_INDEX 3
33
34APPSPAWN_STATIC void DeviceDebugShowKillHelp(void)
35{
36    printf("\r\nusage: devicedebug kill [options] <pid>"
37        "\r\noptions list:"
38        "\r\n         -h, --help                list available commands"
39        "\r\n         kill -<signal> <pid>      send a signal to a process\r\n");
40}
41
42APPSPAWN_STATIC char* DeviceDebugJsonStringGeneral(int pid, const char *op, cJSON *args)
43{
44    cJSON *root = cJSON_CreateObject();
45    if (root == NULL) {
46        DEVICEDEBUG_LOGE("devicedebug json write create root object unsuccess");
47        return NULL;
48    }
49
50    cJSON_AddNumberToObject(root, "app", pid);
51    cJSON_AddStringToObject(root, "op", op);
52    cJSON_AddItemToObject(root, "args", args);
53
54    char *jsonString = cJSON_Print(root);
55    cJSON_Delete(root);
56    return jsonString;
57}
58
59APPSPAWN_STATIC int DeviceDebugKill(int pid, int signal)
60{
61    AppSpawnClientHandle clientHandle;
62    int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
63    if (ret != 0) {
64        DEVICEDEBUG_LOGE("devicedebug appspawn client init unsuccess, ret=%{public}d", ret);
65        return ret;
66    }
67
68    AppSpawnReqMsgHandle reqHandle;
69    ret = AppSpawnReqMsgCreate(MSG_DEVICE_DEBUG, "devicedebug", &reqHandle);
70    if (ret != 0) {
71        DEVICEDEBUG_LOGE("devicedebug appspawn message create unsuccess, ret=%{public}d", ret);
72        return ret;
73    }
74
75    cJSON *args = cJSON_CreateObject();
76    if (args == NULL) {
77        DEVICEDEBUG_LOGE("devicedebug json write create args object unsuccess");
78        return DEVICEDEBUG_ERRNO_JSON_CREATED_FAILED;
79    }
80    cJSON_AddNumberToObject(args, "signal", signal);
81    char *jsonString = DeviceDebugJsonStringGeneral(pid, "kill", args);
82    if (jsonString == NULL) {
83        cJSON_Delete(args);
84        return DEVICEDEBUG_ERRNO_JSON_CREATED_FAILED;
85    }
86
87    ret = AppSpawnReqMsgAddExtInfo(reqHandle, "devicedebug", (uint8_t *)jsonString, strlen(jsonString) + 1);
88    if (ret != 0) {
89        DEVICEDEBUG_LOGE("devicedebug appspawn message add devicedebug[%{public}s] unsuccess, ret=%{public}d",
90            jsonString, ret);
91        return ret;
92    }
93
94    AppSpawnResult result = {0};
95    ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
96    AppSpawnClientDestroy(clientHandle);
97    if (ret != 0) {
98        DEVICEDEBUG_LOGE("devicedebug appspawn send msg unsuccess, ret=%{public}d", ret);
99        return ret;
100    }
101
102    if (result.result != 0) {
103        DEVICEDEBUG_LOGE("devicedebug appspawn kill process unsuccess, result=%{public}d", result.result);
104        return result.result;
105    }
106
107    return 0;
108}
109
110int DeviceDebugCmdKill(int argc, char *argv[])
111{
112    if (!IsDeveloperModeOpen()) {
113        return DEVICEDEBUG_ERRNO_NOT_IN_DEVELOPER_MODE;
114    }
115
116    if (argc <= DEVICEDEBUG_NUM_2 || strcmp(argv[DEVICEDEBUG_NUM_2], "-h") == 0 ||
117        strcmp(argv[DEVICEDEBUG_NUM_2], "help") == 0) {
118        DeviceDebugShowKillHelp();
119        return 0;
120    }
121
122    if (argc < DEVICEDEBUG_KILL_CMD_NUM) {
123        DEVICEDEBUG_LOGE("devicedebug cmd operator num is %{public}d < %{public}d", argc, DEVICEDEBUG_KILL_CMD_NUM);
124        DeviceDebugShowKillHelp();
125        return DEVICEDEBUG_ERRNO_OPERATOR_ARGV_MISS;
126    }
127
128    int signal = atoi(argv[DEVICEDEBUG_KILL_CMD_SIGNAL_INDEX] + 1);
129    if (signal > SIGRTMAX || signal <= 0) {
130        DEVICEDEBUG_LOGE("signal is %{public}d > %{public}d", signal, SIGRTMAX);
131        DeviceDebugShowKillHelp();
132        return DEVICEDEBUG_ERRNO_PARAM_INVALID;
133    }
134
135    int pid = atoi(argv[DEVICEDEBUG_KILL_CMD_PID_INDEX]);
136    DEVICEDEBUG_LOGI("devicedebug cmd kill start signal[%{public}d], pid[%{public}d]", signal, pid);
137
138    return DeviceDebugKill(pid, signal);
139}
140
141#ifdef __cplusplus
142}
143#endif
144