int main(int argc, char **argv) { skod_t skod; ftp_t ftp; skod_init(&skod); skod_parse_cla(argc, argv, &skod); signal(SIGINT, signal_handler); /* Init FTP*/ ftp.user = skod.user; ftp.password = skod.password; ftp.server = skod.server; ftp.port = skod.port; ftp.alarm_sec = 1; /* High risk */ ftp_mkcon(&ftp); /* --dest, -e*/ if ( skod.dest != NULL ) ftp_cwd(&ftp, skod.dest); else if ( skod.dest == NULL && flag == 4 ) die("You need to pass --dest (destination folder) with --upload."); switch(flag) { case 1: ftp_list(&ftp, skod.path, 1); break; case 2: ftp_remove(&ftp, skod.path); break; case 3: ftp_download_single(&ftp, skod.path); break; case 4: ftp_upload_single(&ftp, skod.path); break; case 5: ftp_cat(&ftp, skod.path); break; case 6: printf("%d\n", ftp_size(&ftp, skod.path)); break; case 7: printf("%s\n", ftp_pwd(&ftp)); break; case 8: ftp_delete(&ftp, skod.path); break; case 10: ftp_mdtm(&ftp, skod.path); break; case 99: skod_scan(&skod, &ftp); break; } ftp_close(&ftp); return 0; }
void cmd_nlist(int argc, char **argv) { OPT_HELP_NEW(_("Simple file list."), "nlist [options] [file]", NULL); need_connected(); need_loggedin(); if(argc == optind + 1) ftp_list("NLST", 0, stdout); else { char *args; args = args_cat(argc, argv, optind); ftp_list("NLST", args, stdout); free(args); } }
void cmd_nlist(int argc, char **argv) { OPT_HELP("Simple file list. Usage:\n" " nlist [options] [file]\n" "Options:\n" " -h, --help show this help\n"); need_connected(); need_loggedin(); if(argc == optind + 1) ftp_list("NLST", 0, stdout); else { char *args; args = args_cat(argc, argv, optind); ftp_list("NLST", args, stdout); free(args); } }
/** * Generates response message for client * @param cmd Current command * @param state Current connection state */ void response(Command *cmd, State *state) { switch(lookup_cmd(cmd->command)){ case USER: ftp_user(cmd,state); break; case PASS: ftp_pass(cmd,state); break; case PASV: ftp_pasv(cmd,state); break; case LIST: ftp_list(cmd,state); break; case CWD: ftp_cwd(cmd,state); break; case PWD: ftp_pwd(cmd,state); break; case MKD: ftp_mkd(cmd,state); break; case RMD: ftp_rmd(cmd,state); break; case RETR: ftp_retr(cmd,state); break; case STOR: ftp_stor(cmd,state); break; case DELE: ftp_dele(cmd,state); break; case SIZE: ftp_size(cmd,state); break; case ABOR: ftp_abor(state); break; case QUIT: ftp_quit(state); break; case TYPE: ftp_type(cmd,state); break; case CDUP: ftp_cdup(state); break; case HELP: ftp_help(cmd, state); break; case NLST: ftp_nlst(cmd, state); break; case RNFR: ftp_rnfr(cmd, state); break; case RNTO: ftp_rnto(cmd, state); break; case APPE: ftp_appe(cmd, state); break; case NOOP: if(state->logged_in){ state->message = "200 Zzz...\n"; }else{ state->message = "530 Please login with USER and PASS\n"; } write_state(state); break; default: state->message = "500 Unknown command\n"; write_state(state); break; } }
/*################## get_remote_file_names_ftp_list() ###################*/ int get_remote_file_names_ftp_list(off_t *file_size_to_retrieve, int *more_files_in_list) { int files_to_retrieve = 0, i = 0; *file_size_to_retrieve = 0; #ifdef DO_NOT_PARALLELIZE_ALL_FETCH if ((*more_files_in_list == YES) || (db.special_flag & DISTRIBUTED_HELPER_JOB) || ((db.special_flag & OLD_ERROR_JOB) && (db.retries < 30) && (fra[db.fra_pos].stupid_mode != YES) && (fra[db.fra_pos].remove != YES))) #else if (rl_fd == -1) { try_attach_again: if (attach_ls_data(db.fra_pos, db.fsa_pos, db.special_flag, YES) == INCORRECT) { (void)ftp_quit(); exit(INCORRECT); } if ((db.special_flag & DISTRIBUTED_HELPER_JOB) && ((fra[db.fra_pos].stupid_mode == YES) || (fra[db.fra_pos].remove == YES))) { # ifdef LOCK_DEBUG if (rlock_region(rl_fd, LOCK_RETR_PROC, __FILE__, __LINE__) == LOCK_IS_SET) # else if (rlock_region(rl_fd, LOCK_RETR_PROC) == LOCK_IS_SET) # endif { if (i == 0) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Hmm, lock is set. Assume ls_data file was just modified. Lets try it again. (job_no=%d fsa_pos=%d)", (int)db.job_no, db.fsa_pos); } else { if (i == 30) { trans_log(DEBUG_SIGN, __FILE__, __LINE__, NULL, NULL, "Have waited %d seconds, but unable to get a lock. Terminating.", (i * 100000) / 1000000); (void)ftp_quit(); exit(SUCCESS); } my_usleep(100000L); } detach_ls_data(NO); i++; goto try_attach_again; } } } if ((*more_files_in_list == YES) || (db.special_flag & DISTRIBUTED_HELPER_JOB) || ((db.special_flag & OLD_ERROR_JOB) && (db.retries < 30))) #endif { #ifdef DO_NOT_PARALLELIZE_ALL_FETCH if (rl_fd == -1) { if (attach_ls_data(db.fra_pos, db.fsa_pos, db.special_flag, YES) == INCORRECT) { (void)ftp_quit(); exit(INCORRECT); } } #endif *more_files_in_list = NO; for (i = 0; i < no_of_listed_files; i++) { if ((rl[i].retrieved == NO) && (rl[i].assigned == 0)) { #ifdef DO_NOT_PARALLELIZE_ALL_FETCH if ((fra[db.fra_pos].stupid_mode == YES) || (fra[db.fra_pos].remove == YES) || ((files_to_retrieve < fra[db.fra_pos].max_copied_files) && (*file_size_to_retrieve < fra[db.fra_pos].max_copied_file_size))) #else if ((files_to_retrieve < fra[db.fra_pos].max_copied_files) && (*file_size_to_retrieve < fra[db.fra_pos].max_copied_file_size)) #endif { /* Lock this file in list. */ #ifdef LOCK_DEBUG if (lock_region(rl_fd, (off_t)(LOCK_RETR_FILE + i), __FILE__, __LINE__) == LOCK_IS_NOT_SET) #else if (lock_region(rl_fd, (off_t)(LOCK_RETR_FILE + i)) == LOCK_IS_NOT_SET) #endif { if ((fra[db.fra_pos].ignore_size == -1) || ((fra[db.fra_pos].gt_lt_sign & ISIZE_EQUAL) && (fra[db.fra_pos].ignore_size == rl[i].size)) || ((fra[db.fra_pos].gt_lt_sign & ISIZE_LESS_THEN) && (fra[db.fra_pos].ignore_size < rl[i].size)) || ((fra[db.fra_pos].gt_lt_sign & ISIZE_GREATER_THEN) && (fra[db.fra_pos].ignore_size > rl[i].size))) { if ((rl[i].got_date == NO) || (fra[db.fra_pos].ignore_file_time == 0)) { files_to_retrieve++; if ((fra[db.fra_pos].stupid_mode == APPEND_ONLY) && (rl[i].size > rl[i].prev_size)) { *file_size_to_retrieve += (rl[i].size - rl[i].prev_size); } else { *file_size_to_retrieve += rl[i].size; } rl[i].assigned = (unsigned char)db.job_no + 1; } else { time_t diff_time; diff_time = current_time - rl[i].file_mtime; if (((fra[db.fra_pos].gt_lt_sign & IFTIME_EQUAL) && (fra[db.fra_pos].ignore_file_time == diff_time)) || ((fra[db.fra_pos].gt_lt_sign & IFTIME_LESS_THEN) && (fra[db.fra_pos].ignore_file_time < diff_time)) || ((fra[db.fra_pos].gt_lt_sign & IFTIME_GREATER_THEN) && (fra[db.fra_pos].ignore_file_time > diff_time))) { files_to_retrieve++; if ((fra[db.fra_pos].stupid_mode == APPEND_ONLY) && (rl[i].size > rl[i].prev_size)) { *file_size_to_retrieve += (rl[i].size - rl[i].prev_size); } else { *file_size_to_retrieve += rl[i].size; } rl[i].assigned = (unsigned char)db.job_no + 1; } } #ifdef DEBUG_ASSIGNMENT trans_log(DEBUG_SIGN, __FILE__, __LINE__, NULL, NULL, # if SIZEOF_OFF_T == 4 "%s assigned %d: file_name=%s assigned=%d size=%ld", # else "%s assigned %d: file_name=%s assigned=%d size=%lld", # endif (fra[db.fra_pos].ls_data_alias[0] == '\0') ? fra[db.fra_pos].dir_alias : fra[db.fra_pos].ls_data_alias, i, rl[i].file_name, (int)rl[i].assigned, (pri_off_t)rl[i].size); #endif /* DEBUG_ASSIGNMENT */ } #ifdef LOCK_DEBUG unlock_region(rl_fd, (off_t)(LOCK_RETR_FILE + i), __FILE__, __LINE__); #else unlock_region(rl_fd, (off_t)(LOCK_RETR_FILE + i)); #endif } } else { *more_files_in_list = YES; break; } } } } else { unsigned int files_deleted = 0, list_length = 0; int gotcha, j, k, nfg, /* Number of file mask. */ status, type; char file_name[MAX_FILENAME_LENGTH + 1], *list = NULL, *p_end, *p_mask, *p_start; time_t file_mtime; off_t file_size, file_size_deleted = 0, list_size = 0; struct ftpparse fp; struct file_mask *fml = NULL; struct tm *p_tm; /* * Get a directory listing from the remote site so we can see * what files are there. */ #ifdef WITH_SSL if (db.auth == BOTH) { type = LIST_CMD | BUFFERED_LIST | ENCRYPT_DATA; } else { #endif type = LIST_CMD | BUFFERED_LIST; #ifdef WITH_SSL } #endif if ((status = ftp_list(db.mode_flag, type, &list)) != SUCCESS) { trans_log(ERROR_SIGN, __FILE__, __LINE__, NULL, msg_str, "Failed to send LIST command (%d).", status); (void)ftp_quit(); exit(LIST_ERROR); } if (list != NULL) { /* Get all file masks for this directory. */ if ((j = read_file_mask(fra[db.fra_pos].dir_alias, &nfg, &fml)) == INCORRECT) { if (j == LOCKFILE_NOT_THERE) { system_log(ERROR_SIGN, __FILE__, __LINE__, "Failed to set lock in file masks for %s, because the file is not there.", fra[db.fra_pos].dir_alias); } else if (j == LOCK_IS_SET) { system_log(ERROR_SIGN, __FILE__, __LINE__, "Failed to get the file masks for %s, because lock is already set", fra[db.fra_pos].dir_alias); } else { system_log(ERROR_SIGN, __FILE__, __LINE__, "Failed to get the file masks for %s. (%d)", fra[db.fra_pos].dir_alias, j); } if (fml != NULL) { free(fml); } (void)ftp_quit(); exit(INCORRECT); } #ifdef DO_NOT_PARALLELIZE_ALL_FETCH if ((fra[db.fra_pos].stupid_mode == YES) || (fra[db.fra_pos].remove == YES)) { if (reset_ls_data(db.fra_pos) == INCORRECT) { (void)ftp_quit(); exit(INCORRECT); } } else { if (rl_fd == -1) { if (attach_ls_data(db.fra_pos, db.fsa_pos, db.special_flag, YES) == INCORRECT) { (void)ftp_quit(); exit(INCORRECT); } } } #else if (rl_fd == -1) { if (attach_ls_data(db.fra_pos, db.fsa_pos, db.special_flag, YES) == INCORRECT) { (void)ftp_quit(); exit(INCORRECT); } } if ((fra[db.fra_pos].stupid_mode == YES) || (fra[db.fra_pos].remove == YES)) { /* * If all files from the previous listing have been * collected, lets reset the ls_data structure or otherwise * it keeps on growing forever. */ # ifdef LOCK_DEBUG if (lock_region(rl_fd, LOCK_RETR_PROC, __FILE__, __LINE__) == LOCK_IS_NOT_SET) # else if (lock_region(rl_fd, LOCK_RETR_PROC) == LOCK_IS_NOT_SET) # endif { if (reset_ls_data(db.fra_pos) == INCORRECT) { (void)ftp_quit(); exit(INCORRECT); } } # ifdef LOCK_DEBUG unlock_region(rl_fd, LOCK_RETR_PROC, __FILE__, __LINE__); # else unlock_region(rl_fd, LOCK_RETR_PROC); # endif } #endif if ((fra[db.fra_pos].ignore_file_time != 0) || (fra[db.fra_pos].delete_files_flag & UNKNOWN_FILES)) { /* Note: FTP returns GMT so we need to convert this to GMT! */ current_time = time(NULL); p_tm = gmtime(¤t_time); current_time = mktime(p_tm); } /* * Evaluate the list from the LIST command. */ p_end = list; do { p_start = p_end; while ((*p_end != '\r') && (*p_end != '\n') && (*p_end != '\0')) { p_end++; } if ((ftpparse(&fp, &file_size, &file_mtime, p_start, p_end - p_start) == 1) && ((fp.flagtryretr == 1) && ((fp.name[0] != '.') || (fra[db.fra_pos].dir_flag & ACCEPT_DOT_FILES)))) { list_length++; list_size += file_size; if (fp.namelen < MAX_FILENAME_LENGTH) { /* Store file name */ (void)memcpy(file_name, fp.name, fp.namelen); file_name[fp.namelen] = '\0'; if (fra[db.fra_pos].dir_flag == ALL_DISABLED) { delete_remote_file(FTP, file_name, fp.namelen, #ifdef _DELETE_LOG DELETE_HOST_DISABLED, #endif &files_deleted, &file_size_deleted, file_size); } else { gotcha = NO; for (k = 0; k < nfg; k++) { p_mask = fml[k].file_list; for (j = 0; j < fml[k].fc; j++) { if ((status = pmatch(p_mask, file_name, NULL)) == 0) { if (check_list(file_name, file_size, file_mtime, &files_to_retrieve, file_size_to_retrieve, more_files_in_list) == 0) { gotcha = YES; } else { gotcha = NEITHER; } break; } else if (status == 1) { /* This file is definitly NOT wanted! */ /* Lets skip the rest of this group. */ break; } #ifdef SHOW_FILTER_MISSES if ((status == -1) || (fsa->debug > NORMAL_MODE)) { char tmp_mask[MAX_FILENAME_LENGTH]; if (expand_filter(p_mask, tmp_mask, time(NULL)) == YES) { trans_db_log(INFO_SIGN, __FILE__, __LINE__, NULL, "%s (%s) not fitting %s", p_mask, tmp_mask, file_name); } else { trans_db_log(INFO_SIGN, __FILE__, __LINE__, NULL, "%s not fitting %s", p_mask, file_name); } } #endif NEXT(p_mask); } if ((gotcha == YES) || (gotcha == NEITHER)) { break; } } if ((gotcha == NO) && (status != 0) && (fra[db.fra_pos].delete_files_flag & UNKNOWN_FILES)) { time_t diff_time = current_time - file_mtime; if ((fra[db.fra_pos].unknown_file_time == -2) || ((diff_time > fra[db.fra_pos].unknown_file_time) && (diff_time > DEFAULT_TRANSFER_TIMEOUT))) { delete_remote_file(FTP, file_name, fp.namelen, #ifdef _DELETE_LOG DEL_UNKNOWN_FILE, #endif &files_deleted, &file_size_deleted, file_size); } } } } else { (void)memcpy(file_name, fp.name, MAX_FILENAME_LENGTH); file_name[MAX_FILENAME_LENGTH] = '\0'; trans_log(ERROR_SIGN, __FILE__, __LINE__, NULL, NULL, "Remote file name `%s' is to long, it may only be %d bytes long.", file_name, MAX_FILENAME_LENGTH); } } while ((*p_end == '\r') || (*p_end == '\n')) { p_end++; } } while (*p_end != '\0'); free(list); /* Free file mask list. */ for (i = 0; i < nfg; i++) { free(fml[i].file_list); } free(fml); } if (files_deleted > 0) { trans_log(DEBUG_SIGN, NULL, 0, NULL, NULL, #if SIZEOF_OFF_T == 4 "%d files %ld bytes found for retrieving %s[%u files with %ld bytes in %s (deleted %u files with %ld bytes)]. @%x", #else "%d files %lld bytes found for retrieving %s[%u files with %lld bytes in %s (deleted %u files with %lld bytes)]. @%x", #endif files_to_retrieve, (pri_off_t)(*file_size_to_retrieve), (*more_files_in_list == YES) ? "(+) " : "", list_length, (pri_off_t)list_size, (db.target_dir[0] == '\0') ? "home dir" : db.target_dir, files_deleted, (pri_off_t)file_size_deleted, db.id.dir); } else { trans_log(DEBUG_SIGN, NULL, 0, NULL, NULL, #if SIZEOF_OFF_T == 4 "%d files %ld bytes found for retrieving %s[%u files with %ld bytes in %s]. @%x", #else "%d files %lld bytes found for retrieving %s[%u files with %lld bytes in %s]. @%x", #endif files_to_retrieve, (pri_off_t)(*file_size_to_retrieve), (*more_files_in_list == YES) ? "(+) " : "", list_length, (pri_off_t)list_size, (db.target_dir[0] == '\0') ? "home dir" : db.target_dir, db.id.dir); } /* * Remove all files from the remote_list structure that are not * in the current buffer. */ if ((fra[db.fra_pos].stupid_mode != YES) && (fra[db.fra_pos].remove == NO)) { int files_removed = 0, i; size_t move_size; for (i = 0; i < (no_of_listed_files - files_removed); i++) { if (rl[i].in_list == NO) { int j = i; while ((rl[j].in_list == NO) && (j < (no_of_listed_files - files_removed))) { j++; } if (j != (no_of_listed_files - files_removed)) { move_size = (no_of_listed_files - files_removed - j) * sizeof(struct retrieve_list); (void)memmove(&rl[i], &rl[j], move_size); } files_removed += (j - i); } } if (files_removed > 0) { int current_no_of_listed_files = no_of_listed_files; size_t new_size, old_size; no_of_listed_files -= files_removed; if (no_of_listed_files < 0) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Hmmm, no_of_listed_files = %d", no_of_listed_files); no_of_listed_files = 0; } if (no_of_listed_files == 0) { new_size = (RETRIEVE_LIST_STEP_SIZE * sizeof(struct retrieve_list)) + AFD_WORD_OFFSET; } else { new_size = (((no_of_listed_files / RETRIEVE_LIST_STEP_SIZE) + 1) * RETRIEVE_LIST_STEP_SIZE * sizeof(struct retrieve_list)) + AFD_WORD_OFFSET; } old_size = (((current_no_of_listed_files / RETRIEVE_LIST_STEP_SIZE) + 1) * RETRIEVE_LIST_STEP_SIZE * sizeof(struct retrieve_list)) + AFD_WORD_OFFSET; if (old_size != new_size) { char *ptr; ptr = (char *)rl - AFD_WORD_OFFSET; #ifdef DO_NOT_PARALLELIZE_ALL_FETCH if ((fra[db.fra_pos].stupid_mode == YES) || (fra[db.fra_pos].remove == YES)) { if ((ptr = realloc(ptr, new_size)) == NULL) { system_log(ERROR_SIGN, __FILE__, __LINE__, "realloc() error : %s", strerror(errno)); (void)ftp_quit(); exit(INCORRECT); } } else { #endif if ((ptr = mmap_resize(rl_fd, ptr, new_size)) == (caddr_t) -1) { system_log(ERROR_SIGN, __FILE__, __LINE__, "mmap_resize() error : %s", strerror(errno)); (void)ftp_quit(); exit(INCORRECT); } rl_size = new_size; #ifdef DO_NOT_PARALLELIZE_ALL_FETCH } #endif ptr += AFD_WORD_OFFSET; rl = (struct retrieve_list *)ptr; } *(int *)((char *)rl - AFD_WORD_OFFSET) = no_of_listed_files; } } } return(files_to_retrieve); }
rdirectory *ftp_read_directory(const char *path) { FILE *fp = 0; rdirectory *rdir; bool is_curdir = false; bool _failed = false; char *dir; bool is_mlsd = false; #ifdef HAVE_LIBSSH if(ftp->session) return ssh_read_directory(path); #endif dir = ftp_path_absolute(path); stripslash(dir); is_curdir = (strcmp(dir, ftp->curdir) == 0); if((fp = tmpfile()) == NULL) { /* can't create a tmpfile */ ftp_err("Unable to create temp file: %s\n", strerror(errno)); free(dir); return 0; } /* we do a "CWD" before the listing, because: we want a listing of * the directory contents, not the directory itself, and some * servers misunderstand this. If the target is a link to a * directory, we have to do this. */ if(!is_curdir) { ftp_cmd("CWD %s", dir); if(ftp->code != ctComplete) goto failed; } if(ftp->has_mlsd_command) { is_mlsd = true; #if 0 /* PureFTPd (1.0.11) doesn't recognize directory arguments * with spaces, not even quoted, it just chops the argument * string after the first space, duh... so we have to CWD to * the directory... */ char *asdf; asprintf(&asdf, "%s/", dir); /* Hack to get around issue in PureFTPd (up to version 0.98.2): * doing a 'MLSD link-to-dir' on PureFTPd closes the control * connection, however, 'MLSD link-to-dir/' works fine. */ _failed = (ftp_list("MLSD", asdf, fp) != 0); free(asdf); #else _failed = (ftp_list("MLSD", 0, fp) != 0); #endif if(_failed && ftp->code == ctError) ftp->has_mlsd_command = false; } if(!ftp->has_mlsd_command) { _failed = (ftp_list("LIST", 0, fp) != 0); is_mlsd = false; } if(!is_curdir) ftp_cmd("CWD %s", ftp->curdir); if(_failed) goto failed; rewind(fp); rdir = rdir_create(); if(rdir_parse(rdir, fp, dir, is_mlsd) != 0) { rdir_destroy(rdir); goto failed; } fclose(fp); ftp_trace("added directory '%s' to cache\n", dir); list_additem(ftp->cache, rdir); free(dir); return rdir; failed: /* forgive me father, for I have goto'ed */ if (fp) fclose(fp); free(dir); return 0; }
int main(int argc,char **argv) { printf("ftp>"); char command[MAXSIZE]; char*cmd; scanf("%s",command); cmd=command; while(*(cmd)==' ') cmd++; if(strncmp(cmd,"login",5)==0) { login(); if(login_yes==1) { while(1) { comm: sleep(1); printf("ftp>"); zeromery(command,1024); scanf("%s",command); cmd=command; while(*(cmd)==' ') cmd++; if(strncmp(cmd,"pasv",4)==0) { ftp_list(control_sockfd); } if(strncmp(cmd,"port",4)==0) { ftp_list(control_sockfd); } if(strncmp(cmd,"list",4)==0) { ftp_pwd(control_sockfd); ftp_list(control_sockfd); } if(strncmp(cmd,"pwd",3)==0) { ftp_pwd(control_sockfd); } if(strncmp(cmd,"mkdir",5)==0) { char path[60]; zeromery(path,60); printf("创建的路径名: "); scanf("%s",path); printf("s\n",path); ftp_creat_mkd(path,control_sockfd); } if(strncmp(cmd,"back",4)==0) { ftp_back(control_sockfd); ftp_pwd(control_sockfd); } if(strncmp(cmd,"cd",2)==0) { int i; char path[60]; zeromery(path,60); printf("要到的路径:"); scanf("%s",path); printf("%s\n",path); ftp_changdir(path,control_sockfd); } if(strncmp(cmd,"get",3)==0) { ftp_pwd(control_sockfd); ftp_download(control_sockfd); } if(strncmp(cmd,"up",3)==0) { ftp_pwd(control_sockfd); ftp_up(control_sockfd); } if(strncmp(cmd,"quit",4)==0) { printf("bye^_^\n"); close(control_sockfd); break; } printf("支持 list,pwd,mkdir,back,cd,up,get\n"); } } else if(login_yes==0) { int i;//不成功登录下最多还有两次机会,如果不能在两次登录,则,关闭链接。 printf("Can not login vsftpd"); for(i=2;i>0;i--) { printf("你还有 %d 登录机会\n",i); login(); if(login_yes==1) { goto comm; } } if(i==0) { printf("你不能在登录!\n"); close(control_sockfd); } } else if (strncmp(cmd,"quit",4)==0) { ftp_quit(control_sockfd); close(control_sockfd); } } return 0; }