Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:28

0001 /*
0002  * Copyright (C) 2012, 2020 embedded brains GmbH & Co. KG
0003  *
0004  * Redistribution and use in source and binary forms, with or without
0005  * modification, are permitted provided that the following conditions
0006  * are met:
0007  * 1. Redistributions of source code must retain the above copyright
0008  *    notice, this list of conditions and the following disclaimer.
0009  * 2. Redistributions in binary form must reproduce the above copyright
0010  *    notice, this list of conditions and the following disclaimer in the
0011  *    documentation and/or other materials provided with the distribution.
0012  *
0013  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0014  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0015  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0016  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0017  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0018  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0019  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0020  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0021  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0022  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0023  * POSSIBILITY OF SUCH DAMAGE.
0024  */
0025 
0026 #ifdef HAVE_CONFIG_H
0027 #include "config.h"
0028 #endif
0029 
0030 #include <sys/stat.h>
0031 #include <sys/ioctl.h>
0032 #include <sys/uio.h>
0033 #include <fcntl.h>
0034 #include <unistd.h>
0035 #include <errno.h>
0036 
0037 #include <rtems/imfs.h>
0038 #include <rtems/malloc.h>
0039 #include <rtems/libcsupport.h>
0040 
0041 #include <tmacros.h>
0042 
0043 const char rtems_test_name[] = "FSCLOSE 1";
0044 
0045 typedef enum {
0046   ACTION_CLOSE,
0047   ACTION_FCNTL,
0048   ACTION_FDATASYNC,
0049   ACTION_FCHDIR,
0050   ACTION_FCHMOD,
0051   ACTION_FCHOWN,
0052   /* ACTION_FPATHCONF, not easy to test */
0053   ACTION_FSTAT,
0054   ACTION_FSYNC,
0055   ACTION_FTRUNCATE,
0056   ACTION_IOCTL,
0057   ACTION_LSEEK,
0058   ACTION_READ,
0059   ACTION_READV,
0060   ACTION_WRITE,
0061   ACTION_WRITEV
0062 } test_action;
0063 
0064 typedef struct {
0065   rtems_id worker_id;
0066   int fd;
0067   test_action action;
0068   bool wait_in_close;
0069   bool wait_in_fstat;
0070   int close_count;
0071   int fcntl_count;
0072   int fdatasync_count;
0073   int fstat_count;
0074   int fsync_count;
0075   int ftruncate_count;
0076   int ioctl_count;
0077   int lseek_count;
0078   int open_count;
0079   int read_count;
0080   int readv_count;
0081   int write_count;
0082   int writev_count;
0083 } test_context;
0084 
0085 static test_context test_instance;
0086 
0087 static void wait(void)
0088 {
0089   rtems_status_code sc;
0090 
0091   sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0092   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0093 }
0094 
0095 static void wakeup_worker(const test_context *ctx)
0096 {
0097   rtems_status_code sc;
0098 
0099   sc = rtems_event_transient_send(ctx->worker_id);
0100   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0101 }
0102 
0103 static int handler_open(
0104   rtems_libio_t *iop,
0105   const char *path,
0106   int oflag,
0107   mode_t mode
0108 )
0109 {
0110   test_context *ctx;
0111 
0112   ctx = IMFS_generic_get_context_by_iop(iop);
0113   ++ctx->open_count;
0114 
0115   return 0;
0116 }
0117 
0118 static int handler_close(
0119   rtems_libio_t *iop
0120 )
0121 {
0122   test_context *ctx;
0123 
0124   ctx = IMFS_generic_get_context_by_iop(iop);
0125   ++ctx->close_count;
0126 
0127   if (ctx->wait_in_close) {
0128     ctx->wait_in_close = false;
0129     wait();
0130   }
0131 
0132   return 0;
0133 }
0134 
0135 static ssize_t handler_read(
0136   rtems_libio_t *iop,
0137   void *buffer,
0138   size_t count
0139 )
0140 {
0141   test_context *ctx;
0142 
0143   ctx = IMFS_generic_get_context_by_iop(iop);
0144   ++ctx->read_count;
0145 
0146   wait();
0147   return 0;
0148 }
0149 
0150 static ssize_t handler_write(
0151   rtems_libio_t *iop,
0152   const void *buffer,
0153   size_t count
0154 )
0155 {
0156   test_context *ctx;
0157 
0158   ctx = IMFS_generic_get_context_by_iop(iop);
0159   ++ctx->write_count;
0160 
0161   wait();
0162   return 0;
0163 }
0164 
0165 static int handler_ioctl(
0166   rtems_libio_t *iop,
0167   ioctl_command_t request,
0168   void *buffer
0169 )
0170 {
0171   test_context *ctx;
0172 
0173   ctx = IMFS_generic_get_context_by_iop(iop);
0174   ++ctx->ioctl_count;
0175 
0176   wait();
0177   return 0;
0178 }
0179 
0180 static off_t handler_lseek(
0181   rtems_libio_t *iop,
0182   off_t length,
0183   int whence
0184 )
0185 {
0186   test_context *ctx;
0187 
0188   ctx = IMFS_generic_get_context_by_iop(iop);
0189   ++ctx->lseek_count;
0190 
0191   wait();
0192   return 0;
0193 }
0194 
0195 static int handler_fstat(
0196   const rtems_filesystem_location_info_t *loc,
0197   struct stat *buf
0198 )
0199 {
0200   test_context *ctx;
0201 
0202   buf->st_mode = S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO;
0203   ctx = IMFS_generic_get_context_by_location(loc);
0204   ++ctx->fstat_count;
0205 
0206   if (ctx->wait_in_fstat) {
0207     ctx->wait_in_fstat = false;
0208     wait();
0209   }
0210 
0211   return 0;
0212 }
0213 
0214 static int handler_ftruncate(
0215   rtems_libio_t *iop,
0216   off_t length
0217 )
0218 {
0219   test_context *ctx;
0220 
0221   ctx = IMFS_generic_get_context_by_iop(iop);
0222   ++ctx->ftruncate_count;
0223 
0224   wait();
0225   return 0;
0226 }
0227 
0228 static int handler_fsync(
0229   rtems_libio_t *iop
0230 )
0231 {
0232   test_context *ctx;
0233 
0234   ctx = IMFS_generic_get_context_by_iop(iop);
0235   ++ctx->fsync_count;
0236 
0237   wait();
0238   return 0;
0239 }
0240 
0241 static int handler_fdatasync(
0242   rtems_libio_t *iop
0243 )
0244 {
0245   test_context *ctx;
0246 
0247   ctx = IMFS_generic_get_context_by_iop(iop);
0248   ++ctx->fdatasync_count;
0249 
0250   wait();
0251   return 0;
0252 }
0253 
0254 static int handler_fcntl(
0255   rtems_libio_t *iop,
0256   int cmd
0257 )
0258 {
0259   test_context *ctx;
0260 
0261   ctx = IMFS_generic_get_context_by_iop(iop);
0262   ++ctx->fcntl_count;
0263 
0264   wait();
0265   return 0;
0266 }
0267 
0268 static ssize_t handler_readv(
0269   rtems_libio_t *iop,
0270   const struct iovec *iov,
0271   int iovcnt,
0272   ssize_t total
0273 )
0274 {
0275   test_context *ctx;
0276 
0277   ctx = IMFS_generic_get_context_by_iop(iop);
0278   ++ctx->readv_count;
0279 
0280   wait();
0281   return 0;
0282 }
0283 
0284 static ssize_t handler_writev(
0285   rtems_libio_t *iop,
0286   const struct iovec *iov,
0287   int iovcnt,
0288   ssize_t total
0289 )
0290 {
0291   test_context *ctx;
0292 
0293   ctx = IMFS_generic_get_context_by_iop(iop);
0294   ++ctx->writev_count;
0295 
0296   wait();
0297   return 0;
0298 }
0299 
0300 static const rtems_filesystem_file_handlers_r node_handlers = {
0301   .open_h = handler_open,
0302   .close_h = handler_close,
0303   .read_h = handler_read,
0304   .write_h = handler_write,
0305   .ioctl_h = handler_ioctl,
0306   .lseek_h = handler_lseek,
0307   .fstat_h = handler_fstat,
0308   .ftruncate_h = handler_ftruncate,
0309   .fsync_h = handler_fsync,
0310   .fdatasync_h = handler_fdatasync,
0311   .fcntl_h = handler_fcntl,
0312   .readv_h = handler_readv,
0313   .writev_h = handler_writev
0314 };
0315 
0316 static const IMFS_node_control node_control = {
0317   .handlers = &node_handlers,
0318   .node_initialize = IMFS_node_initialize_generic,
0319   .node_remove = IMFS_node_remove_default,
0320   .node_destroy = IMFS_node_destroy_default
0321 };
0322 
0323 static void worker_task(rtems_task_argument arg)
0324 {
0325   test_context *ctx;
0326   int rv;
0327   char buf[1];
0328   ssize_t n;
0329   off_t off;
0330   struct iovec iov = {
0331     .iov_base = &buf[0],
0332     .iov_len = sizeof(buf)
0333   };
0334   struct stat st;
0335 
0336   ctx = (test_context *) arg;
0337 
0338   while (true) {
0339     wait();
0340 
0341     switch (ctx->action) {
0342       case ACTION_CLOSE:
0343         ctx->wait_in_close = true;
0344         rv = close(ctx->fd);
0345         rtems_test_assert(rv == 0);
0346         break;
0347       case ACTION_FCNTL:
0348         rv = fcntl(ctx->fd, F_GETFD);
0349         rtems_test_assert(rv >= 0);
0350         break;
0351       case ACTION_FDATASYNC:
0352         rv = fdatasync(ctx->fd);
0353         rtems_test_assert(rv == 0);
0354         break;
0355       case ACTION_FCHDIR:
0356         ctx->wait_in_fstat = true;
0357         rv = fchdir(ctx->fd);
0358         rtems_test_assert(rv == -1);
0359         rtems_test_assert(errno == ENOTDIR);
0360         break;
0361       case ACTION_FCHMOD:
0362         rv = fstat(ctx->fd, &st);
0363         rtems_test_assert(rv == 0);
0364         ctx->wait_in_fstat = true;
0365         rv = fchmod(ctx->fd, st.st_mode);
0366         rtems_test_assert(rv == 0);
0367         break;
0368       case ACTION_FCHOWN:
0369         rv = fstat(ctx->fd, &st);
0370         rtems_test_assert(rv == 0);
0371         ctx->wait_in_fstat = true;
0372         rv = fchown(ctx->fd, st.st_uid, st.st_gid);
0373         rtems_test_assert(rv == 0);
0374         break;
0375       case ACTION_FSTAT:
0376         ctx->wait_in_fstat = true;
0377         rv = fstat(ctx->fd, &st);
0378         rtems_test_assert(rv == 0);
0379         break;
0380       case ACTION_FSYNC:
0381         rv = fsync(ctx->fd);
0382         rtems_test_assert(rv == 0);
0383         break;
0384       case ACTION_FTRUNCATE:
0385         rv = ftruncate(ctx->fd, 0);
0386         rtems_test_assert(rv == 0);
0387         break;
0388       case ACTION_IOCTL:
0389         rv = ioctl(ctx->fd, 0);
0390         rtems_test_assert(rv == 0);
0391         break;
0392       case ACTION_LSEEK:
0393         off = lseek(ctx->fd, 0, SEEK_SET);
0394         rtems_test_assert(off == 0);
0395         break;
0396       case ACTION_READ:
0397         n = read(ctx->fd, buf, sizeof(buf));
0398         rtems_test_assert(n == 0);
0399         break;
0400       case ACTION_READV:
0401         n = readv(ctx->fd, &iov, 1);
0402         rtems_test_assert(n == 0);
0403         break;
0404       case ACTION_WRITE:
0405         n = write(ctx->fd, buf, sizeof(buf));
0406         rtems_test_assert(n == 0);
0407         break;
0408       case ACTION_WRITEV:
0409         n = writev(ctx->fd, &iov, 1);
0410         rtems_test_assert(n == 0);
0411         break;
0412       default:
0413         rtems_test_assert(0);
0414         break;
0415     }
0416   }
0417 }
0418 
0419 static void test_fd_free_fifo(const char *path)
0420 {
0421   int a;
0422   int b;
0423   int rv;
0424 
0425   a = open(path, O_RDWR);
0426   rtems_test_assert(a >= 0);
0427 
0428   rv = close(a);
0429   rtems_test_assert(rv == 0);
0430 
0431   b = open(path, O_RDWR);
0432   rtems_test_assert(b >= 0);
0433 
0434   rv = close(b);
0435   rtems_test_assert(rv == 0);
0436 
0437   rtems_test_assert(a != b);
0438 }
0439 
0440 static void test_close(test_context *ctx)
0441 {
0442   const char *path = "generic";
0443   int rv;
0444   rtems_status_code sc;
0445   test_action ac;
0446 
0447   rv = IMFS_make_generic_node(
0448     path,
0449     S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
0450     &node_control,
0451     ctx
0452   );
0453   rtems_test_assert(rv == 0);
0454 
0455   test_fd_free_fifo(path);
0456 
0457   sc = rtems_task_create(
0458     rtems_build_name('W', 'O', 'R', 'K'),
0459     1,
0460     RTEMS_MINIMUM_STACK_SIZE,
0461     RTEMS_DEFAULT_MODES,
0462     RTEMS_DEFAULT_ATTRIBUTES,
0463     &ctx->worker_id
0464   );
0465   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0466 
0467   sc = rtems_task_start(
0468     ctx->worker_id,
0469     worker_task,
0470     (rtems_task_argument) ctx
0471   );
0472   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0473 
0474   for (ac = ACTION_CLOSE; ac <= ACTION_WRITEV; ++ac) {
0475     rtems_libio_t *iop;
0476     unsigned int flags;
0477     unsigned int expected_flags;
0478 
0479     ctx->action = ac;
0480     ctx->fd = open(path, O_RDWR);
0481     rtems_test_assert(ctx->fd >= 0);
0482     iop = rtems_libio_iop(ctx->fd);
0483 
0484     wakeup_worker(ctx);
0485     rv = close(ctx->fd);
0486     rtems_test_assert(rv == -1);
0487 
0488     if (ac == ACTION_CLOSE) {
0489       rtems_test_assert(errno == EBADF);
0490 
0491       flags = rtems_libio_iop_hold(iop);
0492       expected_flags = LIBIO_FLAGS_READ_WRITE;
0493       rtems_test_assert(flags == expected_flags);
0494       flags = rtems_libio_iop_flags(iop);
0495       expected_flags = LIBIO_FLAGS_REFERENCE_INC | LIBIO_FLAGS_READ_WRITE;
0496       rtems_test_assert(flags == expected_flags);
0497     } else {
0498       rtems_test_assert(errno == EBUSY);
0499     }
0500 
0501     wakeup_worker(ctx);
0502 
0503     if (ac == ACTION_CLOSE) {
0504       flags = rtems_libio_iop_flags(iop);
0505       expected_flags = LIBIO_FLAGS_REFERENCE_INC;
0506       rtems_test_assert(flags == expected_flags);
0507       rtems_libio_iop_drop(iop);
0508       flags = rtems_libio_iop_flags(iop);
0509       expected_flags = 0;
0510       rtems_test_assert(flags == expected_flags);
0511     }
0512 
0513     rv = close(ctx->fd);
0514 
0515     if (ac == ACTION_CLOSE) {
0516       rtems_test_assert(rv == -1);
0517       rtems_test_assert(errno == EBADF);
0518     } else {
0519       rtems_test_assert(rv == 0);
0520     }
0521   }
0522 
0523   sc = rtems_task_delete(ctx->worker_id);
0524   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0525 
0526   rv = unlink(path);
0527   rtems_test_assert(rv == 0);
0528 
0529   rtems_test_assert(ctx->close_count == 17);
0530   rtems_test_assert(ctx->fcntl_count == 1);
0531   rtems_test_assert(ctx->fdatasync_count == 1);
0532   rtems_test_assert(ctx->fstat_count == 42);
0533   rtems_test_assert(ctx->fsync_count == 1);
0534   rtems_test_assert(ctx->ftruncate_count == 1);
0535   rtems_test_assert(ctx->ioctl_count == 1);
0536   rtems_test_assert(ctx->lseek_count == 1);
0537   rtems_test_assert(ctx->open_count == 17);
0538   rtems_test_assert(ctx->read_count == 1);
0539   rtems_test_assert(ctx->readv_count == 1);
0540   rtems_test_assert(ctx->write_count == 1);
0541   rtems_test_assert(ctx->writev_count == 1);
0542 }
0543 
0544 static void test_tmpfile(test_context *ctx)
0545 {
0546   rtems_resource_snapshot before;
0547   FILE *f;
0548   int rv;
0549 
0550   rv = mkdir("/tmp", S_IRWXU | S_IRWXG | S_IRWXO);
0551   rtems_test_assert(rv == 0);
0552 
0553   f = tmpfile();
0554   rtems_test_assert(f != NULL);
0555   rv = fclose(f);
0556   rtems_test_assert(rv == 0);
0557 
0558   rtems_resource_snapshot_take(&before);
0559   f = tmpfile();
0560   rtems_test_assert(f != NULL);
0561   rv = fclose(f);
0562   rtems_test_assert(rv == 0);
0563   rtems_test_assert(rtems_resource_snapshot_check(&before));
0564 }
0565 
0566 static void Init(rtems_task_argument arg)
0567 {
0568   TEST_BEGIN();
0569   test_close(&test_instance);
0570   test_tmpfile(&test_instance);
0571   TEST_END();
0572   rtems_test_exit(0);
0573 }
0574 
0575 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0576 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0577 
0578 #define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 5
0579 
0580 #define CONFIGURE_MAXIMUM_TASKS 2
0581 
0582 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
0583 
0584 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0585 
0586 #define CONFIGURE_INIT_TASK_PRIORITY 2
0587 #define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
0588 #define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
0589 
0590 #define CONFIGURE_INIT
0591 
0592 #include <rtems/confdefs.h>