From 4bf6a9f22a4651101c69981f7337e74e2cd5f6d3 Mon Sep 17 00:00:00 2001 From: Ralf Corsepius Date: Fri, 4 Feb 2005 12:47:44 +0000 Subject: 2005-02-04 Ralf Corsepius * libnetworking/rtems_servers/ftp.c, libnetworking/rtems_servers/ftp.h, libnetworking/rtems_servers/Makefile.am: Remove (relocated to cpukit/ftpd). * configure.ac, Makefile.am, wrapup/Makefile.am: Reflect having removed move libnetworking/rtems_servers. --- c/src/libnetworking/rtems_servers/ftpd.c | 2062 ------------------------------ 1 file changed, 2062 deletions(-) delete mode 100644 c/src/libnetworking/rtems_servers/ftpd.c (limited to 'c/src/libnetworking/rtems_servers/ftpd.c') diff --git a/c/src/libnetworking/rtems_servers/ftpd.c b/c/src/libnetworking/rtems_servers/ftpd.c deleted file mode 100644 index e6e2c683d9..0000000000 --- a/c/src/libnetworking/rtems_servers/ftpd.c +++ /dev/null @@ -1,2062 +0,0 @@ -/* FIXME: 1. Parse command is a hack. We can do better. - * 2. Some sort of access control? - * 3. OSV: hooks support seems to be bad, as it requires storing of - * entire input file in memory. Seem to be better to change it to - * something more reasonable, like having - * 'hook_write(void const *buf, int count)' routine that will be - * called multiple times while file is being received. - * 4. OSV: Remove hack with "/dev/null"? - * - * FTP Server Daemon - * - * Submitted by: Jake Janovetz - * - * Changed by: Sergei Organov (OSV) - * - * Changes: - * - * 2001-01-31 Sergei Organov - * - * * Hacks with current dir and root dir removed in favor of new libio - * support for task-local current and root directories. - * - * 2001-01-30 Sergei Organov - * - * * Bug in `close_data_socket()' introduced by previous change fixed. - * * `command_pasv()' changed to set timeout on socket we are listening on - * and code fixed to don't close socket twice on error. - * * `serr()' changed to clear `errno'. - * * `data_socket()' changed to clear `errno' before `bind()'. - * * `session()' changed to clear `errno' before processing session. - * - * 2001-01-29 Sergei Organov - * - * * `close_data_socket()' fixed to close both active and passive sockets - * * Initialize info->data_socket to -1 in `daemon()' - * * Initialize `fname' to empty string in `exec_command()' - * - * 2001-01-22 Sergei Organov - * - * * Timeouts on sockets implemented. 'idle' field added to - * configuration. No timeout by default to keep backward compatibility. - * Note: SITE IDLE command not implemented yet. - * * Basic global access control implemented. 'access' field added to - * configuration. No access limitations by default to keep backward - * compatibility. - * - * 2001-01-17 Sergei Organov - * - * * Anchor data socket for active mode (using self IP and port 20.) - * * Fixed default data port support (still not tested). - * * Don't allow IP address different from originating host in - * PORT command to improve security. - * * Fixed bug in MDTM command. - * * Check for correctness of parsing of argument in command_port(). - * * Fixed squeeze_path() to don't allow names like 'NAME/smth' where - * 'NAME' is not a directory. - * * Command parsing a little bit improved: command names are now - * converted to upper-case to be more compatible with RFC (command - * names are not case-sensitive.) - * * Reformat comments so that they have RTEMS look-and-feel. - * - * 2001-01-16 Sergei Organov - * - * * Fixed DELE, SITE CHMOD, RMD, MKD broken by previous changes - * * True ASCII mode implemented (doesn't work for hooks and /dev/null) - * * Passive mode implemented, PASV command added. - * * Default port for data connection could be used (untested, can't find - * ftp client that doesn't send PORT command) - * * SYST reply changed to UNIX, as former RTEMS isn't registered name. - * * Reply codes reviewed and fixed. - * - * 2001-01-08 Sergei Organov - * - * * use pool of pre-created threads to handle sessions - * * LIST output now similar to what "/bin/ls -al" would output, thus - * FTP clients could parse it. - * * LIST NAME now works (both for files and directories) - * * keep track of CWD for every session separately - * * ability to specify root directory name in configuration table - * * options sent in commands are ignored, thus LIST -al FILE works - * * added support for NLST, CDUP and MDTM commands - * * buffers are allocated on stack instead of heap where possible - * * drop using of task notepad to pass parameters - use function - * arguments instead - * * various bug-fixes, e.g., use of PF_INET in socket() instead of - * AF_INET, use snprintf() instead of sprintf() everywhere for safety, - * etc. - * - * $Id$ - */ - -/************************************************************************* - * ftpd.c - ************************************************************************* - * Description: - * - * This file contains the daemon which services requests that appear - * on the FTP port. This server is compatible with FTP, but it - * also provides 'hooks' to make it usable in situations where files - * are not used/necessary. Once the server is started, it runs - * forever. - * - * - * Organization: - * - * The FTP daemon is started upon boot along with a (configurable) - * number of tasks to handle sessions. It runs all the time and - * waits for connections on the known FTP port (21). When - * a connection is made, it wakes-up a 'session' task. That - * session then interacts with the remote host. When the session - * is complete, the session task goes to sleep. The daemon still - * runs, however. - * - * - * Supported commands are: - * - * RETR xxx - Sends a file from the client. - * STOR xxx - Receives a file from the client. xxx = filename. - * LIST xxx - Sends a file list to the client. - * NLST xxx - Sends a file list to the client. - * USER - Does nothing. - * PASS - Does nothing. - * SYST - Replies with the system type (`RTEMS'). - * DELE xxx - Delete file xxx. - * MKD xxx - Create directory xxx. - * RMD xxx - Remove directory xxx. - * PWD - Print working directory. - * CWD xxx - Change working directory. - * CDUP - Change to upper directory. - * SITE CHMOD xxx yyy - Change permissions on file yyy to xxx. - * PORT a,b,c,d,x,y - Setup for a data port to IP address a.b.c.d - * and port (x*256 + y). - * MDTM xxx - Send file modification date/time to the client. - * xxx = filename. - * PASV - Use passive mode data connection. - * - * - * The public routines contained in this file are: - * - * rtems_initialize_ftpd - Initializes and starts the server daemon, - * then returns to its caller. - * - *------------------------------------------------------------------------ - * Jake Janovetz - * University of Illinois - * 1406 West Green Street - * Urbana IL 61801 - ************************************************************************* - * Change History: - * 12/01/97 - Creation (JWJ) - * 2001-01-08 - Changes by OSV - *************************************************************************/ - -/************************************************************************* - * Meanings of first and second digits of reply codes: - * - * Reply: Description: - *-------- -------------- - * 1yz Positive preliminary reply. The action is being started but - * expect another reply before sending another command. - * 2yz Positive completion reply. A new command can be sent. - * 3yz Positive intermediate reply. The command has been accepted - * but another command must be sent. - * 4yz Transient negative completion reply. The requested action did - * not take place, but the error condition is temporary so the - * command can be reissued later. - * 5yz Permanent negative completion reply. The command was not - * accepted and should not be retried. - *------------------------------------------------------------------------- - * x0z Syntax errors. - * x1z Information. - * x2z Connections. Replies referring to the control or data - * connections. - * x3z Authentication and accounting. Replies for the login or - * accounting commands. - * x4z Unspecified. - * x5z Filesystem status. - *************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "ftpd.h" - - -#ifdef __GNUC__ -/* change to #if 1 to disable syslog entirely */ -#if 0 -#undef syslog -#define syslog(a, b, ...) while(0){} -#endif -#endif - -#define FTPD_SERVER_MESSAGE "RTEMS FTP server (Version 1.1-JWJ) ready." - -#define FTPD_SYSTYPE "UNIX Type: L8" - -/* Seem to be unused */ -#if 0 -#define FTPD_WELCOME_MESSAGE \ - "Welcome to the RTEMS FTP server.\n" \ - "\n" \ - "Login accepted.\n" -#endif - -/* Various buffer sizes */ -enum -{ - FTPD_BUFSIZE = 256, /* Size for temporary buffers */ - FTPD_DATASIZE = 1024, /* Size for file transfer buffers */ - FTPD_STACKSIZE = 8 * 1024, /* Tasks stack size */ -}; - -/* Event to be used by session tasks for waiting */ -enum -{ - FTPD_RTEMS_EVENT = RTEMS_EVENT_1 -}; - -/* Configuration table */ -extern struct rtems_ftpd_configuration rtems_ftpd_configuration; - -/* this is not prototyped in strict ansi mode */ -FILE *fdopen (int fildes, const char *mode); - -/*PAGE - * SessionInfo structure. - * - * The following structure is allocated for each session. - */ -typedef struct -{ - struct sockaddr_in ctrl_addr; /* Control connection self address */ - struct sockaddr_in data_addr; /* Data address set by PORT command */ - struct sockaddr_in def_addr; /* Default address for data */ - int use_default; /* 1 - use default address for data */ - FILE *ctrl_fp; /* File pointer for control connection */ - int ctrl_socket; /* Socket for ctrl connection */ - int pasv_socket; /* Socket for PASV connection */ - int data_socket; /* Socket for data connection */ - int idle; /* Timeout in seconds */ - int xfer_mode; /* Transfer mode (ASCII/binary) */ - rtems_id tid; /* Task id */ -} FTPD_SessionInfo_t; - - -/* - * TaskPool structure. - */ -typedef struct -{ - FTPD_SessionInfo_t *info; - FTPD_SessionInfo_t **queue; - int count; - int head; - int tail; - rtems_id mutex; - rtems_id sem; -} FTPD_TaskPool_t; - -/* - * Task pool instance. - */ -static FTPD_TaskPool_t task_pool; - -/* - * Root directory - */ - -static char const* ftpd_root = "/"; - -/* - * Default idle timeout for sockets in seconds. - */ -static int ftpd_timeout = 0; - -/* - * Global access flags. - */ -static int ftpd_access = 0; - -/*PAGE - * - * serr - * - * Return error string corresponding to current 'errno'. - * - */ -static char const* -serr(void) -{ - int err = errno; - errno = 0; - return strerror(err); -} - -/*PAGE - * - * Utility routines for access control. - * - */ - -static int -can_read(void) -{ - return (ftpd_access & FTPD_NO_READ) == 0; -} - -static int -can_write(void) -{ - return (ftpd_access & FTPD_NO_WRITE) == 0; -} - -/*PAGE - * - * Task pool management routines - * - */ - - -/*PAGE - * - * task_pool_done - * - * Cleanup task pool. - * - * Input parameters: - * count - number of entries in task pool to cleanup - * - * Output parameters: - * NONE - * - */ -static void -task_pool_done(int count) -{ - int i; - for(i = 0; i < count; ++i) - rtems_task_delete(task_pool.info[i].tid); - if(task_pool.info) - free(task_pool.info); - if(task_pool.queue) - free(task_pool.queue); - if(task_pool.mutex != (rtems_id)-1) - rtems_semaphore_delete(task_pool.mutex); - if(task_pool.sem != (rtems_id)-1) - rtems_semaphore_delete(task_pool.sem); - task_pool.info = 0; - task_pool.queue = 0; - task_pool.count = 0; - task_pool.sem = -1; - task_pool.mutex = -1; -} - -/*PAGE - * - * task_pool_init - * - * Initialize task pool. - * - * Input parameters: - * count - number of entries in task pool to create - * priority - priority tasks are started with - * - * Output parameters: - * returns 1 on success, 0 on failure. - * - */ -static void session(rtems_task_argument arg); /* Forward declare */ - -static int -task_pool_init(int count, rtems_task_priority priority) -{ - int i; - rtems_status_code sc; - char id = 'a'; - - task_pool.count = 0; - task_pool.head = task_pool.tail = 0; - task_pool.mutex = (rtems_id)-1; - task_pool.sem = (rtems_id)-1; - - sc = rtems_semaphore_create( - rtems_build_name('F', 'T', 'P', 'M'), - 1, - RTEMS_DEFAULT_ATTRIBUTES - | RTEMS_BINARY_SEMAPHORE - | RTEMS_INHERIT_PRIORITY - | RTEMS_PRIORITY, - RTEMS_NO_PRIORITY, - &task_pool.mutex); - - if(sc == RTEMS_SUCCESSFUL) - sc = rtems_semaphore_create( - rtems_build_name('F', 'T', 'P', 'S'), - count, - RTEMS_DEFAULT_ATTRIBUTES, - RTEMS_NO_PRIORITY, - &task_pool.sem); - - if(sc != RTEMS_SUCCESSFUL) { - task_pool_done(0); - syslog(LOG_ERR, "ftpd: Can not create semaphores"); - return 0; - } - - task_pool.info = (FTPD_SessionInfo_t*) - malloc(sizeof(FTPD_SessionInfo_t) * count); - task_pool.queue = (FTPD_SessionInfo_t**) - malloc(sizeof(FTPD_SessionInfo_t*) * count); - if (NULL == task_pool.info || NULL == task_pool.queue) - { - task_pool_done(0); - syslog(LOG_ERR, "ftpd: Not enough memory"); - return 0; - } - - for(i = 0; i < count; ++i) - { - FTPD_SessionInfo_t *info = &task_pool.info[i]; - sc = rtems_task_create(rtems_build_name('F', 'T', 'P', id), - priority, FTPD_STACKSIZE, - RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | - RTEMS_NO_ASR | RTEMS_INTERRUPT_LEVEL(0), - RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, - &info->tid); - if (sc == RTEMS_SUCCESSFUL) - { - sc = rtems_task_start( - info->tid, session, (rtems_task_argument)info); - if (sc != RTEMS_SUCCESSFUL) - task_pool_done(i); - } - else - task_pool_done(i + 1); - if (sc != RTEMS_SUCCESSFUL) - { - syslog(LOG_ERR, "ftpd: Could not create/start FTPD session: %s", - rtems_status_text(sc)); - return 0; - } - task_pool.queue[i] = task_pool.info + i; - if (++id > 'z') - id = 'a'; - } - task_pool.count = count; - return 1; -} - -/*PAGE - * - * task_pool_obtain - * - * Obtain free task from task pool. - * - * Input parameters: - * NONE - * - * Output parameters: - * returns pointer to the corresponding SessionInfo structure on success, - * NULL if there are no free tasks in the pool. - * - */ -static FTPD_SessionInfo_t* -task_pool_obtain() -{ - FTPD_SessionInfo_t* info = 0; - rtems_status_code sc; - sc = rtems_semaphore_obtain(task_pool.sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT); - if (sc == RTEMS_SUCCESSFUL) - { - rtems_semaphore_obtain(task_pool.mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - info = task_pool.queue[task_pool.head]; - if(++task_pool.head >= task_pool.count) - task_pool.head = 0; - rtems_semaphore_release(task_pool.mutex); - } - return info; -} - -/*PAGE - * - * task_pool_release - * - * Return task obtained by 'obtain()' back to the task pool. - * - * Input parameters: - * info - pointer to corresponding SessionInfo structure. - * - * Output parameters: - * NONE - * - */ -static void -task_pool_release(FTPD_SessionInfo_t* info) -{ - rtems_semaphore_obtain(task_pool.mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - task_pool.queue[task_pool.tail] = info; - if(++task_pool.tail >= task_pool.count) - task_pool.tail = 0; - rtems_semaphore_release(task_pool.mutex); - rtems_semaphore_release(task_pool.sem); -} - -/* - * End of task pool routines - */ - -/*PAGE - * - * Function: send_reply - * - * - * This procedure sends a reply to the client via the control - * connection. - * - * - * Input parameters: - * code - 3-digit reply code. - * text - Reply text. - * - * Output parameters: - * NONE - */ -static void -send_reply(FTPD_SessionInfo_t *info, int code, char *text) -{ - char const* s = (info->xfer_mode == TYPE_A) ? "\r" : ""; - /* If a text reply exists, add it to the reply data. */ - if (text != NULL) - fprintf(info->ctrl_fp, "%d %.70s%s\n", code, text, s); - else - fprintf(info->ctrl_fp, "%d%s\n", code, s); - fflush(info->ctrl_fp); -} - - -/*PAGE - * - * close_socket - * - * Close socket. - * - * Input parameters: - * s - socket descriptor. - * seconds - number of seconds the timeout should be, - * if >= 0 - infinite timeout (no timeout). - * - * Output parameters: - * returns 1 on success, 0 on failure. - */ -static int -set_socket_timeout(int s, int seconds) -{ - int res = 0; - struct timeval tv; - int len = sizeof(tv); - - if(seconds < 0) - seconds = 0; - tv.tv_usec = 0; - tv.tv_sec = seconds; - if(0 != setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tv, len)) - syslog(LOG_ERR, "ftpd: Can't set send timeout on socket: %s.", serr()); - else if(0 != setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, len)) - syslog(LOG_ERR, "ftpd: Can't set receive timeout on socket: %s.", serr()); - else - res = 1; - return res; -} - -/*PAGE - * - * close_socket - * - * Close socket. - * - * Input parameters: - * s - socket descriptor to be closed. - * - * Output parameters: - * returns 1 on success, 0 on failure - */ -static int -close_socket(int s) -{ - if (0 <= s) - { - if (0 != close(s)) - { - shutdown(s, 2); - if (0 != close(s)) - return 0; - } - } - return 1; -} - -/*PAGE - * - * data_socket - * - * Create data socket for session. - * - * Input parameters: - * info - corresponding SessionInfo structure - * - * Output parameters: - * returns socket descriptor, or -1 if failure - * - */ -static int -data_socket(FTPD_SessionInfo_t *info) -{ - int s = info->pasv_socket; - if(0 > s) - { - int on = 1; - s = socket(PF_INET, SOCK_STREAM, 0); - if(0 > s) - send_reply(info, 425, "Can't create data socket."); - else if(0 > setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) - { - close_socket(s); - s = -1; - } - else - { - struct sockaddr_in data_source; - int tries; - - /* anchor socket to avoid multi-homing problems */ - data_source = info->ctrl_addr; - data_source.sin_port = htons(20); /* ftp-data port */ - for(tries = 1; tries < 10; ++tries) - { - errno = 0; - if(bind(s, (struct sockaddr *)&data_source, sizeof(data_source)) >= 0) - break; - if (errno != EADDRINUSE) - tries = 10; - else - rtems_task_wake_after(tries * 10); - } - if(tries >= 10) - { - send_reply(info, 425, "Can't bind data socket."); - close_socket(s); - s = -1; - } - else - { - struct sockaddr_in *data_dest = - (info->use_default) ? &info->def_addr : &info->data_addr; - if(0 > connect(s, (struct sockaddr *)data_dest, sizeof(*data_dest))) - { - send_reply(info, 425, "Can't connect data socket."); - close_socket(s); - s = -1; - } - } - } - } - info->data_socket = s; - info->use_default = 1; - if(s >= 0) - set_socket_timeout(s, info->idle); - return s; -} - -/*PAGE - * - * close_data_socket - * - * Close data socket for session. - * - * Input parameters: - * info - corresponding SessionInfo structure - * - * Output parameters: - * NONE - * - */ -static void -close_data_socket(FTPD_SessionInfo_t *info) -{ - /* As at most one data socket could be open simultaneously and in some cases - data_socket == pasv_socket, we select socket to close, then close it. */ - int s = info->data_socket; - if(0 > s) - s = info->pasv_socket; - if(!close_socket(s)) - syslog(LOG_ERR, "ftpd: Error closing data socket."); - info->data_socket = -1; - info->pasv_socket = -1; - info->use_default = 1; -} - -/*PAGE - * - * close_stream - * - * Close control stream of session. - * - * Input parameters: - * info - corresponding SessionInfo structure - * - * Output parameters: - * NONE - * - */ -static void -close_stream(FTPD_SessionInfo_t* info) -{ - if (NULL != info->ctrl_fp) - { - if (0 != fclose(info->ctrl_fp)) - { - syslog(LOG_ERR, "ftpd: Could not close control stream: %s", serr()); - } - else - info->ctrl_socket = -1; - } - - if (!close_socket(info->ctrl_socket)) - syslog(LOG_ERR, "ftpd: Could not close control socket: %s", serr()); - - info->ctrl_fp = NULL; - info->ctrl_socket = -1; -} - - -/*PAGE - * - * send_mode_reply - * - * Sends BINARY/ASCII reply string depending on current transfer mode. - * - * Input parameters: - * info - corresponding SessionInfo structure - * - * Output parameters: - * NONE - * - */ -static void -send_mode_reply(FTPD_SessionInfo_t *info) -{ - if(info->xfer_mode == TYPE_I) - send_reply(info, 150, "Opening BINARY mode data connection."); - else - send_reply(info, 150, "Opening ASCII mode data connection."); -} - -/*PAGE - * - * command_retrieve - * - * Perform the "RETR" command (send file to client). - * - * Input parameters: - * info - corresponding SessionInfo structure - * char *filename - source filename. - * - * Output parameters: - * NONE - * - */ -static void -command_retrieve(FTPD_SessionInfo_t *info, char const *filename) -{ - int s = -1; - int fd = -1; - char buf[FTPD_DATASIZE]; - int res = 0; - - if(!can_read()) - { - send_reply(info, 550, "Access denied."); - return; - } - - if (0 > (fd = open(filename, O_RDONLY))) - { - send_reply(info, 550, "Error opening file."); - return; - } - - send_mode_reply(info); - - s = data_socket(info); - - if (0 <= s) - { - int n = -1; - - if(info->xfer_mode == TYPE_I) - { - while ((n = read(fd, buf, FTPD_DATASIZE)) > 0) - { - if(send(s, buf, n, 0) != n) - break; - } - } - else if (info->xfer_mode == TYPE_A) - { - int rest = 0; - while (rest == 0 && (n = read(fd, buf, FTPD_DATASIZE)) > 0) - { - char const* e = buf; - char const* b; - int i; - rest = n; - do - { - char lf = '\0'; - - b = e; - for(i = 0; i < rest; ++i, ++e) - { - if(*e == '\n') - { - lf = '\n'; - break; - } - } - if(send(s, b, i, 0) != i) - break; - if(lf == '\n') - { - if(send(s, "\r\n", 2, 0) != 2) - break; - ++e; - ++i; - } - } - while((rest -= i) > 0); - } - } - - if (0 == n) - { - if (0 == close(fd)) - { - fd = -1; - res = 1; - } - } - } - - if (-1 != fd) - close(fd); - - if (0 == res) - send_reply(info, 451, "File read error."); - else - send_reply(info, 226, "Transfer complete."); - - close_data_socket(info); - - return; -} - - -/*PAGE - * - * discard - * - * Analog of `write' routine that just discards passed data - * - * Input parameters: - * fd - file descriptor (ignored) - * buf - data to write (ignored) - * count - number of bytes in `buf' - * - * Output parameters: - * returns `count' - * - */ -static ssize_t -discard(int fd, void const* buf, size_t count) -{ - (void)fd; - (void)buf; - return count; -} - -/*PAGE - * - * command_store - * - * Performs the "STOR" command (receive data from client). - * - * Input parameters: - * info - corresponding SessionInfo structure - * char *filename - Destination filename. - * - * Output parameters: - * NONE - */ -static void -command_store(FTPD_SessionInfo_t *info, char const *filename) -{ - int s; - int n; - unsigned long size = 0; - struct rtems_ftpd_hook *usehook = NULL; - char buf[FTPD_DATASIZE]; - int res = 1; - int bare_lfs = 0; - int null = 0; - typedef ssize_t (*WriteProc)(int, void const*, size_t); - WriteProc wrt = &write; - - if(!can_write()) - { - send_reply(info, 550, "Access denied."); - return; - } - - send_mode_reply(info); - - s = data_socket(info); - if(0 > s) - return; - - null = !strcmp("/dev/null", filename); - if (null) - { - /* File "/dev/null" just throws data away. - * FIXME: this is hack. Using `/dev/null' filesystem entry would be - * better. - */ - wrt = &discard; - } - - if (!null && rtems_ftpd_configuration.hooks != NULL) - { - - /* Search our list of hooks to see if we need to do something special. */ - struct rtems_ftpd_hook *hook; - int i; - - i = 0; - hook = &rtems_ftpd_configuration.hooks[i++]; - while (hook->filename != NULL) - { - if (!strcmp(hook->filename, filename)) - { - usehook = hook; - break; - } - hook = &rtems_ftpd_configuration.hooks[i++]; - } - } - - if (usehook != NULL) - { - /* - * OSV: FIXME: Small buffer could be used and hook routine - * called multiple times instead. Alternatively, the support could be - * removed entirely in favor of configuring RTEMS pseudo-device with - * given name. - */ - - char *bigBufr; - size_t filesize = rtems_ftpd_configuration.max_hook_filesize + 1; - - /* - * Allocate space for our "file". - */ - bigBufr = (char *)malloc(filesize); - if (bigBufr == NULL) - { - send_reply(info, 451, "Local resource failure: malloc."); - close_data_socket(info); - return; - } - - /* - * Retrieve the file into our buffer space. - */ - size = 0; - while ((n = recv(s, bigBufr + size, filesize - size, 0)) > 0) - { - size += n; - } - if (size >= filesize) - { - send_reply(info, 451, "File too long: buffer size exceeded."); - free(bigBufr); - close_data_socket(info); - return; - } - - /* - * Call our hook. - */ - res = (usehook->hook_function)(bigBufr, size) == 0; - free(bigBufr); - if(!res) - { - send_reply(info, 451, "File processing failed."); - close_data_socket(info); - return; - } - } - else - { - /* Data transfer to regular file or /dev/null. */ - int fd = 0; - - if(!null) - fd = creat(filename, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - - if (0 > fd) - { - send_reply(info, 550, "Error creating file."); - close_data_socket(info); - return; - } - - if(info->xfer_mode == TYPE_I) - { - while ((n = recv(s, buf, FTPD_DATASIZE, 0)) > 0) - { - if (wrt(fd, buf, n) != n) - { - res = 0; - break; - } - } - } - else if(info->xfer_mode == TYPE_A) - { - int rest = 0; - int pended_cr = 0; - while (res && rest == 0 && (n = recv(s, buf, FTPD_DATASIZE, 0)) > 0) - { - char const* e = buf; - char const* b; - int i; - - rest = n; - if(pended_cr && *e != '\n') - { - char const lf = '\r'; - pended_cr = 0; - if(wrt(fd, &lf, 1) != 1) - { - res = 0; - break; - } - } - do - { - int count; - int sub = 0; - - b = e; - for(i = 0; i < rest; ++i, ++e) - { - int pcr = pended_cr; - pended_cr = 0; - if(*e == '\r') - { - pended_cr = 1; - } - else if(*e == '\n') - { - if(pcr) - { - sub = 2; - ++i; - ++e; - break; - } - ++bare_lfs; - } - } - if(res == 0) - break; - count = i - sub - pended_cr; - if(count > 0 && wrt(fd, b, count) != count) - { - res = 0; - break; - } - if(sub == 2 && wrt(fd, e - 1, 1) != 1) - res = 0; - } - while((rest -= i) > 0); - } - } - - if (0 > close(fd) || res == 0) - { - send_reply(info, 452, "Error writing file."); - close_data_socket(info); - return; - } - } - - if (bare_lfs > 0) - { - snprintf(buf, FTPD_BUFSIZE, - "Transfer complete. WARNING! %d bare linefeeds received in ASCII mode.", - bare_lfs); - send_reply(info, 226, buf); - } - else - send_reply(info, 226, "Transfer complete."); - close_data_socket(info); - -} - - -/*PAGE - * - * send_dirline - * - * Sends one line of LIST command reply corresponding to single file. - * - * Input parameters: - * s - socket descriptor to send data to - * wide - if 0, send only file name. If not 0, send 'stat' info as well in - * "ls -l" format. - * curTime - current time - * path - path to be prepended to what is given by 'add' - * add - path to be appended to what is given by 'path', the resulting path - * is then passed to 'stat()' routine - * name - file name to be reported in output - * buf - buffer for temporary data - * - * Output parameters: - * returns 0 on failure, 1 on success - * - */ -static int -send_dirline(int s, int wide, time_t curTime, char const* path, - char const* add, char const* fname, char* buf) -{ - if(wide) - { - struct stat stat_buf; - - int plen = strlen(path); - int alen = strlen(add); - if(plen == 0) - { - buf[plen++] = '/'; - buf[plen] = '\0'; - } - else - { - strcpy(buf, path); - if(alen > 0 && buf[plen - 1] != '/') - { - buf[plen++] = '/'; - if(plen >= FTPD_BUFSIZE) - return 0; - buf[plen] = '\0'; - } - } - if(plen + alen >= FTPD_BUFSIZE) - return 0; - strcpy(buf + plen, add); - - if (stat(buf, &stat_buf) == 0) - { - int len; - struct tm bt; - time_t tf = stat_buf.st_mtime; - enum { SIZE = 80 }; - enum { SIX_MONTHS = 365*24*60*60/2 }; - char timeBuf[SIZE]; - gmtime_r(&tf, &bt); - if(curTime > tf + SIX_MONTHS || tf > curTime + SIX_MONTHS) - strftime (timeBuf, SIZE, "%b %d %Y", &bt); - else - strftime (timeBuf, SIZE, "%b %d %H:%M", &bt); - - len = snprintf(buf, FTPD_BUFSIZE, - "%c%c%c%c%c%c%c%c%c%c 1 %5d %5d %11u %s %s\r\n", - (S_ISLNK(stat_buf.st_mode)?('l'): - (S_ISDIR(stat_buf.st_mode)?('d'):('-'))), - (stat_buf.st_mode & S_IRUSR)?('r'):('-'), - (stat_buf.st_mode & S_IWUSR)?('w'):('-'), - (stat_buf.st_mode & S_IXUSR)?('x'):('-'), - (stat_buf.st_mode & S_IRGRP)?('r'):('-'), - (stat_buf.st_mode & S_IWGRP)?('w'):('-'), - (stat_buf.st_mode & S_IXGRP)?('x'):('-'), - (stat_buf.st_mode & S_IROTH)?('r'):('-'), - (stat_buf.st_mode & S_IWOTH)?('w'):('-'), - (stat_buf.st_mode & S_IXOTH)?('x'):('-'), - (int)stat_buf.st_uid, - (int)stat_buf.st_gid, - (int)stat_buf.st_size, - timeBuf, - fname - ); - - if(send(s, buf, len, 0) != len) - return 0; - } - } - else - { - int len = snprintf(buf, FTPD_BUFSIZE, "%s\r\n", fname); - if(send(s, buf, len, 0) != len) - return 0; - } - return 1; -} - -/*PAGE - * - * command_list - * - * Send file list to client. - * - * Input parameters: - * info - corresponding SessionInfo structure - * char *fname - File (or directory) to list. - * - * Output parameters: - * NONE - */ -static void -command_list(FTPD_SessionInfo_t *info, char const *fname, int wide) -{ - int s; - DIR *dirp = 0; - struct dirent *dp = 0; - struct stat stat_buf; - char buf[FTPD_BUFSIZE]; - time_t curTime; - int sc = 1; - - send_reply(info, 150, "Opening ASCII mode data connection for LIST."); - - s = data_socket(info); - if(0 > s) - { - syslog(LOG_ERR, "ftpd: Error connecting to data socket."); - return; - } - - if(fname[0] == '\0') - fname = "."; - - if (0 > stat(fname, &stat_buf)) - { - snprintf(buf, FTPD_BUFSIZE, - "%s: No such file or directory.\r\n", fname); - send(s, buf, strlen(buf), 0); - } - else if (S_ISDIR(stat_buf.st_mode) && (NULL == (dirp = opendir(fname)))) - { - snprintf(buf, FTPD_BUFSIZE, - "%s: Can not open directory.\r\n", fname); - send(s, buf, strlen(buf), 0); - } - else - { - time(&curTime); - if(!dirp && *fname) - sc = sc && send_dirline(s, wide, curTime, fname, "", fname, buf); - else { - /* FIXME: need "." and ".." only when '-a' option is given */ - sc = sc && send_dirline(s, wide, curTime, fname, "", ".", buf); - sc = sc && send_dirline(s, wide, curTime, fname, - (strcmp(fname, ftpd_root) ? ".." : ""), "..", buf); - while (sc && (dp = readdir(dirp)) != NULL) - sc = sc && - send_dirline(s, wide, curTime, fname, dp->d_name, dp->d_name, buf); - } - } - - if(dirp) - closedir(dirp); - close_data_socket(info); - - if(sc) - send_reply(info, 226, "Transfer complete."); - else - send_reply(info, 426, "Connection aborted."); -} - - -/*PAGE - * - * command_cwd - * - * Change current working directory. - * - * Input parameters: - * info - corresponding SessionInfo structure - * dir - directory name passed in CWD command - * - * Output parameters: - * NONE - * - */ -static void -command_cwd(FTPD_SessionInfo_t *info, char *dir) -{ - if(chdir(dir) == 0) - send_reply(info, 250, "CWD command successful."); - else - send_reply(info, 550, "CWD command failed."); -} - - -/*PAGE - * - * command_pwd - * - * Send current working directory to client. - * - * Input parameters: - * info - corresponding SessionInfo structure - * - * Output parameters: - * NONE - */ -static void -command_pwd(FTPD_SessionInfo_t *info) -{ - char buf[FTPD_BUFSIZE]; - char const* cwd; - errno = 0; - buf[0] = '"'; - cwd = getcwd(buf + 1, FTPD_BUFSIZE - 4); - if(cwd) - { - int len = strlen(cwd); - static char const txt[] = "\" is the current directory."; - int size = sizeof(txt); - if(len + size + 1 >= FTPD_BUFSIZE) - size = FTPD_BUFSIZE - len - 2; - memcpy(buf + len + 1, txt, size); - buf[len + size] = '\0'; - send_reply(info, 250, buf); - } - else { - snprintf(buf, FTPD_BUFSIZE, "Error: %s.", serr()); - send_reply(info, 452, buf); - } -} - -/*PAGE - * - * command_mdtm - * - * Handle FTP MDTM command (send file modification time to client)/ - * - * Input parameters: - * info - corresponding SessionInfo structure - * fname - file name passed in MDTM command - * - * Output parameters: - * info->cwd is set to new CWD value. - */ -static void -command_mdtm(FTPD_SessionInfo_t *info, char const* fname) -{ - struct stat stbuf; - char buf[FTPD_BUFSIZE]; - - if (0 > stat(fname, &stbuf)) - { - snprintf(buf, FTPD_BUFSIZE, "%s: %s.", fname, serr()); - send_reply(info, 550, buf); - } - else - { - struct tm *t = gmtime(&stbuf.st_mtime); - snprintf(buf, FTPD_BUFSIZE, "%04d%02d%02d%02d%02d%02d", - 1900 + t->tm_year, - t->tm_mon+1, t->tm_mday, - t->tm_hour, t->tm_min, t->tm_sec); - send_reply(info, 213, buf); - } -} - -/*PAGE - * - * command_port - * - * This procedure fills address for data connection given the IP address and - * port of the remote machine. - * - * Input parameters: - * info - corresponding SessionInfo structure - * args - arguments to the "PORT" command. - * - * Output parameters: - * info->data_addr is set according to arguments of the PORT command. - * info->use_default is set to 0 on success, 1 on failure. - */ -static void -command_port(FTPD_SessionInfo_t *info, char const *args) -{ - enum { NUM_FIELDS = 6 }; - unsigned int a[NUM_FIELDS]; - int n; - - close_data_socket(info); - - n = sscanf(args, "%u,%u,%u,%u,%u,%u", a+0, a+1, a+2, a+3, a+4, a+5); - if(NUM_FIELDS == n) - { - int i; - uint8_t b[NUM_FIELDS]; - - for(i = 0; i < NUM_FIELDS; ++i) - { - if(a[i] > 255) - break; - b[i] = (uint8_t)a[i]; - } - - if(i == NUM_FIELDS) - { - /* Note: while it contradicts with RFC959, we don't allow PORT command - * to specify IP address different than those of the originating client - * for the sake of safety. */ - uint32_t const *ip = (uint32_t *)b; - if(*ip == info->def_addr.sin_addr.s_addr) - { - info->data_addr.sin_addr.s_addr = *ip; - info->data_addr.sin_port = *(uint16_t *)(b + 4); - info->data_addr.sin_family = AF_INET; - memset(info->data_addr.sin_zero, 0, sizeof(info->data_addr.sin_zero)); - - info->use_default = 0; - send_reply(info, 200, "PORT command successful."); - return; /* success */ - } - else - { - send_reply(info, 425, "Address doesn't match peer's IP."); - return; - } - } - } - send_reply(info, 501, "Syntax error."); -} - - -/*PAGE - * - * command_pasv - * - * Handle FTP PASV command. - * Open socket, listen for and accept connection on it. - * - * Input parameters: - * info - corresponding SessionInfo structure - * - * Output parameters: - * info->pasv_socket is set to the descriptor of the data socket - */ -static void -command_pasv(FTPD_SessionInfo_t *info) -{ - int s = -1; - int err = 1; - - close_data_socket(info); - - s = socket(PF_INET, SOCK_STREAM, 0); - if (s < 0) - syslog(LOG_ERR, "ftpd: Error creating PASV socket: %s", serr()); - else - { - struct sockaddr_in addr; - int addrLen = sizeof(addr); - - addr = info->ctrl_addr; - addr.sin_port = htons(0); - - if (0 > bind(s, (struct sockaddr *)&addr, addrLen)) - syslog(LOG_ERR, "ftpd: Error binding PASV socket: %s", serr()); - else if (0 > listen(s, 1)) - syslog(LOG_ERR, "ftpd: Error listening on PASV socket: %s", serr()); - else if(set_socket_timeout(s, info->idle)) - { - char buf[FTPD_BUFSIZE]; - unsigned char const *ip, *p; - - getsockname(s, (struct sockaddr *)&addr, &addrLen); - ip = (unsigned char const*)&(addr.sin_addr); - p = (unsigned char const*)&(addr.sin_port); - snprintf(buf, FTPD_BUFSIZE, "Entering passive mode (%u,%u,%u,%u,%u,%u).", - ip[0], ip[1], ip[2], ip[3], p[0], p[1]); - send_reply(info, 227, buf); - - info->pasv_socket = accept(s, (struct sockaddr *)&addr, &addrLen); - if (0 > info->pasv_socket) - syslog(LOG_ERR, "ftpd: Error accepting PASV connection: %s", serr()); - else - { - close_socket(s); - s = -1; - err = 0; - } - } - } - if(err) - { - /* (OSV) The note is from FreeBSD FTPD. - * Note: a response of 425 is not mentioned as a possible response to - * the PASV command in RFC959. However, it has been blessed as a - * legitimate response by Jon Postel in a telephone conversation - * with Rick Adams on 25 Jan 89. */ - send_reply(info, 425, "Can't open passive connection."); - close_socket(s); - } -} - - -/*PAGE - * - * skip_options - * - * Utility routine to skip options (if any) from input command. - * - * Input parameters: - * p - pointer to pointer to command - * - * Output parameters: - * p - is changed to point to first non-option argument - */ -static void -skip_options(char **p) -{ - char* buf = *p; - char* last = NULL; - while(1) { - while(isspace(*buf)) - ++buf; - if(*buf == '-') { - if(*++buf == '-') { /* `--' should terminate options */ - if(isspace(*++buf)) { - last = buf; - do ++buf; - while(isspace(*buf)); - break; - } - } - while(*buf && !isspace(*buf)) - ++buf; - last = buf; - } - else - break; - } - if(last) - *last = '\0'; - *p = buf; -} - -/*PAGE - * - * split_command - * - * Split command into command itself, options, and arguments. Command itself - * is converted to upper case. - * - * Input parameters: - * buf - initial command string - * - * Output parameter: - * buf - is modified by inserting '\0' at ends of split entities - * cmd - upper-cased command code - * opts - string containing all the options - * args - string containing all the arguments - */ -void -split_command(char *buf, char **cmd, char **opts, char **args) -{ - char* eoc; - char* p = buf; - while(isspace(*p)) - ++p; - *cmd = p; - while(*p && !isspace(*p)) - { - *p = toupper(*p); - ++p; - } - eoc = p; - if(*p) - *p++ = '\0'; - while(isspace(*p)) - ++p; - *opts = p; - skip_options(&p); - *args = p; - if(*opts == p) - *opts = eoc; - while(*p && *p != '\r' && *p != '\n') - ++p; - if(*p) - *p++ = '\0'; -} - -/*PAGE - * - * exec_command - * - * Parse and execute FTP command. - * - * FIXME: This section is somewhat of a hack. We should have a better - * way to parse commands. - * - * Input parameters: - * info - corresponding SessionInfo structure - * cmd - command to be executed (upper-case) - * args - arguments of the command - * - * Output parameters: - * NONE - */ -static void -exec_command(FTPD_SessionInfo_t *info, char* cmd, char* args) -{ - char fname[FTPD_BUFSIZE]; - int wrong_command = 0; - - fname[0] = '\0'; - - if (!strcmp("PORT", cmd)) - { - command_port(info, args); - } - else if (!strcmp("PASV", cmd)) - { - command_pasv(info); - } - else if (!strcmp("RETR", cmd)) - { - sscanf(args, "%254s", fname); - command_retrieve(info, fname); - } - else if (!strcmp("STOR", cmd)) - { - sscanf(args, "%254s", fname); - command_store(info, fname); - } - else if (!strcmp("LIST", cmd)) - { - sscanf(args, "%254s", fname); - command_list(info, fname, 1); - } - else if (!strcmp("NLST", cmd)) - { - sscanf(args, "%254s", fname); - command_list(info, fname, 0); - } - else if (!strcmp("MDTM", cmd)) - { - sscanf(args, "%254s", fname); - command_mdtm(info, fname); - } - else if (!strcmp("SYST", cmd)) - { - send_reply(info, 215, FTPD_SYSTYPE); - } - else if (!strcmp("TYPE", cmd)) - { - if (args[0] == 'I') - { - info->xfer_mode = TYPE_I; - send_reply(info, 200, "Type set to I."); - } - else if (args[0] == 'A') - { - info->xfer_mode = TYPE_A; - send_reply(info, 200, "Type set to A."); - } - else - { - info->xfer_mode = TYPE_I; - send_reply(info, 504, "Type not implemented. Set to I."); - } - } - else if (!strcmp("USER", cmd) || !strcmp("PASS", cmd)) - { - send_reply(info, 230, "User logged in."); - } - else if (!strcmp("DELE", cmd)) - { - if(!can_write()) - { - send_reply(info, 550, "Access denied."); - } - else if ( - 1 == sscanf(args, "%254s", fname) && - unlink(fname) == 0) - { - send_reply(info, 257, "DELE successful."); - } - else - { - send_reply(info, 550, "DELE failed."); - } - } - else if (!strcmp("SITE", cmd)) - { - char* opts; - split_command(args, &cmd, &opts, &args); - if(!strcmp("CHMOD", cmd)) - { - int mask; - - if(!can_write()) - { - send_reply(info, 550, "Access denied."); - } - else if( - 2 == sscanf(args, "%o %254s", &mask, fname) && - chmod(fname, (mode_t)mask) == 0) - { - send_reply(info, 257, "CHMOD successful."); - } - else - { - send_reply(info, 550, "CHMOD failed."); - } - } - else - wrong_command = 1; - } - else if (!strcmp("RMD", cmd)) - { - if(!can_write()) - { - send_reply(info, 550, "Access denied."); - } - else if ( - 1 == sscanf(args, "%254s", fname) && - rmdir(fname) == 0) - { - send_reply(info, 257, "RMD successful."); - } - else - { - send_reply(info, 550, "RMD failed."); - } - } - else if (!strcmp("MKD", cmd)) - { - if(!can_write()) - { - send_reply(info, 550, "Access denied."); - } - else if ( - 1 == sscanf(args, "%254s", fname) && - mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0) - { - send_reply(info, 257, "MKD successful."); - } - else - { - send_reply(info, 550, "MKD failed."); - } - } - else if (!strcmp("CWD", cmd)) - { - sscanf(args, "%254s", fname); - command_cwd(info, fname); - } - else if (!strcmp("CDUP", cmd)) - { - command_cwd(info, ".."); - } - else if (!strcmp("PWD", cmd)) - { - command_pwd(info); - } - else - wrong_command = 1; - - if(wrong_command) - send_reply(info, 500, "Command not understood."); -} - - -/*PAGE - * - * session - * - * This task handles single session. It is waked up when the FTP daemon gets a - * service request from a remote machine. Here, we watch for commands that - * will come through the control connection. These commands are then parsed - * and executed until the connection is closed, either unintentionally or - * intentionally with the "QUIT" command. - * - * Input parameters: - * arg - pointer to corresponding SessionInfo. - * - * Output parameters: - * NONE - */ -static void -session(rtems_task_argument arg) -{ - FTPD_SessionInfo_t *const info = (FTPD_SessionInfo_t *)arg; - int chroot_made = 0; - - rtems_libio_set_private_env(); - - /* chroot() can fail here because the directory may not exist yet. */ - chroot_made = chroot(ftpd_root) == 0; - - while(1) - { - rtems_event_set set; - - rtems_event_receive(FTPD_RTEMS_EVENT, RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, - &set); - - chroot_made = chroot_made || chroot(ftpd_root) == 0; - chdir("/"); - - errno = 0; - - send_reply(info, 220, FTPD_SERVER_MESSAGE); - - while (1) - { - char buf[FTPD_BUFSIZE]; - char *cmd, *opts, *args; - - if (fgets(buf, FTPD_BUFSIZE, info->ctrl_fp) == NULL) - { - syslog(LOG_INFO, "ftpd: Connection aborted."); - break; - } - - split_command(buf, &cmd, &opts, &args); - - if (!strcmp("QUIT", cmd)) - { - send_reply(info, 221, "Goodbye."); - break; - } - else - { - exec_command(info, cmd, args); - } - } - - /* Close connection and put ourselves back into the task pool. */ - close_data_socket(info); - close_stream(info); - task_pool_release(info); - } -} - - -/*PAGE - * - * daemon - * - * This task runs forever. It waits for service requests on the FTP port - * (port 21 by default). When a request is received, it opens a new session - * to handle those requests until the connection is closed. - * - * Input parameters: - * NONE - * - * Output parameters: - * NONE - */ -static void -daemon() -{ - int s; - int addrLen; - struct sockaddr_in addr; - FTPD_SessionInfo_t *info = NULL; - - - s = socket(PF_INET, SOCK_STREAM, 0); - if (s < 0) - syslog(LOG_ERR, "ftpd: Error creating socket: %s", serr()); - - addr.sin_family = AF_INET; - addr.sin_port = htons(rtems_ftpd_configuration.port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - memset(addr.sin_zero, 0, sizeof(addr.sin_zero)); - - if (0 > bind(s, (struct sockaddr *)&addr, sizeof(addr))) - syslog(LOG_ERR, "ftpd: Error binding control socket: %s", serr()); - else if (0 > listen(s, 1)) - syslog(LOG_ERR, "ftpd: Error listening on control socket: %s", serr()); - else while (1) - { - int ss; - addrLen = sizeof(addr); - ss = accept(s, (struct sockaddr *)&addr, &addrLen); - if (0 > ss) - syslog(LOG_ERR, "ftpd: Error accepting control connection: %s", serr()); - else if(!set_socket_timeout(ss, ftpd_timeout)) - close_socket(ss); - else - { - info = task_pool_obtain(); - if (NULL == info) - { - close_socket(ss); - } - else - { - info->ctrl_socket = ss; - if ((info->ctrl_fp = fdopen(info->ctrl_socket, "r+")) == NULL) - { - syslog(LOG_ERR, "ftpd: fdopen() on socket failed: %s", serr()); - close_stream(info); - task_pool_release(info); - } - else - { - /* Initialize corresponding SessionInfo structure */ - info->def_addr = addr; - if(0 > getsockname(ss, (struct sockaddr *)&addr, &addrLen)) - { - syslog(LOG_ERR, "ftpd: getsockname(): %s", serr()); - close_stream(info); - task_pool_release(info); - } - else - { - info->use_default = 1; - info->ctrl_addr = addr; - info->pasv_socket = -1; - info->data_socket = -1; - info->xfer_mode = TYPE_A; - info->data_addr.sin_port = - htons(ntohs(info->ctrl_addr.sin_port) - 1); - info->idle = ftpd_timeout; - /* Wakeup the session task. The task will call task_pool_release - after it closes connection. */ - rtems_event_send(info->tid, FTPD_RTEMS_EVENT); - } - } - } - } - } - rtems_task_delete(RTEMS_SELF); -} - - -/*PAGE - * - * rtems_ftpd_start - * - * Here, we start the FTPD task which waits for FTP requests and services - * them. This procedure returns to its caller once the task is started. - * - * - * Input parameters: - * - * Output parameters: - * returns RTEMS_SUCCESSFUL on successful start of the daemon. - */ -int -rtems_initialize_ftpd() -{ - rtems_status_code sc; - rtems_id tid; - rtems_task_priority priority; - int count; - - if (rtems_ftpd_configuration.port == 0) - { - rtems_ftpd_configuration.port = FTPD_CONTROL_PORT; - } - - if (rtems_ftpd_configuration.priority == 0) - { - rtems_ftpd_configuration.priority = 40; - } - priority = rtems_ftpd_configuration.priority; - - ftpd_timeout = rtems_ftpd_configuration.idle; - if (ftpd_timeout < 0) - ftpd_timeout = 0; - rtems_ftpd_configuration.idle = ftpd_timeout; - - ftpd_access = rtems_ftpd_configuration.access; - - if (rtems_ftpd_configuration.tasks_count <= 0) - rtems_ftpd_configuration.tasks_count = 1; - count = rtems_ftpd_configuration.tasks_count; - - if (!task_pool_init(count, priority)) - { - syslog(LOG_ERR, "ftpd: Could not initialize task pool."); - return RTEMS_UNSATISFIED; - } - - sc = rtems_task_create(rtems_build_name('F', 'T', 'P', 'D'), - priority, FTPD_STACKSIZE, - RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR | - RTEMS_INTERRUPT_LEVEL(0), - RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, - &tid); - - if (sc == RTEMS_SUCCESSFUL) - { - sc = rtems_task_start(tid, daemon, 0); - if (sc != RTEMS_SUCCESSFUL) - rtems_task_delete(tid); - } - - if (sc != RTEMS_SUCCESSFUL) - { - task_pool_done(count); - syslog(LOG_ERR, "ftpd: Could not create/start FTP daemon: %s", - rtems_status_text(sc)); - return RTEMS_UNSATISFIED; - } - - ftpd_root = "/"; - if ( - rtems_ftpd_configuration.root && - rtems_ftpd_configuration.root[0] == '/' - ) - ftpd_root = rtems_ftpd_configuration.root; - - rtems_ftpd_configuration.root = ftpd_root; - - syslog(LOG_INFO, "ftpd: FTP daemon started (%d session%s max)", - count, ((count > 1) ? "s" : "")); - - return RTEMS_SUCCESSFUL; -} -- cgit v1.2.3