210 lines
5.3 KiB
C
210 lines
5.3 KiB
C
/****************************************************************************
|
|
* system/adb/shell_service.c
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you 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.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "adb.h"
|
|
#include "shell_service.h"
|
|
#include "shell_pipe.h"
|
|
|
|
/****************************************************************************
|
|
* Private types
|
|
****************************************************************************/
|
|
|
|
typedef struct ash_service_s
|
|
{
|
|
adb_service_t service;
|
|
shell_pipe_t pipe;
|
|
adb_client_t *client;
|
|
} ash_service_t;
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
static void exec_on_data_available(shell_pipe_t * pipe, apacket * p);
|
|
|
|
static int shell_ack(adb_service_t *service, apacket *p);
|
|
static int shell_write(adb_service_t *service, apacket *p);
|
|
static void shell_close(struct adb_service_s *service);
|
|
static void shell_kick(adb_service_t *service);
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
static void exec_on_data_available(shell_pipe_t * pipe, apacket * p)
|
|
{
|
|
ash_service_t *service = container_of(pipe, ash_service_t, pipe);
|
|
|
|
if (p->msg.data_length <= 0)
|
|
{
|
|
/* Got EOF */
|
|
|
|
adb_service_close(service->client, &service->service, p);
|
|
return;
|
|
}
|
|
|
|
p->write_len = p->msg.data_length;
|
|
p->msg.arg0 = service->service.id;
|
|
p->msg.arg1 = service->service.peer_id;
|
|
adb_send_data_frame(service->client, p);
|
|
}
|
|
|
|
static int shell_write(adb_service_t *service, apacket *p)
|
|
{
|
|
int ret;
|
|
ash_service_t *svc = container_of(service, ash_service_t, service);
|
|
UNUSED(svc);
|
|
|
|
if (p->msg.data_length <= 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
ret = shell_pipe_write(&svc->pipe, p->data, p->msg.data_length);
|
|
|
|
if (ret < 0)
|
|
{
|
|
/* Shell process terminated, close service */
|
|
|
|
return -1;
|
|
}
|
|
|
|
assert(ret == p->msg.data_length);
|
|
return 0;
|
|
}
|
|
|
|
static int shell_ack(adb_service_t *service, apacket *p)
|
|
{
|
|
UNUSED(service);
|
|
UNUSED(p);
|
|
return 0;
|
|
}
|
|
|
|
static void shell_kick(adb_service_t *service)
|
|
{
|
|
int ret;
|
|
ash_service_t *svc = container_of(service, ash_service_t, service);
|
|
ret = shell_pipe_start(&svc->pipe, exec_on_data_available);
|
|
|
|
/* TODO handle return code */
|
|
|
|
assert(ret == 0);
|
|
}
|
|
|
|
static void shell_on_close(shell_pipe_t *pipe)
|
|
{
|
|
ash_service_t *svc = container_of(pipe, ash_service_t, pipe);
|
|
free(svc);
|
|
}
|
|
|
|
static void shell_close(adb_service_t *service)
|
|
{
|
|
ash_service_t *svc = container_of(service, ash_service_t, service);
|
|
|
|
/* FIXME missing logic here if shell process is still running */
|
|
|
|
shell_pipe_destroy(&svc->pipe, shell_on_close);
|
|
}
|
|
|
|
static const adb_service_ops_t shell_ops =
|
|
{
|
|
.on_write_frame = shell_write,
|
|
.on_ack_frame = shell_ack,
|
|
.on_kick = shell_kick,
|
|
.close = shell_close
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
adb_service_t * shell_service(adb_client_t *client, const char *params)
|
|
{
|
|
UNUSED(params);
|
|
UNUSED(client);
|
|
|
|
int ret;
|
|
char **argv;
|
|
const char *target;
|
|
ash_service_t *service =
|
|
(ash_service_t *)malloc(sizeof(ash_service_t));
|
|
|
|
if (service == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
service->client = client;
|
|
service->service.ops = &shell_ops;
|
|
|
|
ret = shell_pipe_setup(client, &service->pipe);
|
|
|
|
/* TODO check return code */
|
|
|
|
assert(ret == 0);
|
|
|
|
/* Check parameters after "shell:" */
|
|
|
|
target = ¶ms[6];
|
|
|
|
if (target[0] != 0)
|
|
{
|
|
/* Build argv: <nsh -c "command">
|
|
* argv[0] => "-c"
|
|
* argv[1] => command
|
|
* argv[2] => NULL
|
|
*
|
|
* malloc content:
|
|
* - x3 argv pointers
|
|
* - 3 characters: "-c\0"
|
|
* - space for command string
|
|
*/
|
|
|
|
argv = malloc(sizeof(char *) * 3 + 3 + (strlen(target)+1));
|
|
|
|
argv[0] = (char *)&argv[3];
|
|
argv[1] = &((char *)&argv[3])[3];
|
|
argv[2] = NULL;
|
|
strcpy(argv[0], "-c");
|
|
strcpy(argv[1], target);
|
|
}
|
|
else
|
|
{
|
|
argv = NULL;
|
|
}
|
|
|
|
ret = shell_pipe_exec(argv, &service->pipe,
|
|
exec_on_data_available);
|
|
|
|
/* TODO check return code */
|
|
|
|
assert(ret == 0);
|
|
|
|
free(argv);
|
|
|
|
return &service->service;
|
|
}
|