File indexing completed on 2025-05-11 08:24:11
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222 #ifdef HAVE_CONFIG_H
0223 #include "config.h"
0224 #endif
0225
0226 #include <stdio.h>
0227 #include <stdlib.h>
0228 #include <string.h>
0229 #include <unistd.h>
0230 #include <fcntl.h>
0231 #include <dirent.h>
0232 #include <errno.h>
0233 #include <ctype.h>
0234 #include <inttypes.h>
0235 #include <sched.h>
0236
0237 #include <rtems.h>
0238 #include <rtems/error.h>
0239 #include <rtems/ftpd.h>
0240 #include <rtems/libio.h>
0241 #include <rtems/thread.h>
0242 #include <rtems/userenv.h>
0243 #include <syslog.h>
0244
0245 #include <sys/types.h>
0246 #include <sys/socket.h>
0247 #include <arpa/ftp.h>
0248 #include <netinet/in.h>
0249
0250
0251 #ifdef __GNUC__
0252
0253 #if 0
0254 #undef syslog
0255 #define syslog(a, b, ...) while(0){}
0256 #endif
0257 #endif
0258
0259 #define FTPD_SERVER_MESSAGE "RTEMS FTP server (Version 1.1-JWJ) ready."
0260
0261 #define FTPD_SYSTYPE "UNIX Type: L8"
0262
0263
0264 #if 0
0265 #define FTPD_WELCOME_MESSAGE \
0266 "Welcome to the RTEMS FTP server.\n" \
0267 "\n" \
0268 "Login accepted.\n"
0269 #endif
0270
0271
0272 enum
0273 {
0274 FTPD_RTEMS_EVENT = RTEMS_EVENT_1
0275 };
0276
0277
0278 static struct rtems_ftpd_configuration *ftpd_config;
0279
0280
0281 FILE *fdopen (int fildes, const char *mode);
0282
0283
0284
0285
0286
0287 typedef struct
0288 {
0289 struct sockaddr_in ctrl_addr;
0290 struct sockaddr_in data_addr;
0291 struct sockaddr_in def_addr;
0292 int use_default;
0293 FILE *ctrl_fp;
0294 int ctrl_socket;
0295 int pasv_socket;
0296 int data_socket;
0297 int idle;
0298 int xfer_mode;
0299 rtems_id tid;
0300 char *user;
0301 char user_buf[256];
0302 bool auth;
0303 } FTPD_SessionInfo_t;
0304
0305
0306
0307
0308
0309 typedef struct
0310 {
0311 FTPD_SessionInfo_t *info;
0312 FTPD_SessionInfo_t **queue;
0313 int count;
0314 int head;
0315 int tail;
0316 rtems_mutex mutex;
0317 rtems_counting_semaphore sem;
0318 } FTPD_TaskPool_t;
0319
0320
0321
0322
0323 static FTPD_TaskPool_t task_pool;
0324
0325
0326
0327
0328
0329 static char const* ftpd_root = "/";
0330
0331
0332
0333
0334 static int ftpd_timeout = 0;
0335
0336
0337
0338
0339 static int ftpd_access = 0;
0340
0341 static void
0342 yield(void)
0343 {
0344
0345
0346
0347
0348
0349 #ifndef RTEMS_NETWORKING
0350 sched_yield();
0351 #endif
0352 }
0353
0354
0355
0356
0357
0358
0359
0360 static char const*
0361 serr(void)
0362 {
0363 int err = errno;
0364 errno = 0;
0365 return strerror(err);
0366 }
0367
0368
0369
0370
0371
0372
0373 static int
0374 can_read(void)
0375 {
0376 return (ftpd_access & FTPD_NO_READ) == 0;
0377 }
0378
0379 static int
0380 can_write(void)
0381 {
0382 return (ftpd_access & FTPD_NO_WRITE) == 0;
0383 }
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403 static void
0404 task_pool_done(int count)
0405 {
0406 int i;
0407 for(i = 0; i < count; ++i)
0408 rtems_task_delete(task_pool.info[i].tid);
0409 free(task_pool.info);
0410 free(task_pool.queue);
0411 rtems_mutex_destroy(&task_pool.mutex);
0412 rtems_counting_semaphore_destroy(&task_pool.sem);
0413 task_pool.info = 0;
0414 task_pool.queue = 0;
0415 task_pool.count = 0;
0416 }
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431 static void session(rtems_task_argument arg);
0432
0433 static int
0434 task_pool_init(int count, rtems_task_priority priority)
0435 {
0436 int i;
0437 rtems_status_code sc;
0438 char id = 'a';
0439
0440 task_pool.count = 0;
0441 task_pool.head = task_pool.tail = 0;
0442
0443 rtems_mutex_init(&task_pool.mutex, "FTPD");
0444 rtems_counting_semaphore_init(&task_pool.sem, "FTPD", (unsigned int) count);
0445
0446 task_pool.info = (FTPD_SessionInfo_t*)
0447 malloc(sizeof(FTPD_SessionInfo_t) * count);
0448 task_pool.queue = (FTPD_SessionInfo_t**)
0449 malloc(sizeof(FTPD_SessionInfo_t*) * count);
0450 if (NULL == task_pool.info || NULL == task_pool.queue)
0451 {
0452 task_pool_done(0);
0453 syslog(LOG_ERR, "ftpd: Not enough memory");
0454 return 0;
0455 }
0456
0457 for(i = 0; i < count; ++i)
0458 {
0459 FTPD_SessionInfo_t *info = &task_pool.info[i];
0460 sc = rtems_task_create(rtems_build_name('F', 'T', 'P', id),
0461 priority, FTPD_STACKSIZE,
0462 RTEMS_PREEMPT | RTEMS_NO_TIMESLICE |
0463 RTEMS_NO_ASR | RTEMS_INTERRUPT_LEVEL(0),
0464 RTEMS_FLOATING_POINT | RTEMS_LOCAL,
0465 &info->tid);
0466 if (sc == RTEMS_SUCCESSFUL)
0467 {
0468 sc = rtems_task_start(
0469 info->tid, session, (rtems_task_argument)info);
0470 if (sc != RTEMS_SUCCESSFUL)
0471 task_pool_done(i);
0472 }
0473 else
0474 task_pool_done(i + 1);
0475 if (sc != RTEMS_SUCCESSFUL)
0476 {
0477 syslog(LOG_ERR, "ftpd: Could not create/start FTPD session: %s",
0478 rtems_status_text(sc));
0479 return 0;
0480 }
0481 task_pool.queue[i] = task_pool.info + i;
0482 if (++id > 'z')
0483 id = 'a';
0484 }
0485 task_pool.count = count;
0486 return 1;
0487 }
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502 static FTPD_SessionInfo_t*
0503 task_pool_obtain(void)
0504 {
0505 FTPD_SessionInfo_t* info = 0;
0506 rtems_counting_semaphore_wait(&task_pool.sem);
0507 rtems_mutex_lock(&task_pool.mutex);
0508 info = task_pool.queue[task_pool.head];
0509 if(++task_pool.head >= task_pool.count)
0510 task_pool.head = 0;
0511 rtems_mutex_unlock(&task_pool.mutex);
0512 return info;
0513 }
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527 static void
0528 task_pool_release(FTPD_SessionInfo_t* info)
0529 {
0530 rtems_mutex_lock(&task_pool.mutex);
0531 task_pool.queue[task_pool.tail] = info;
0532 if(++task_pool.tail >= task_pool.count)
0533 task_pool.tail = 0;
0534 rtems_mutex_unlock(&task_pool.mutex);
0535 rtems_counting_semaphore_post(&task_pool.sem);
0536 }
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557 static void
0558 send_reply(FTPD_SessionInfo_t *info, int code, const char *text)
0559 {
0560 text = text != NULL ? text : "";
0561 fprintf(info->ctrl_fp, "%d %.70s\r\n", code, text);
0562 fflush(info->ctrl_fp);
0563 }
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579 static void
0580 set_socket_timeout(int s, int seconds)
0581 {
0582 struct timeval tv;
0583 int len = sizeof(tv);
0584
0585 if(seconds < 0)
0586 seconds = 0;
0587 tv.tv_usec = 0;
0588 tv.tv_sec = seconds;
0589 if(0 != setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tv, len))
0590 syslog(LOG_ERR, "ftpd: Can't set send timeout on socket: %s.", serr());
0591 else if(0 != setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, len))
0592 syslog(LOG_ERR, "ftpd: Can't set receive timeout on socket: %s.", serr());
0593 }
0594
0595
0596
0597
0598
0599
0600
0601
0602
0603
0604
0605
0606 static int
0607 close_socket(int s)
0608 {
0609 if (0 <= s)
0610 {
0611 if (0 != close(s))
0612 {
0613 shutdown(s, 2);
0614 if (0 != close(s))
0615 return 0;
0616 }
0617 }
0618 return 1;
0619 }
0620
0621
0622
0623
0624
0625
0626
0627
0628
0629
0630
0631
0632
0633 static int
0634 data_socket(FTPD_SessionInfo_t *info)
0635 {
0636 int s = info->pasv_socket;
0637 if(0 > s)
0638 {
0639 int on = 1;
0640 s = socket(PF_INET, SOCK_STREAM, 0);
0641 if(0 > s)
0642 send_reply(info, 425, "Can't create data socket.");
0643 else if(0 > setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
0644 {
0645 close_socket(s);
0646 s = -1;
0647 }
0648 else
0649 {
0650 struct sockaddr_in data_source;
0651 int tries;
0652
0653
0654 data_source = info->ctrl_addr;
0655 data_source.sin_port = htons(20);
0656 for(tries = 1; tries < 10; ++tries)
0657 {
0658 errno = 0;
0659 if(bind(s, (struct sockaddr *)&data_source, sizeof(data_source)) >= 0)
0660 break;
0661 if (errno != EADDRINUSE)
0662 tries = 10;
0663 else
0664 rtems_task_wake_after(tries * 10);
0665 }
0666 if(tries >= 10)
0667 {
0668 send_reply(info, 425, "Can't bind data socket.");
0669 close_socket(s);
0670 s = -1;
0671 }
0672 else
0673 {
0674 struct sockaddr_in *data_dest =
0675 (info->use_default) ? &info->def_addr : &info->data_addr;
0676 if(0 > connect(s, (struct sockaddr *)data_dest, sizeof(*data_dest)))
0677 {
0678 send_reply(info, 425, "Can't connect data socket.");
0679 close_socket(s);
0680 s = -1;
0681 }
0682 }
0683 }
0684 }
0685 info->data_socket = s;
0686 info->use_default = 1;
0687 set_socket_timeout(s, info->idle);
0688 return s;
0689 }
0690
0691
0692
0693
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703 static void
0704 close_data_socket(FTPD_SessionInfo_t *info)
0705 {
0706
0707
0708 int s = info->data_socket;
0709 if(0 > s)
0710 s = info->pasv_socket;
0711 if(!close_socket(s))
0712 syslog(LOG_ERR, "ftpd: Error closing data socket.");
0713 info->data_socket = -1;
0714 info->pasv_socket = -1;
0715 info->use_default = 1;
0716 }
0717
0718
0719
0720
0721
0722
0723
0724
0725
0726
0727
0728
0729
0730 static void
0731 close_stream(FTPD_SessionInfo_t* info)
0732 {
0733 if (NULL != info->ctrl_fp)
0734 {
0735 if (0 != fclose(info->ctrl_fp))
0736 {
0737 syslog(LOG_ERR, "ftpd: Could not close control stream: %s", serr());
0738 }
0739 else
0740 info->ctrl_socket = -1;
0741 }
0742
0743 if (!close_socket(info->ctrl_socket))
0744 syslog(LOG_ERR, "ftpd: Could not close control socket: %s", serr());
0745
0746 info->ctrl_fp = NULL;
0747 info->ctrl_socket = -1;
0748 }
0749
0750
0751
0752
0753
0754
0755
0756
0757
0758
0759
0760
0761
0762
0763 static void
0764 send_mode_reply(FTPD_SessionInfo_t *info)
0765 {
0766 if(info->xfer_mode == TYPE_I)
0767 send_reply(info, 150, "Opening BINARY mode data connection.");
0768 else
0769 send_reply(info, 150, "Opening ASCII mode data connection.");
0770 }
0771
0772
0773
0774
0775
0776
0777
0778
0779
0780
0781
0782
0783
0784
0785 static void
0786 command_retrieve(FTPD_SessionInfo_t *info, char const *filename)
0787 {
0788 int s = -1;
0789 int fd = -1;
0790 char buf[FTPD_DATASIZE];
0791 struct stat stat_buf;
0792 int res = 0;
0793
0794 if(!can_read() || !info->auth)
0795 {
0796 send_reply(info, 550, "Access denied.");
0797 return;
0798 }
0799
0800 if (0 > (fd = open(filename, O_RDONLY)))
0801 {
0802 send_reply(info, 550, "Error opening file.");
0803 return;
0804 }
0805
0806 if (fstat(fd, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode))
0807 {
0808 if (-1 != fd)
0809 close(fd);
0810 send_reply(info, 550, "Is a directory.");
0811 return;
0812 }
0813
0814 send_mode_reply(info);
0815
0816 s = data_socket(info);
0817
0818 if (0 <= s)
0819 {
0820 int n = -1;
0821
0822 if(info->xfer_mode == TYPE_I)
0823 {
0824 while ((n = read(fd, buf, FTPD_DATASIZE)) > 0)
0825 {
0826 if(send(s, buf, n, 0) != n)
0827 break;
0828 yield();
0829 }
0830 }
0831 else if (info->xfer_mode == TYPE_A)
0832 {
0833 int rest = 0;
0834 while (rest == 0 && (n = read(fd, buf, FTPD_DATASIZE)) > 0)
0835 {
0836 char const* e = buf;
0837 char const* b;
0838 int i;
0839 rest = n;
0840 do
0841 {
0842 char lf = '\0';
0843
0844 b = e;
0845 for(i = 0; i < rest; ++i, ++e)
0846 {
0847 if(*e == '\n')
0848 {
0849 lf = '\n';
0850 break;
0851 }
0852 }
0853 if(send(s, b, i, 0) != i)
0854 break;
0855 if(lf == '\n')
0856 {
0857 if(send(s, "\r\n", 2, 0) != 2)
0858 break;
0859 ++e;
0860 ++i;
0861 }
0862 }
0863 while((rest -= i) > 0);
0864 yield();
0865 }
0866 }
0867
0868 if (0 == n)
0869 {
0870 if (0 == close(fd))
0871 {
0872 fd = -1;
0873 res = 1;
0874 }
0875 }
0876 }
0877
0878 if (-1 != fd)
0879 close(fd);
0880
0881 if (0 == res)
0882 send_reply(info, 451, "File read error.");
0883 else
0884 send_reply(info, 226, "Transfer complete.");
0885
0886 close_data_socket(info);
0887
0888 return;
0889 }
0890
0891
0892
0893
0894
0895
0896
0897
0898
0899
0900
0901
0902
0903
0904
0905
0906 static ssize_t
0907 discard(int fd, void const* buf, size_t count)
0908 {
0909 (void)fd;
0910 (void)buf;
0911 return count;
0912 }
0913
0914
0915
0916
0917
0918
0919
0920
0921
0922
0923
0924
0925
0926 static void
0927 command_store(FTPD_SessionInfo_t *info, char const *filename)
0928 {
0929 int s;
0930 int n;
0931 unsigned long size = 0;
0932 struct rtems_ftpd_hook *usehook = NULL;
0933 char buf[FTPD_DATASIZE];
0934 int res = 1;
0935 int bare_lfs = 0;
0936 int null = 0;
0937 typedef ssize_t (*WriteProc)(int, void const*, size_t);
0938 WriteProc wrt = &write;
0939
0940 if(!can_write() || !info->auth)
0941 {
0942 send_reply(info, 550, "Access denied.");
0943 return;
0944 }
0945
0946 send_mode_reply(info);
0947
0948 s = data_socket(info);
0949 if(0 > s)
0950 return;
0951
0952 null = !strcmp("/dev/null", filename);
0953 if (null)
0954 {
0955
0956
0957
0958
0959 wrt = &discard;
0960 }
0961
0962 if (!null && ftpd_config->hooks != NULL)
0963 {
0964
0965
0966 struct rtems_ftpd_hook *hook;
0967 int i;
0968
0969 i = 0;
0970 hook = &ftpd_config->hooks[i++];
0971 while (hook->filename != NULL)
0972 {
0973 if (!strcmp(hook->filename, filename))
0974 {
0975 usehook = hook;
0976 break;
0977 }
0978 hook = &ftpd_config->hooks[i++];
0979 }
0980 }
0981
0982 if (usehook != NULL)
0983 {
0984
0985
0986
0987
0988
0989
0990
0991 char *bigBufr;
0992 size_t filesize = ftpd_config->max_hook_filesize + 1;
0993
0994
0995
0996
0997 bigBufr = (char *)malloc(filesize);
0998 if (bigBufr == NULL)
0999 {
1000 send_reply(info, 451, "Local resource failure: malloc.");
1001 close_data_socket(info);
1002 return;
1003 }
1004
1005
1006
1007
1008 size = 0;
1009 while ((n = recv(s, bigBufr + size, filesize - size, 0)) > 0)
1010 {
1011 size += n;
1012 }
1013 if (size >= filesize)
1014 {
1015 send_reply(info, 451, "File too long: buffer size exceeded.");
1016 free(bigBufr);
1017 close_data_socket(info);
1018 return;
1019 }
1020
1021
1022
1023
1024 res = (usehook->hook_function)(bigBufr, size) == 0;
1025 free(bigBufr);
1026 if(!res)
1027 {
1028 send_reply(info, 451, "File processing failed.");
1029 close_data_socket(info);
1030 return;
1031 }
1032 }
1033 else
1034 {
1035
1036 int fd = 0;
1037
1038 if(!null)
1039 fd = creat(filename,
1040 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
1041
1042 if (0 > fd)
1043 {
1044 send_reply(info, 550, "Error creating file.");
1045 close_data_socket(info);
1046 return;
1047 }
1048
1049 if(info->xfer_mode == TYPE_I)
1050 {
1051 while ((n = recv(s, buf, FTPD_DATASIZE, 0)) > 0)
1052 {
1053 if (wrt(fd, buf, n) != n)
1054 {
1055 res = 0;
1056 break;
1057 }
1058 yield();
1059 }
1060 }
1061 else if(info->xfer_mode == TYPE_A)
1062 {
1063 int rest = 0;
1064 int pended_cr = 0;
1065 while (res && rest == 0 && (n = recv(s, buf, FTPD_DATASIZE, 0)) > 0)
1066 {
1067 char const* e = buf;
1068 char const* b;
1069 int i;
1070
1071 rest = n;
1072 if(pended_cr && *e != '\n')
1073 {
1074 char const lf = '\r';
1075 pended_cr = 0;
1076 if(wrt(fd, &lf, 1) != 1)
1077 {
1078 res = 0;
1079 break;
1080 }
1081 }
1082 do
1083 {
1084 int count;
1085 int sub = 0;
1086
1087 b = e;
1088 for(i = 0; i < rest; ++i, ++e)
1089 {
1090 int pcr = pended_cr;
1091 pended_cr = 0;
1092 if(*e == '\r')
1093 {
1094 pended_cr = 1;
1095 }
1096 else if(*e == '\n')
1097 {
1098 if(pcr)
1099 {
1100 sub = 2;
1101 ++i;
1102 ++e;
1103 break;
1104 }
1105 ++bare_lfs;
1106 }
1107 }
1108 if(res == 0)
1109 break;
1110 count = i - sub - pended_cr;
1111 if(count > 0 && wrt(fd, b, count) != count)
1112 {
1113 res = 0;
1114 break;
1115 }
1116 if(sub == 2 && wrt(fd, e - 1, 1) != 1)
1117 res = 0;
1118 }
1119 while((rest -= i) > 0);
1120 yield();
1121 }
1122 }
1123
1124 if (0 > close(fd) || res == 0)
1125 {
1126 send_reply(info, 452, "Error writing file.");
1127 close_data_socket(info);
1128 return;
1129 }
1130 }
1131
1132 if (bare_lfs > 0)
1133 {
1134 snprintf(buf, FTPD_BUFSIZE,
1135 "Transfer complete. WARNING! %d bare linefeeds received in ASCII mode.",
1136 bare_lfs);
1137 send_reply(info, 226, buf);
1138 }
1139 else
1140 send_reply(info, 226, "Transfer complete.");
1141 close_data_socket(info);
1142
1143 }
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166 static bool
1167 send_dirline(int s, bool wide, time_t curTime, char const* path,
1168 char const* add, char const* fname, char* buf)
1169 {
1170 struct stat stat_buf;
1171 size_t plen = strlen(path);
1172 size_t alen = strlen(add);
1173 int slen = 0;
1174
1175 if(plen == 0)
1176 {
1177 buf[plen++] = '/';
1178 buf[plen] = '\0';
1179 }
1180 else
1181 {
1182 buf = memcpy(buf, path, plen + 1);
1183 if(alen > 0 && buf[plen - 1] != '/')
1184 {
1185 buf[plen++] = '/';
1186 if(plen >= FTPD_BUFSIZE)
1187 return 0;
1188 buf[plen] = '\0';
1189 }
1190 }
1191 if(plen + alen >= FTPD_BUFSIZE)
1192 return 0;
1193 memcpy(buf + plen, add, alen + 1);
1194
1195 if (stat(buf, &stat_buf) == 0)
1196 {
1197 if (wide)
1198 {
1199 struct tm bt;
1200 time_t tf = stat_buf.st_mtime;
1201 enum { SIZE = 80 };
1202 time_t SIX_MONTHS = (365L*24L*60L*60L)/2L;
1203 char timeBuf[SIZE];
1204 gmtime_r(&tf, &bt);
1205 if(curTime > tf + SIX_MONTHS || tf > curTime + SIX_MONTHS)
1206 strftime (timeBuf, SIZE, "%b %d %Y", &bt);
1207 else
1208 strftime (timeBuf, SIZE, "%b %d %H:%M", &bt);
1209
1210 slen = snprintf(buf, FTPD_BUFSIZE,
1211 "%c%c%c%c%c%c%c%c%c%c 1 %5d %5d %11u %s %s\r\n",
1212 (S_ISLNK(stat_buf.st_mode)?('l'):
1213 (S_ISDIR(stat_buf.st_mode)?('d'):('-'))),
1214 (stat_buf.st_mode & S_IRUSR)?('r'):('-'),
1215 (stat_buf.st_mode & S_IWUSR)?('w'):('-'),
1216 (stat_buf.st_mode & S_IXUSR)?('x'):('-'),
1217 (stat_buf.st_mode & S_IRGRP)?('r'):('-'),
1218 (stat_buf.st_mode & S_IWGRP)?('w'):('-'),
1219 (stat_buf.st_mode & S_IXGRP)?('x'):('-'),
1220 (stat_buf.st_mode & S_IROTH)?('r'):('-'),
1221 (stat_buf.st_mode & S_IWOTH)?('w'):('-'),
1222 (stat_buf.st_mode & S_IXOTH)?('x'):('-'),
1223 (int)stat_buf.st_uid,
1224 (int)stat_buf.st_gid,
1225 (int)stat_buf.st_size,
1226 timeBuf,
1227 fname
1228 );
1229 }
1230 else
1231 {
1232 slen = snprintf(buf, FTPD_BUFSIZE, "%s\r\n", fname);
1233 }
1234 }
1235 else
1236 {
1237 slen = snprintf(buf, FTPD_BUFSIZE, "%s: %s.\r\n", fname, strerror(errno));
1238 }
1239
1240 if (slen >= FTPD_BUFSIZE)
1241 {
1242 static const char dots[] = { '.', '.', '.', '\r', '\n' };
1243
1244
1245
1246
1247
1248 slen = FTPD_BUFSIZE - 1;
1249 memcpy(&buf[slen - sizeof(dots)], dots, sizeof(dots));
1250 }
1251
1252 if (slen > 0 && send(s, buf, (size_t) slen, 0) != slen)
1253 return false;
1254
1255 return true;
1256 }
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270 static void
1271 command_list(FTPD_SessionInfo_t *info, char const *fname, bool wide)
1272 {
1273 int s;
1274 DIR *dirp = 0;
1275 struct dirent *dp = 0;
1276 char buf[FTPD_BUFSIZE];
1277 time_t curTime;
1278 bool ok = true;
1279
1280 if(!info->auth)
1281 {
1282 send_reply(info, 550, "Access denied.");
1283 return;
1284 }
1285
1286 send_reply(info, 150, "Opening ASCII mode data connection for LIST.");
1287
1288 s = data_socket(info);
1289 if(0 > s)
1290 {
1291 syslog(LOG_ERR, "ftpd: Error connecting to data socket.");
1292 return;
1293 }
1294
1295 if (fname[0] == '\0')
1296 fname = ".";
1297
1298 time(&curTime);
1299 dirp = opendir(fname);
1300 if (dirp != NULL)
1301 {
1302
1303 ok = ok && send_dirline(s, wide, curTime, fname, "", ".", buf);
1304 ok = ok && send_dirline(s, wide, curTime, fname,
1305 (strcmp(fname, ftpd_root) ? ".." : ""), "..", buf);
1306
1307 while (ok && (dp = readdir(dirp)) != NULL)
1308 ok = ok &&
1309 send_dirline(s, wide, curTime, fname, dp->d_name, dp->d_name, buf);
1310
1311 closedir(dirp);
1312 }
1313 else
1314 {
1315 send_dirline(s, wide, curTime, fname, "", fname, buf);
1316 }
1317
1318 close_data_socket(info);
1319
1320 if (ok)
1321 send_reply(info, 226, "Transfer complete.");
1322 else
1323 send_reply(info, 426, "Connection aborted.");
1324 }
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340 static void
1341 command_cwd(FTPD_SessionInfo_t *info, const char *dir)
1342 {
1343 if(!info->auth)
1344 {
1345 send_reply(info, 550, "Access denied.");
1346 return;
1347 }
1348
1349 if(chdir(dir) == 0)
1350 send_reply(info, 250, "CWD command successful.");
1351 else
1352 send_reply(info, 550, "CWD command failed.");
1353 }
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367 static void
1368 command_pwd(FTPD_SessionInfo_t *info)
1369 {
1370 char buf[FTPD_BUFSIZE];
1371 char const* cwd;
1372 errno = 0;
1373 buf[0] = '"';
1374
1375 if(!info->auth)
1376 {
1377 send_reply(info, 550, "Access denied.");
1378 return;
1379 }
1380
1381 cwd = getcwd(buf + 1, FTPD_BUFSIZE - 4);
1382 if(cwd)
1383 {
1384 int len = strlen(cwd);
1385 static char const txt[] = "\" is the current directory.";
1386 int size = sizeof(txt);
1387 if(len + size + 1 >= FTPD_BUFSIZE)
1388 size = FTPD_BUFSIZE - len - 2;
1389 memcpy(buf + len + 1, txt, size);
1390 buf[len + size] = '\0';
1391 send_reply(info, 250, buf);
1392 }
1393 else {
1394 snprintf(buf, FTPD_BUFSIZE, "Error: %s.", serr());
1395 send_reply(info, 452, buf);
1396 }
1397 }
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411 static void
1412 command_mdtm(FTPD_SessionInfo_t *info, char const* fname)
1413 {
1414 struct stat stbuf;
1415 char buf[FTPD_BUFSIZE];
1416
1417 if(!info->auth)
1418 {
1419 send_reply(info, 550, "Access denied.");
1420 return;
1421 }
1422
1423 if (0 > stat(fname, &stbuf))
1424 {
1425 snprintf(buf, FTPD_BUFSIZE, "%s: %s.", fname, serr());
1426 send_reply(info, 550, buf);
1427 }
1428 else
1429 {
1430 struct tm *t = gmtime(&stbuf.st_mtime);
1431 snprintf(buf, FTPD_BUFSIZE, "%04d%02d%02d%02d%02d%02d",
1432 1900 + t->tm_year,
1433 t->tm_mon+1, t->tm_mday,
1434 t->tm_hour, t->tm_min, t->tm_sec);
1435 send_reply(info, 213, buf);
1436 }
1437 }
1438
1439 static void
1440 command_size(FTPD_SessionInfo_t *info, char const* fname)
1441 {
1442 struct stat stbuf;
1443 char buf[FTPD_BUFSIZE];
1444
1445 if(!info->auth)
1446 {
1447 send_reply(info, 550, "Access denied.");
1448 return;
1449 }
1450
1451 if (info->xfer_mode != TYPE_I || 0 > stat(fname, &stbuf) || stbuf.st_size < 0)
1452 {
1453 send_reply(info, 550, "Could not get file size.");
1454 }
1455 else
1456 {
1457 snprintf(buf, FTPD_BUFSIZE, "%" PRIuMAX, (uintmax_t) stbuf.st_size);
1458 send_reply(info, 213, buf);
1459 }
1460 }
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476 static void
1477 command_port(FTPD_SessionInfo_t *info, char const *args)
1478 {
1479 enum { NUM_FIELDS = 6 };
1480 unsigned int a[NUM_FIELDS];
1481 int n;
1482
1483 close_data_socket(info);
1484
1485 n = sscanf(args, "%u,%u,%u,%u,%u,%u", a+0, a+1, a+2, a+3, a+4, a+5);
1486 if(NUM_FIELDS == n)
1487 {
1488 int i;
1489 union {
1490 uint8_t b[NUM_FIELDS];
1491 struct {
1492 uint32_t ip;
1493 uint16_t port;
1494 } u ;
1495 } ip_info;
1496
1497 for(i = 0; i < NUM_FIELDS; ++i)
1498 {
1499 if(a[i] > 255)
1500 break;
1501 ip_info.b[i] = (uint8_t)a[i];
1502 }
1503
1504 if(i == NUM_FIELDS)
1505 {
1506
1507
1508
1509 if (ip_info.u.ip == info->def_addr.sin_addr.s_addr)
1510 {
1511 info->data_addr.sin_addr.s_addr = ip_info.u.ip;
1512 info->data_addr.sin_port = ip_info.u.port;
1513 info->data_addr.sin_family = AF_INET;
1514 memset(info->data_addr.sin_zero, 0, sizeof(info->data_addr.sin_zero));
1515
1516 info->use_default = 0;
1517 send_reply(info, 200, "PORT command successful.");
1518 return;
1519 }
1520 else
1521 {
1522 send_reply(info, 425, "Address doesn't match peer's IP.");
1523 return;
1524 }
1525 }
1526 }
1527 send_reply(info, 501, "Syntax error.");
1528 }
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543 static void
1544 command_pasv(FTPD_SessionInfo_t *info)
1545 {
1546 int s = -1;
1547 int err = 1;
1548
1549 close_data_socket(info);
1550
1551 s = socket(PF_INET, SOCK_STREAM, 0);
1552 if (s < 0)
1553 syslog(LOG_ERR, "ftpd: Error creating PASV socket: %s", serr());
1554 else
1555 {
1556 struct sockaddr_in addr;
1557 socklen_t addrLen = sizeof(addr);
1558
1559 addr = info->ctrl_addr;
1560 addr.sin_port = htons(0);
1561
1562 if (0 > bind(s, (struct sockaddr *)&addr, addrLen))
1563 syslog(LOG_ERR, "ftpd: Error binding PASV socket: %s", serr());
1564 else if (0 > listen(s, 1))
1565 syslog(LOG_ERR, "ftpd: Error listening on PASV socket: %s", serr());
1566 {
1567 set_socket_timeout(s, info->idle);
1568 if (0 == getsockname(s, (struct sockaddr *)&addr, &addrLen))
1569 {
1570 char buf[FTPD_BUFSIZE];
1571 unsigned char const *ip, *p;
1572
1573 ip = (unsigned char const*)&(addr.sin_addr);
1574 p = (unsigned char const*)&(addr.sin_port);
1575 snprintf(buf, FTPD_BUFSIZE, "Entering passive mode (%u,%u,%u,%u,%u,%u).",
1576 ip[0], ip[1], ip[2], ip[3], p[0], p[1]);
1577 send_reply(info, 227, buf);
1578
1579 info->pasv_socket = accept(s, (struct sockaddr *)&addr, &addrLen);
1580 if (0 > info->pasv_socket)
1581 syslog(LOG_ERR, "ftpd: Error accepting PASV connection: %s", serr());
1582 else
1583 {
1584 close_socket(s);
1585 s = -1;
1586 err = 0;
1587 }
1588 }
1589 else
1590 syslog(LOG_ERR, "ftpd: Cannot get socket name: %s", serr());
1591 }
1592 }
1593 if(err)
1594 {
1595
1596
1597
1598
1599
1600 send_reply(info, 425, "Can't open passive connection.");
1601 close_socket(s);
1602 }
1603 }
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617 static void
1618 skip_options(char **p)
1619 {
1620 char* buf = *p;
1621 char* last = NULL;
1622 while(1) {
1623 while(isspace((unsigned char)*buf))
1624 ++buf;
1625 if(*buf == '-') {
1626 if(*++buf == '-') {
1627 if(isspace((unsigned char)*++buf)) {
1628 last = buf;
1629 do ++buf;
1630 while(isspace((unsigned char)*buf));
1631 break;
1632 }
1633 }
1634 while(*buf && !isspace((unsigned char)*buf))
1635 ++buf;
1636 last = buf;
1637 }
1638 else
1639 break;
1640 }
1641 if(last)
1642 *last = '\0';
1643 *p = buf;
1644 }
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661 static void
1662 split_command(char *buf, char **cmd, char **opts, char **args)
1663 {
1664 char* eoc;
1665 char* p = buf;
1666 while(isspace((unsigned char)*p))
1667 ++p;
1668 *cmd = p;
1669 while(*p && !isspace((unsigned char)*p))
1670 {
1671 *p = toupper((unsigned char)*p);
1672 ++p;
1673 }
1674 eoc = p;
1675 if(*p)
1676 *p++ = '\0';
1677 while(isspace((unsigned char)*p))
1678 ++p;
1679 *opts = p;
1680 skip_options(&p);
1681 *args = p;
1682 if(*opts == p)
1683 *opts = eoc;
1684 while(*p && *p != '\r' && *p != '\n')
1685 ++p;
1686 if(*p)
1687 *p++ = '\0';
1688 }
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706 static void
1707 exec_command(FTPD_SessionInfo_t *info, char *cmd, char *args)
1708 {
1709 int wrong_command = 0;
1710
1711 if (!strcmp("PORT", cmd))
1712 {
1713 command_port(info, args);
1714 }
1715 else if (!strcmp("PASV", cmd))
1716 {
1717 command_pasv(info);
1718 }
1719 else if (!strcmp("RETR", cmd))
1720 {
1721 command_retrieve(info, args);
1722 }
1723 else if (!strcmp("STOR", cmd))
1724 {
1725 command_store(info, args);
1726 }
1727 else if (!strcmp("LIST", cmd))
1728 {
1729 command_list(info, args, true);
1730 }
1731 else if (!strcmp("NLST", cmd))
1732 {
1733 command_list(info, args, false);
1734 }
1735 else if (!strcmp("MDTM", cmd))
1736 {
1737 command_mdtm(info, args);
1738 }
1739 else if (!strcmp("SIZE", cmd))
1740 {
1741 command_size(info, args);
1742 }
1743 else if (!strcmp("SYST", cmd))
1744 {
1745 send_reply(info, 215, FTPD_SYSTYPE);
1746 }
1747 else if (!strcmp("TYPE", cmd))
1748 {
1749 if (args[0] == 'I')
1750 {
1751 info->xfer_mode = TYPE_I;
1752 send_reply(info, 200, "Type set to I.");
1753 }
1754 else if (args[0] == 'A')
1755 {
1756 info->xfer_mode = TYPE_A;
1757 send_reply(info, 200, "Type set to A.");
1758 }
1759 else
1760 {
1761 info->xfer_mode = TYPE_I;
1762 send_reply(info, 504, "Type not implemented. Set to I.");
1763 }
1764 }
1765 else if (!strcmp("USER", cmd))
1766 {
1767 strlcpy(info->user_buf, args, sizeof(info->user_buf));
1768 info->user = info->user_buf;
1769 if (ftpd_config->login &&
1770 !ftpd_config->login(info->user, NULL)) {
1771 info->auth = false;
1772 send_reply(info, 331, "User name okay, need password.");
1773 } else {
1774 info->auth = true;
1775 send_reply(info, 230, "User logged in.");
1776 }
1777 }
1778 else if (!strcmp("PASS", cmd))
1779 {
1780 if (!info->user) {
1781 send_reply(info, 332, "Need account to log in");
1782 } else {
1783 if (ftpd_config->login &&
1784 !ftpd_config->login(info->user, args)) {
1785 info->auth = false;
1786 send_reply(info, 530, "Not logged in.");
1787 } else {
1788 info->auth = true;
1789 send_reply(info, 230, "User logged in.");
1790 }
1791 }
1792 }
1793 else if (!strcmp("DELE", cmd))
1794 {
1795 if(!can_write() || !info->auth)
1796 {
1797 send_reply(info, 550, "Access denied.");
1798 }
1799 else if (unlink(args) == 0)
1800 {
1801 send_reply(info, 257, "DELE successful.");
1802 }
1803 else
1804 {
1805 send_reply(info, 550, "DELE failed.");
1806 }
1807 }
1808 else if (!strcmp("SITE", cmd))
1809 {
1810 char* opts;
1811 split_command(args, &cmd, &opts, &args);
1812 if(!strcmp("CHMOD", cmd))
1813 {
1814 int mask;
1815
1816 if(!can_write() || !info->auth)
1817 {
1818 send_reply(info, 550, "Access denied.");
1819 }
1820 else {
1821 char *c;
1822 c = strchr(args, ' ');
1823 if((c != NULL) && (sscanf(args, "%o", &mask) == 1)
1824 && (chmod(c + 1, (mode_t)mask) == 0))
1825 send_reply(info, 257, "CHMOD successful.");
1826 else
1827 send_reply(info, 550, "CHMOD failed.");
1828 }
1829 }
1830 else
1831 wrong_command = 1;
1832 }
1833 else if (!strcmp("RMD", cmd))
1834 {
1835 if(!can_write() || !info->auth)
1836 {
1837 send_reply(info, 550, "Access denied.");
1838 }
1839 else if (rmdir(args) == 0)
1840 {
1841 send_reply(info, 257, "RMD successful.");
1842 }
1843 else
1844 {
1845 send_reply(info, 550, "RMD failed.");
1846 }
1847 }
1848 else if (!strcmp("MKD", cmd))
1849 {
1850 if(!can_write() || !info->auth)
1851 {
1852 send_reply(info, 550, "Access denied.");
1853 }
1854 else if (mkdir(args, S_IRWXU | S_IRWXG | S_IRWXO) == 0)
1855 {
1856 send_reply(info, 257, "MKD successful.");
1857 }
1858 else
1859 {
1860 send_reply(info, 550, "MKD failed.");
1861 }
1862 }
1863 else if (!strcmp("CWD", cmd))
1864 {
1865 command_cwd(info, args);
1866 }
1867 else if (!strcmp("CDUP", cmd))
1868 {
1869 command_cwd(info, "..");
1870 }
1871 else if (!strcmp("PWD", cmd))
1872 {
1873 command_pwd(info);
1874 }
1875 else
1876 wrong_command = 1;
1877
1878 if(wrong_command)
1879 send_reply(info, 500, "Command not understood.");
1880 }
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898 static void
1899 session(rtems_task_argument arg)
1900 {
1901 FTPD_SessionInfo_t *const info = (FTPD_SessionInfo_t *)arg;
1902 bool chroot_made = false;
1903
1904 while (1)
1905 {
1906 rtems_event_set set;
1907
1908 rtems_event_receive(FTPD_RTEMS_EVENT, RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT,
1909 &set);
1910
1911 chroot_made = chroot_made
1912 || (rtems_libio_set_private_env() == RTEMS_SUCCESSFUL
1913 && chroot(ftpd_root) == 0);
1914
1915
1916
1917
1918
1919
1920 if (chroot_made && chdir("/") == 0)
1921 {
1922 send_reply(info, 220, FTPD_SERVER_MESSAGE);
1923
1924 while (1)
1925 {
1926 char buf[FTPD_BUFSIZE];
1927 char *cmd, *opts, *args;
1928 size_t len;
1929
1930 if (fgets(buf, FTPD_BUFSIZE, info->ctrl_fp) == NULL)
1931 {
1932 syslog(LOG_INFO, "ftpd: Connection aborted.");
1933 break;
1934 }
1935
1936 len = strlen(buf);
1937
1938 if (len == 0)
1939 continue;
1940
1941 if (buf[len - 1] != '\n')
1942 {
1943 send_reply(info, 501, "Command line too long.");
1944
1945
1946
1947
1948
1949
1950
1951
1952 break;
1953 }
1954
1955 split_command(buf, &cmd, &opts, &args);
1956
1957 if (!strcmp("QUIT", cmd))
1958 {
1959 send_reply(info, 221, "Goodbye.");
1960 break;
1961 }
1962 else
1963 {
1964 exec_command(info, cmd, args);
1965 }
1966 }
1967 }
1968 else
1969 {
1970 send_reply(info, 421, "Service not available, closing control connection.");
1971 }
1972
1973
1974
1975
1976
1977
1978
1979 chdir("/");
1980
1981
1982 close_data_socket(info);
1983 close_stream(info);
1984 task_pool_release(info);
1985 }
1986 }
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002 static void
2003 ftpd_daemon(rtems_task_argument args RTEMS_UNUSED)
2004 {
2005 int s;
2006 socklen_t addrLen;
2007 struct sockaddr_in addr;
2008
2009 memset(&addr, 0, sizeof(addr));
2010 addr.sin_family = AF_INET;
2011 addr.sin_port = htons(ftpd_config->port);
2012 addr.sin_addr.s_addr = htonl(INADDR_ANY);
2013
2014 s = socket(PF_INET, SOCK_STREAM, 0);
2015 if (s < 0)
2016 syslog(LOG_ERR, "ftpd: Error creating control socket: %s", serr());
2017 else if (0 > bind(s, (struct sockaddr *)&addr, sizeof(addr)))
2018 syslog(LOG_ERR, "ftpd: Error binding control socket: %s", serr());
2019 else if (0 > listen(s, 1))
2020 syslog(LOG_ERR, "ftpd: Error listening on control socket: %s", serr());
2021 else while (1)
2022 {
2023 int ss;
2024 addrLen = sizeof(addr);
2025 ss = accept(s, (struct sockaddr *)&addr, &addrLen);
2026 if (0 > ss)
2027 syslog(LOG_ERR, "ftpd: Error accepting control connection: %s", serr());
2028 else
2029 {
2030 FTPD_SessionInfo_t *info;
2031
2032 set_socket_timeout(ss, ftpd_timeout);
2033 info = task_pool_obtain();
2034 if (NULL == info)
2035 {
2036 close_socket(ss);
2037 }
2038 else
2039 {
2040 info->ctrl_socket = ss;
2041 if ((info->ctrl_fp = fdopen(info->ctrl_socket, "r+")) == NULL)
2042 {
2043 syslog(LOG_ERR, "ftpd: fdopen() on socket failed: %s", serr());
2044 close_stream(info);
2045 task_pool_release(info);
2046 }
2047 else
2048 {
2049
2050 info->def_addr = addr;
2051 if(0 > getsockname(ss, (struct sockaddr *)&addr, &addrLen))
2052 {
2053 syslog(LOG_ERR, "ftpd: getsockname(): %s", serr());
2054 close_stream(info);
2055 task_pool_release(info);
2056 }
2057 else
2058 {
2059 info->use_default = 1;
2060 info->ctrl_addr = addr;
2061 info->pasv_socket = -1;
2062 info->data_socket = -1;
2063 info->xfer_mode = TYPE_A;
2064 info->data_addr.sin_port =
2065 htons(ntohs(info->ctrl_addr.sin_port) - 1);
2066 info->idle = ftpd_timeout;
2067 info->user = NULL;
2068 if (ftpd_config->login)
2069 info->auth = false;
2070 else
2071 info->auth = true;
2072
2073
2074 rtems_event_send(info->tid, FTPD_RTEMS_EVENT);
2075 }
2076 }
2077 }
2078 }
2079 }
2080
2081 close(s);
2082 rtems_task_exit();
2083 }
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098 rtems_status_code
2099 rtems_ftpd_start(const struct rtems_ftpd_configuration* config)
2100 {
2101 rtems_status_code sc;
2102 rtems_id tid;
2103 rtems_task_priority priority;
2104 int count;
2105
2106 if (ftpd_config != NULL)
2107 return RTEMS_RESOURCE_IN_USE;
2108
2109 ftpd_config = malloc(sizeof(*ftpd_config));
2110 if (ftpd_config == NULL)
2111 return RTEMS_NO_MEMORY;
2112
2113 *ftpd_config = *config;
2114
2115 if (ftpd_config->port == 0)
2116 {
2117 ftpd_config->port = FTPD_CONTROL_PORT;
2118 }
2119
2120 if (ftpd_config->priority == 0)
2121 {
2122 ftpd_config->priority = 40;
2123 }
2124 priority = ftpd_config->priority;
2125
2126 ftpd_timeout = ftpd_config->idle;
2127 if (ftpd_timeout < 0)
2128 ftpd_timeout = 0;
2129 ftpd_config->idle = ftpd_timeout;
2130
2131 ftpd_access = ftpd_config->access;
2132
2133 ftpd_root = "/";
2134 if (ftpd_config->root && ftpd_config->root[0] == '/' )
2135 ftpd_root = ftpd_config->root;
2136
2137 ftpd_config->root = ftpd_root;
2138
2139 if (ftpd_config->tasks_count <= 0)
2140 ftpd_config->tasks_count = 1;
2141 count = ftpd_config->tasks_count;
2142
2143 if (!task_pool_init(count, priority))
2144 {
2145 syslog(LOG_ERR, "ftpd: Could not initialize task pool.");
2146 return RTEMS_UNSATISFIED;
2147 }
2148
2149 sc = rtems_task_create(rtems_build_name('F', 'T', 'P', 'D'),
2150 priority, RTEMS_MINIMUM_STACK_SIZE,
2151 RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR |
2152 RTEMS_INTERRUPT_LEVEL(0),
2153 RTEMS_FLOATING_POINT | RTEMS_LOCAL,
2154 &tid);
2155
2156 if (sc == RTEMS_SUCCESSFUL)
2157 {
2158 sc = rtems_task_start(tid, ftpd_daemon, 0);
2159 if (sc != RTEMS_SUCCESSFUL)
2160 rtems_task_delete(tid);
2161 }
2162
2163 if (sc != RTEMS_SUCCESSFUL)
2164 {
2165 task_pool_done(count);
2166 syslog(LOG_ERR, "ftpd: Could not create/start FTP daemon: %s",
2167 rtems_status_text(sc));
2168 return RTEMS_UNSATISFIED;
2169 }
2170
2171 if (ftpd_config->verbose)
2172 syslog(LOG_INFO, "ftpd: FTP daemon started (%d session%s max)",
2173 count, ((count > 1) ? "s" : ""));
2174
2175 return RTEMS_SUCCESSFUL;
2176 }