source: rtems/testsuites/fstests/fsclose01/init.c

Last change on this file was bcef89f2, checked in by Sebastian Huber <sebastian.huber@…>, on 05/19/23 at 06:18:25

Update company name

The embedded brains GmbH & Co. KG is the legal successor of embedded
brains GmbH.

  • Property mode set to 100644
File size: 12.6 KB
Line 
1/*
2 * Copyright (C) 2012, 2020 embedded brains GmbH & Co. KG
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
17 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
23 * POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29
30#include <sys/stat.h>
31#include <sys/ioctl.h>
32#include <sys/uio.h>
33#include <fcntl.h>
34#include <unistd.h>
35#include <errno.h>
36
37#include <rtems/imfs.h>
38#include <rtems/malloc.h>
39#include <rtems/libcsupport.h>
40
41#include <tmacros.h>
42
43const char rtems_test_name[] = "FSCLOSE 1";
44
45typedef enum {
46  ACTION_CLOSE,
47  ACTION_FCNTL,
48  ACTION_FDATASYNC,
49  ACTION_FCHDIR,
50  ACTION_FCHMOD,
51  ACTION_FCHOWN,
52  /* ACTION_FPATHCONF, not easy to test */
53  ACTION_FSTAT,
54  ACTION_FSYNC,
55  ACTION_FTRUNCATE,
56  ACTION_IOCTL,
57  ACTION_LSEEK,
58  ACTION_READ,
59  ACTION_READV,
60  ACTION_WRITE,
61  ACTION_WRITEV
62} test_action;
63
64typedef struct {
65  rtems_id worker_id;
66  int fd;
67  test_action action;
68  bool wait_in_close;
69  bool wait_in_fstat;
70  int close_count;
71  int fcntl_count;
72  int fdatasync_count;
73  int fstat_count;
74  int fsync_count;
75  int ftruncate_count;
76  int ioctl_count;
77  int lseek_count;
78  int open_count;
79  int read_count;
80  int readv_count;
81  int write_count;
82  int writev_count;
83} test_context;
84
85static test_context test_instance;
86
87static void wait(void)
88{
89  rtems_status_code sc;
90
91  sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
92  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
93}
94
95static void wakeup_worker(const test_context *ctx)
96{
97  rtems_status_code sc;
98
99  sc = rtems_event_transient_send(ctx->worker_id);
100  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
101}
102
103static int handler_open(
104  rtems_libio_t *iop,
105  const char *path,
106  int oflag,
107  mode_t mode
108)
109{
110  test_context *ctx;
111
112  ctx = IMFS_generic_get_context_by_iop(iop);
113  ++ctx->open_count;
114
115  return 0;
116}
117
118static int handler_close(
119  rtems_libio_t *iop
120)
121{
122  test_context *ctx;
123
124  ctx = IMFS_generic_get_context_by_iop(iop);
125  ++ctx->close_count;
126
127  if (ctx->wait_in_close) {
128    ctx->wait_in_close = false;
129    wait();
130  }
131
132  return 0;
133}
134
135static ssize_t handler_read(
136  rtems_libio_t *iop,
137  void *buffer,
138  size_t count
139)
140{
141  test_context *ctx;
142
143  ctx = IMFS_generic_get_context_by_iop(iop);
144  ++ctx->read_count;
145
146  wait();
147  return 0;
148}
149
150static ssize_t handler_write(
151  rtems_libio_t *iop,
152  const void *buffer,
153  size_t count
154)
155{
156  test_context *ctx;
157
158  ctx = IMFS_generic_get_context_by_iop(iop);
159  ++ctx->write_count;
160
161  wait();
162  return 0;
163}
164
165static int handler_ioctl(
166  rtems_libio_t *iop,
167  ioctl_command_t request,
168  void *buffer
169)
170{
171  test_context *ctx;
172
173  ctx = IMFS_generic_get_context_by_iop(iop);
174  ++ctx->ioctl_count;
175
176  wait();
177  return 0;
178}
179
180static off_t handler_lseek(
181  rtems_libio_t *iop,
182  off_t length,
183  int whence
184)
185{
186  test_context *ctx;
187
188  ctx = IMFS_generic_get_context_by_iop(iop);
189  ++ctx->lseek_count;
190
191  wait();
192  return 0;
193}
194
195static int handler_fstat(
196  const rtems_filesystem_location_info_t *loc,
197  struct stat *buf
198)
199{
200  test_context *ctx;
201
202  buf->st_mode = S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO;
203  ctx = IMFS_generic_get_context_by_location(loc);
204  ++ctx->fstat_count;
205
206  if (ctx->wait_in_fstat) {
207    ctx->wait_in_fstat = false;
208    wait();
209  }
210
211  return 0;
212}
213
214static int handler_ftruncate(
215  rtems_libio_t *iop,
216  off_t length
217)
218{
219  test_context *ctx;
220
221  ctx = IMFS_generic_get_context_by_iop(iop);
222  ++ctx->ftruncate_count;
223
224  wait();
225  return 0;
226}
227
228static int handler_fsync(
229  rtems_libio_t *iop
230)
231{
232  test_context *ctx;
233
234  ctx = IMFS_generic_get_context_by_iop(iop);
235  ++ctx->fsync_count;
236
237  wait();
238  return 0;
239}
240
241static int handler_fdatasync(
242  rtems_libio_t *iop
243)
244{
245  test_context *ctx;
246
247  ctx = IMFS_generic_get_context_by_iop(iop);
248  ++ctx->fdatasync_count;
249
250  wait();
251  return 0;
252}
253
254static int handler_fcntl(
255  rtems_libio_t *iop,
256  int cmd
257)
258{
259  test_context *ctx;
260
261  ctx = IMFS_generic_get_context_by_iop(iop);
262  ++ctx->fcntl_count;
263
264  wait();
265  return 0;
266}
267
268static ssize_t handler_readv(
269  rtems_libio_t *iop,
270  const struct iovec *iov,
271  int iovcnt,
272  ssize_t total
273)
274{
275  test_context *ctx;
276
277  ctx = IMFS_generic_get_context_by_iop(iop);
278  ++ctx->readv_count;
279
280  wait();
281  return 0;
282}
283
284static ssize_t handler_writev(
285  rtems_libio_t *iop,
286  const struct iovec *iov,
287  int iovcnt,
288  ssize_t total
289)
290{
291  test_context *ctx;
292
293  ctx = IMFS_generic_get_context_by_iop(iop);
294  ++ctx->writev_count;
295
296  wait();
297  return 0;
298}
299
300static const rtems_filesystem_file_handlers_r node_handlers = {
301  .open_h = handler_open,
302  .close_h = handler_close,
303  .read_h = handler_read,
304  .write_h = handler_write,
305  .ioctl_h = handler_ioctl,
306  .lseek_h = handler_lseek,
307  .fstat_h = handler_fstat,
308  .ftruncate_h = handler_ftruncate,
309  .fsync_h = handler_fsync,
310  .fdatasync_h = handler_fdatasync,
311  .fcntl_h = handler_fcntl,
312  .readv_h = handler_readv,
313  .writev_h = handler_writev
314};
315
316static const IMFS_node_control node_control = {
317  .handlers = &node_handlers,
318  .node_initialize = IMFS_node_initialize_generic,
319  .node_remove = IMFS_node_remove_default,
320  .node_destroy = IMFS_node_destroy_default
321};
322
323static void worker_task(rtems_task_argument arg)
324{
325  test_context *ctx;
326  int rv;
327  char buf[1];
328  ssize_t n;
329  off_t off;
330  struct iovec iov = {
331    .iov_base = &buf[0],
332    .iov_len = sizeof(buf)
333  };
334  struct stat st;
335
336  ctx = (test_context *) arg;
337
338  while (true) {
339    wait();
340
341    switch (ctx->action) {
342      case ACTION_CLOSE:
343        ctx->wait_in_close = true;
344        rv = close(ctx->fd);
345        rtems_test_assert(rv == 0);
346        break;
347      case ACTION_FCNTL:
348        rv = fcntl(ctx->fd, F_GETFD);
349        rtems_test_assert(rv >= 0);
350        break;
351      case ACTION_FDATASYNC:
352        rv = fdatasync(ctx->fd);
353        rtems_test_assert(rv == 0);
354        break;
355      case ACTION_FCHDIR:
356        ctx->wait_in_fstat = true;
357        rv = fchdir(ctx->fd);
358        rtems_test_assert(rv == -1);
359        rtems_test_assert(errno == ENOTDIR);
360        break;
361      case ACTION_FCHMOD:
362        rv = fstat(ctx->fd, &st);
363        rtems_test_assert(rv == 0);
364        ctx->wait_in_fstat = true;
365        rv = fchmod(ctx->fd, st.st_mode);
366        rtems_test_assert(rv == 0);
367        break;
368      case ACTION_FCHOWN:
369        rv = fstat(ctx->fd, &st);
370        rtems_test_assert(rv == 0);
371        ctx->wait_in_fstat = true;
372        rv = fchown(ctx->fd, st.st_uid, st.st_gid);
373        rtems_test_assert(rv == 0);
374        break;
375      case ACTION_FSTAT:
376        ctx->wait_in_fstat = true;
377        rv = fstat(ctx->fd, &st);
378        rtems_test_assert(rv == 0);
379        break;
380      case ACTION_FSYNC:
381        rv = fsync(ctx->fd);
382        rtems_test_assert(rv == 0);
383        break;
384      case ACTION_FTRUNCATE:
385        rv = ftruncate(ctx->fd, 0);
386        rtems_test_assert(rv == 0);
387        break;
388      case ACTION_IOCTL:
389        rv = ioctl(ctx->fd, 0);
390        rtems_test_assert(rv == 0);
391        break;
392      case ACTION_LSEEK:
393        off = lseek(ctx->fd, 0, SEEK_SET);
394        rtems_test_assert(off == 0);
395        break;
396      case ACTION_READ:
397        n = read(ctx->fd, buf, sizeof(buf));
398        rtems_test_assert(n == 0);
399        break;
400      case ACTION_READV:
401        n = readv(ctx->fd, &iov, 1);
402        rtems_test_assert(n == 0);
403        break;
404      case ACTION_WRITE:
405        n = write(ctx->fd, buf, sizeof(buf));
406        rtems_test_assert(n == 0);
407        break;
408      case ACTION_WRITEV:
409        n = writev(ctx->fd, &iov, 1);
410        rtems_test_assert(n == 0);
411        break;
412      default:
413        rtems_test_assert(0);
414        break;
415    }
416  }
417}
418
419static void test_fd_free_fifo(const char *path)
420{
421  int a;
422  int b;
423  int rv;
424
425  a = open(path, O_RDWR);
426  rtems_test_assert(a >= 0);
427
428  rv = close(a);
429  rtems_test_assert(rv == 0);
430
431  b = open(path, O_RDWR);
432  rtems_test_assert(b >= 0);
433
434  rv = close(b);
435  rtems_test_assert(rv == 0);
436
437  rtems_test_assert(a != b);
438}
439
440static void test_close(test_context *ctx)
441{
442  const char *path = "generic";
443  int rv;
444  rtems_status_code sc;
445  test_action ac;
446
447  rv = IMFS_make_generic_node(
448    path,
449    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
450    &node_control,
451    ctx
452  );
453  rtems_test_assert(rv == 0);
454
455  test_fd_free_fifo(path);
456
457  sc = rtems_task_create(
458    rtems_build_name('W', 'O', 'R', 'K'),
459    1,
460    RTEMS_MINIMUM_STACK_SIZE,
461    RTEMS_DEFAULT_MODES,
462    RTEMS_DEFAULT_ATTRIBUTES,
463    &ctx->worker_id
464  );
465  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
466
467  sc = rtems_task_start(
468    ctx->worker_id,
469    worker_task,
470    (rtems_task_argument) ctx
471  );
472  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
473
474  for (ac = ACTION_CLOSE; ac <= ACTION_WRITEV; ++ac) {
475    rtems_libio_t *iop;
476    unsigned int flags;
477    unsigned int expected_flags;
478
479    ctx->action = ac;
480    ctx->fd = open(path, O_RDWR);
481    rtems_test_assert(ctx->fd >= 0);
482    iop = rtems_libio_iop(ctx->fd);
483
484    wakeup_worker(ctx);
485    rv = close(ctx->fd);
486    rtems_test_assert(rv == -1);
487
488    if (ac == ACTION_CLOSE) {
489      rtems_test_assert(errno == EBADF);
490
491      flags = rtems_libio_iop_hold(iop);
492      expected_flags = LIBIO_FLAGS_READ_WRITE;
493      rtems_test_assert(flags == expected_flags);
494      flags = rtems_libio_iop_flags(iop);
495      expected_flags = LIBIO_FLAGS_REFERENCE_INC | LIBIO_FLAGS_READ_WRITE;
496      rtems_test_assert(flags == expected_flags);
497    } else {
498      rtems_test_assert(errno == EBUSY);
499    }
500
501    wakeup_worker(ctx);
502
503    if (ac == ACTION_CLOSE) {
504      flags = rtems_libio_iop_flags(iop);
505      expected_flags = LIBIO_FLAGS_REFERENCE_INC;
506      rtems_test_assert(flags == expected_flags);
507      rtems_libio_iop_drop(iop);
508      flags = rtems_libio_iop_flags(iop);
509      expected_flags = 0;
510      rtems_test_assert(flags == expected_flags);
511    }
512
513    rv = close(ctx->fd);
514
515    if (ac == ACTION_CLOSE) {
516      rtems_test_assert(rv == -1);
517      rtems_test_assert(errno == EBADF);
518    } else {
519      rtems_test_assert(rv == 0);
520    }
521  }
522
523  sc = rtems_task_delete(ctx->worker_id);
524  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
525
526  rv = unlink(path);
527  rtems_test_assert(rv == 0);
528
529  rtems_test_assert(ctx->close_count == 17);
530  rtems_test_assert(ctx->fcntl_count == 1);
531  rtems_test_assert(ctx->fdatasync_count == 1);
532  rtems_test_assert(ctx->fstat_count == 42);
533  rtems_test_assert(ctx->fsync_count == 1);
534  rtems_test_assert(ctx->ftruncate_count == 1);
535  rtems_test_assert(ctx->ioctl_count == 1);
536  rtems_test_assert(ctx->lseek_count == 1);
537  rtems_test_assert(ctx->open_count == 17);
538  rtems_test_assert(ctx->read_count == 1);
539  rtems_test_assert(ctx->readv_count == 1);
540  rtems_test_assert(ctx->write_count == 1);
541  rtems_test_assert(ctx->writev_count == 1);
542}
543
544static void test_tmpfile(test_context *ctx)
545{
546  rtems_resource_snapshot before;
547  FILE *f;
548  int rv;
549
550  rv = mkdir("/tmp", S_IRWXU | S_IRWXG | S_IRWXO);
551  rtems_test_assert(rv == 0);
552
553  f = tmpfile();
554  rtems_test_assert(f != NULL);
555  rv = fclose(f);
556  rtems_test_assert(rv == 0);
557
558  rtems_resource_snapshot_take(&before);
559  f = tmpfile();
560  rtems_test_assert(f != NULL);
561  rv = fclose(f);
562  rtems_test_assert(rv == 0);
563  rtems_test_assert(rtems_resource_snapshot_check(&before));
564}
565
566static void Init(rtems_task_argument arg)
567{
568  TEST_BEGIN();
569  test_close(&test_instance);
570  test_tmpfile(&test_instance);
571  TEST_END();
572  rtems_test_exit(0);
573}
574
575#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
576#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
577
578#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 5
579
580#define CONFIGURE_MAXIMUM_TASKS 2
581
582#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
583
584#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
585
586#define CONFIGURE_INIT_TASK_PRIORITY 2
587#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
588#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
589
590#define CONFIGURE_INIT
591
592#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.