ftpd.c
来自「RTEMS (Real-Time Executive for Multiproc」· C语言 代码 · 共 2,063 行 · 第 1/4 页
C
2,063 行
* * Input parameters: * p - pointer to pointer to command * * Output parameters: * p - is changed to point to first non-option argument */static voidskip_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 */voidsplit_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 voidexec_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 voidsession(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 voiddaemon(){ 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. */intrtems_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;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?