330 lines
9.1 KiB
C
330 lines
9.1 KiB
C
/* *****************************************************************************
|
|
* usage/server/classical.c -- set up a classical protocol 7 server.
|
|
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
|
*
|
|
* This file is part of libp7.
|
|
* libp7 is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation; either version 3.0 of the License,
|
|
* or (at your option) any later version.
|
|
*
|
|
* libp7 is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with libp7; if not, see <http://www.gnu.org/licenses/>.
|
|
* ************************************************************************** */
|
|
#include <libp7/internals.h>
|
|
#include <string.h>
|
|
|
|
/* ************************************************************************** */
|
|
/* Utilities */
|
|
/* ************************************************************************** */
|
|
/* cookie structure */
|
|
typedef struct {
|
|
p7_server_t *info;
|
|
p7_filesystem_t *filesystems;
|
|
} p7_server_cookie_t;
|
|
|
|
/* macros */
|
|
#define gather_fs() \
|
|
p7_filesystem_t *fs = find_filesystem(response.args[4], \
|
|
cookie->filesystems); \
|
|
if (!fs) return (p7_error_unknown);
|
|
#define gather_sdir() \
|
|
const char *sdir = response.args[0]; \
|
|
if (!sdir) sdir = fs->working_directory;
|
|
|
|
/**
|
|
* find_filesystem:
|
|
* Find a filesystem in a list.
|
|
*
|
|
* @arg name the name of the filesystem to look for.
|
|
* @arg filesystems the filesystems list (with terminating entry)
|
|
* @return the filesystem.
|
|
*/
|
|
|
|
static p7_filesystem_t *find_filesystem(const char *name,
|
|
p7_filesystem_t *filesystems)
|
|
{
|
|
while (filesystems->name) {
|
|
if (!strcmp(name, filesystems->name))
|
|
return (filesystems);
|
|
filesystems++;
|
|
}
|
|
return (NULL);
|
|
}
|
|
/* ************************************************************************** */
|
|
/* General callbacks */
|
|
/* ************************************************************************** */
|
|
/**
|
|
* send_server_info:
|
|
* Send the server information.
|
|
*
|
|
* @arg cookie the cookie.
|
|
* @arg handle the libp7 handle.
|
|
* @return the libp7 error.
|
|
*/
|
|
|
|
static int send_server_info(p7_server_cookie_t *cookie, p7_handle_t *handle)
|
|
{
|
|
return (p7_seven_send_eack(handle, cookie->info));
|
|
}
|
|
/* ************************************************************************** */
|
|
/* Backup-related callbacks */
|
|
/* ************************************************************************** */
|
|
/**
|
|
* backup_ram:
|
|
* Request a RAM image transfer.
|
|
*
|
|
* @arg cookie the cookie.
|
|
* @arg handle the libp7 handle.
|
|
* @return the libp7 error.
|
|
*/
|
|
|
|
static int backup_ram(p7_server_cookie_t *cookie, p7_handle_t *handle)
|
|
{
|
|
p7_server_t *info = cookie->info;
|
|
|
|
/* check that we have the RAM */
|
|
if (!info->ram) return (p7_error_unknown);
|
|
|
|
/* accept and roleswap */
|
|
int err = p7_seven_send_ack(handle, 1);
|
|
if (err) return (err);
|
|
if (response.type != p7_seven_type_swp)
|
|
return (p7_error_unknown);
|
|
|
|
/* send the command */
|
|
err = p7_seven_send_cmdbak_putram(handle);
|
|
if (err) return (err);
|
|
if (response.type == p7_seven_type_ack) {
|
|
/* send the thing */
|
|
err = p7_seven_send_data(handle, info->ram, info->ram_capacity,
|
|
0, NULL);
|
|
if (err) return (err);
|
|
}
|
|
|
|
/* re-swap roles */
|
|
return (p7_seven_send_swp(handle));
|
|
}
|
|
|
|
/**
|
|
* backup_rom:
|
|
* Request a ROM image transfer.
|
|
*
|
|
* @arg cookie the cookie.
|
|
* @arg handle the libp7 handle.
|
|
* @return the libp7 error.
|
|
*/
|
|
|
|
static int backup_rom(p7_server_cookie_t *cookie, p7_handle_t *handle)
|
|
{
|
|
p7_server_t *info = cookie->info;
|
|
|
|
/* check that we have the ROM */
|
|
if (!info->flash_rom) return (p7_error_unknown);
|
|
|
|
/* accept and roleswap */
|
|
int err = p7_seven_send_ack(handle, 1);
|
|
if (err) return (err);
|
|
if (response.type != p7_seven_type_swp)
|
|
return (p7_error_unknown);
|
|
|
|
/* send the command */
|
|
err = p7_seven_send_cmdbak_putrom(handle);
|
|
if (err) return (err);
|
|
if (response.type == p7_seven_type_ack) {
|
|
/* send the thing */
|
|
err = p7_seven_send_data(handle, info->flash_rom,
|
|
info->flash_rom_capacity, 0, NULL);
|
|
if (err) return (err);
|
|
}
|
|
|
|
/* re-swap roles */
|
|
return (p7_seven_send_swp(handle));
|
|
}
|
|
|
|
/**
|
|
* backup_boot:
|
|
* Request a bootcode transfer.
|
|
*
|
|
* @arg cookie the cookie.
|
|
* @arg handle the libp7 handle.
|
|
* @return the libp7 error.
|
|
*/
|
|
|
|
static int backup_boot(p7_server_cookie_t *cookie, p7_handle_t *handle)
|
|
{
|
|
p7_server_t *info = cookie->info;
|
|
|
|
/* check that we have the bootcode */
|
|
if (!info->bootcode) return (p7_error_unknown);
|
|
|
|
/* accept and roleswap */
|
|
int err = p7_seven_send_ack(handle, 1);
|
|
if (err) return (err);
|
|
if (response.type != p7_seven_type_swp)
|
|
return (p7_error_unknown);
|
|
|
|
/* send the command */
|
|
err = p7_seven_send_cmdbak_putboot(handle);
|
|
if (err) return (err);
|
|
if (response.type == p7_seven_type_ack) {
|
|
/* send the thing */
|
|
err = p7_seven_send_data(handle, info->bootcode, info->bootcode_size,
|
|
0, NULL);
|
|
if (err) return (err);
|
|
}
|
|
|
|
/* re-swap roles */
|
|
return (p7_seven_send_swp(handle));
|
|
}
|
|
/* ************************************************************************** */
|
|
/* Storage-related callbacks */
|
|
/* ************************************************************************** */
|
|
/**
|
|
* create_directory:
|
|
* Create a directory.
|
|
*
|
|
* @arg cookie the cookie.
|
|
* @arg handle the libp7 handle.
|
|
* @return the libp7 error.
|
|
*/
|
|
|
|
static int create_directory(p7_server_cookie_t *cookie, p7_handle_t *handle)
|
|
{
|
|
gather_fs()
|
|
gather_sdir()
|
|
|
|
/* create the directory */
|
|
if (!fs->create_directory || !sdir)
|
|
return (p7_error_unknown);
|
|
int err = (*fs->create_directory)(fs->cookie, sdir);
|
|
if (err) return (err);
|
|
|
|
/* send ack */
|
|
return (p7_seven_send_ack(handle, 1));
|
|
}
|
|
|
|
/**
|
|
* delete_directory:
|
|
* Delete a directory.
|
|
*
|
|
* @arg cookie the cookie.
|
|
* @arg handle the libp7 handle.
|
|
* @return the libp7 error.
|
|
*/
|
|
|
|
static int delete_directory(p7_server_cookie_t *cookie, p7_handle_t *handle)
|
|
{
|
|
gather_fs()
|
|
gather_sdir()
|
|
|
|
/* delete the directory */
|
|
if (!fs->delete_directory || !sdir)
|
|
return (p7_error_unknown);
|
|
int err = (*fs->delete_directory)(fs->cookie, sdir);
|
|
if (err) return (err);
|
|
|
|
/* send ack */
|
|
return (p7_seven_send_ack(handle, 1));
|
|
}
|
|
|
|
/**
|
|
* rename_directory:
|
|
* Rename a directory.
|
|
*
|
|
* @arg cookie the cookie.
|
|
* @arg handle the libp7 handle.
|
|
* @return the libp7 error.
|
|
*/
|
|
|
|
static int rename_directory(p7_server_cookie_t *cookie, p7_handle_t *handle)
|
|
{
|
|
gather_fs()
|
|
gather_sdir()
|
|
|
|
/* rename the directory */
|
|
if (!fs->rename_directory || !sdir || !response.args[1])
|
|
return (p7_error_unknown);
|
|
int err = (*fs->rename_directory)(fs->cookie, sdir, response.args[1]);
|
|
if (err) return (err);
|
|
|
|
/* send ack */
|
|
return (p7_seven_send_ack(handle, 1));
|
|
}
|
|
|
|
/**
|
|
* change_working_directory:
|
|
* Change the current working directory.
|
|
*
|
|
* @arg cookie the cookie.
|
|
* @arg handle the libp7 handle.
|
|
* @return the libp7 error.
|
|
*/
|
|
|
|
static int change_working_directory(p7_server_cookie_t *cookie,
|
|
p7_handle_t *handle)
|
|
{
|
|
gather_fs()
|
|
|
|
/* check and change working directory */
|
|
log_info("Changing directory to \"%s\"", response.args[0]);
|
|
if (!response.args[0])
|
|
fs->working_directory = NULL;
|
|
else if (fs->directory_exists
|
|
&& (*fs->directory_exists)(fs->cookie, response.args[0])) {
|
|
log_info("Directory does not exist, not changing!");
|
|
return (p7_error_unknown);
|
|
} else {
|
|
fs->working_directory = fs->_wd;
|
|
strncpy(fs->_wd, response.args[0], 256);
|
|
fs->_wd[256] = 0;
|
|
}
|
|
|
|
/* success! */
|
|
return (p7_seven_send_ack(handle, 1));
|
|
}
|
|
/* ************************************************************************** */
|
|
/* Main function */
|
|
/* ************************************************************************** */
|
|
/**
|
|
* p7_serve:
|
|
* Initialize a server.
|
|
*
|
|
* @arg handle the libp7 handle.
|
|
* @arg info the server information.
|
|
* @arg callbacks the server callbacks.
|
|
* @return the error code.
|
|
*/
|
|
|
|
int p7_serve(p7_handle_t *handle, p7_server_t *info,
|
|
p7_filesystem_t *filesystems)
|
|
{
|
|
/* make cookie and commands */
|
|
p7_server_cookie_t cookie = {
|
|
.info = info,
|
|
.filesystems = filesystems};
|
|
p7_server_callback_t callbacks[256] = {
|
|
/* main commands */
|
|
[p7_seven_cmdsys_getinfo] = (p7_server_callback_t)send_server_info,
|
|
|
|
/* backup commands */
|
|
[p7_seven_cmdbak_reqram] = (p7_server_callback_t)backup_ram,
|
|
[p7_seven_cmdbak_reqrom] = (p7_server_callback_t)backup_rom,
|
|
[p7_seven_cmdbak_reqboot] = (p7_server_callback_t)backup_boot,
|
|
|
|
/* storage-related commands */
|
|
[p7_seven_cmdfls_mkdir] = (p7_server_callback_t)create_directory,
|
|
[p7_seven_cmdfls_rmdir] = (p7_server_callback_t)delete_directory,
|
|
[p7_seven_cmdfls_mvdir] = (p7_server_callback_t)rename_directory,
|
|
[p7_seven_cmdfls_cwd] = (p7_server_callback_t)change_working_directory,
|
|
};
|
|
|
|
/* serve! */
|
|
return (p7_serve_directly(handle, callbacks, (void*)&cookie));
|
|
}
|