/* ***************************************************************************** * usage/server/classical.c -- set up a classical protocol 7 server. * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey * * 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 . * ************************************************************************** */ #include #include /* ************************************************************************** */ /* 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)); }