---
 libbsd.py                        |   2 +-
 testsuite/media01/pattern-test.c | 337 +++++++++++++++++++++++++++++++
 testsuite/media01/pattern-test.h |  44 ++++
 testsuite/media01/test_main.c    |   5 +-
 4 files changed, 386 insertions(+), 2 deletions(-)
 create mode 100644 testsuite/media01/pattern-test.c
 create mode 100644 testsuite/media01/pattern-test.h
diff --git a/libbsd.py b/libbsd.py
index a2056f364..f8a35e6c6 100644
--- a/libbsd.py
+++ b/libbsd.py
@@ -5402,7 +5402,7 @@ class tests(builder.Module):
                                           runTest = False, netTest = True,
                                           extraLibs = ['telnetd']))
         self.addTest(mm.generator['test']('smp01', ['test_main'], extraLibs = 
['rtemstest']))
-        self.addTest(mm.generator['test']('media01', ['test_main'],
+        self.addTest(mm.generator['test']('media01', ['test_main', 
'pattern-test'],
                                           runTest = False,
                                           extraLibs = ['ftpd', 'telnetd']))
         self.addTest(mm.generator['test']('mcast01', ['test_main']))
diff --git a/testsuite/media01/pattern-test.c b/testsuite/media01/pattern-test.c
new file mode 100644
index 000000000..4b00cb736
--- /dev/null
+++ b/testsuite/media01/pattern-test.c
@@ -0,0 +1,337 @@
+/**
+ * @file
+ *
+ * @brief Command to fill a file with a pattern.
+ *
+ * The written pattern is a simple 32 bit counter which makes it easy to find
+ * problems where buffers are not written to the correct location or where some
+ * blocks are missing.
+ *
+ * This file can be either compiled as part of RTEMS or as a stand alone Linux
+ * or (most likely) FreeBSD application. To compile it as stand alone, just use
+ * "gcc pattern-test.c"
+ */
+
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2020 embedded brains GmbH.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef __rtems__
+#include "pattern-test.h"
+#endif /* __rtems__ */
+
+#include <arpa/inet.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
+
+static const char * const usage =
+       "Fill a file or a device file with a simple incrementing 32 bit 
pattern.\n"
+       "Use with:\n"
+       "    pattern [fill|check] <file> <size> <block_size> [<start_value> 
[<output>]]\n"
+       "Arguments:\n"
+       "    All numbers can be decimal (e.g. 256) or hex (e.g. 0x100)\n"
+       "    <size> and <block_size> is in bytes\n"
+       "    <start_value> start with this counter value\n"
+       "    <output>: Only relevant for check. Can be: \n"
+       "              <nr>: print the first <nr> errors\n"
+       "              \"short\": Print all errors but short form\n";
+
+static int
+check_and_process_params(
+       int argc,
+       char *argv[],
+       int open_flags,
+       int *fd,
+       size_t *size,
+       size_t *block_size,
+       uint8_t **block,
+       uint8_t **read_block,
+       int *max_errors,
+       bool *short_output,
+       uint32_t *start_value
+)
+{
+       if (argc < 4) {
+               printf(usage);
+               return -1;
+       }
+
+       if (argc > 4) {
+               *start_value = strtoul(argv[4], NULL, 0);
+       } else {
+               *start_value = 0;
+       }
+
+       if (short_output != NULL && max_errors != NULL) {
+               *short_output = false;
+               *max_errors = 1;
+               if (argc > 5) {
+                       if (strcmp("short", argv[5]) == 0) {
+                               *max_errors = -1;
+                               *short_output = true;
+                       } else {
+                               *max_errors = strtol(argv[5], NULL, 0);
+                               if (*max_errors <= 0) {
+                                       warn("Can't use <output> parameter.");
+                                       return -1;
+                               }
+                       }
+               }
+       }
+
+       *size = strtoul(argv[2], NULL, 0);
+       if (size == 0) {
+               warn("Couldn't convert size or size set to 0");
+               return -1;
+       }
+
+       *block_size = strtoul(argv[3], NULL, 0);
+       if (block_size == 0) {
+               warn("Couldn't convert block_size or block_size set to 0");
+               return -1;
+       }
+
+       if (block != NULL) {
+               *block = malloc(*block_size);
+               if (*block == NULL) {
+                       warn("Couldn't allocate block");
+                       return -1;
+               }
+       }
+
+       if (read_block != NULL) {
+               *read_block = malloc(*block_size);
+               if (*read_block == NULL) {
+                       warn("Couldn't allocate read_block");
+                       if (block != NULL) {
+                               free(*block);
+                       }
+                       return -1;
+               }
+       }
+
+       *fd = open(argv[1], open_flags, 0666);
+       if (*fd < 0) {
+               warn("Couldn't open file");
+               if (block != NULL) {
+                       free(*block);
+               }
+               if (read_block != NULL) {
+                       free(*read_block);
+               }
+               return -1;
+       }
+
+       printf("File: %s\nSize: 0x%x\nBlock size: 0x%x\n",
+           argv[1], *size, *block_size);
+
+       return 0;
+}
+
+/* Write addresses to the block. Keep word boundaries intact. */
+static void
+fill_block(uint8_t *block, size_t size, uint32_t start)
+{
+       uint32_t pattern_size = sizeof(start);
+       uint32_t start_offset = start % pattern_size;
+       uint32_t value_h = start & ~(pattern_size - 1);
+       uint32_t value_n = htonl(value_h);
+       uint8_t *val = (uint8_t *) &value_n;
+
+       if (start_offset != 0) {
+               size_t to_write = MIN(pattern_size - start_offset, size);
+               memcpy(block, val + start_offset, to_write);
+               block += to_write;
+               size -= to_write;
+               value_h += pattern_size;
+               value_n = htonl(value_h);
+       }
+
+       while (size >= pattern_size) {
+               memcpy(block, val, pattern_size);
+               value_h += pattern_size;
+               value_n = htonl(value_h);
+               block += pattern_size;
+               size -= pattern_size;
+       }
+
+       if (size > 0) {
+               memcpy(block, val, size);
+       }
+}
+
+static int
+command_pattern_fill(int argc, char *argv[])
+{
+       int fd;
+       size_t size;
+       size_t block_size;
+       uint8_t *block;
+       uint32_t start_value;
+       int rv;
+
+       rv = check_and_process_params(argc, argv, O_WRONLY | O_CREAT,
+           &fd, &size, &block_size, &block, NULL, NULL, NULL, &start_value);
+       if (rv != 0) {
+               warnx("Error while processing parameters.\n");
+               return rv;
+       }
+
+       for (size_t current = start_value;
+           current < start_value + size;
+           current += block_size) {
+               size_t write_size = MIN(block_size, size-current);
+               ssize_t written;
+               fill_block(block, write_size, current);
+               written = write(fd, block, write_size);
+               if (written != (ssize_t)write_size) {
+                       warn("Writing failed on block at 0x%x", current);
+                       break;
+               }
+       }
+
+       free(block);
+       close(fd);
+
+       return 0;
+}
+
+static void
+print_block(uint8_t *block, size_t size)
+{
+       for (size_t i = 0; i < size; ++i) {
+               if (i > 0 && i % 0x10 == 0) {
+                       printf("\n");
+               }
+               printf("%02x ", block[i]);
+       }
+       printf("\n");
+}
+
+static int
+command_pattern_check(int argc, char *argv[])
+{
+       int fd;
+       size_t size;
+       size_t block_size;
+       uint8_t *block;
+       uint8_t *read_block;
+       int rv;
+       int errors = 0;
+       int max_errors;
+       bool short_output;
+       bool last_was_error = false;
+       uint32_t start_value;
+
+       rv = check_and_process_params(argc, argv, O_RDONLY,
+           &fd, &size, &block_size, &block, &read_block,
+           &max_errors, &short_output, &start_value);
+       if (rv != 0) {
+               warnx("Error while processing parameters.\n");
+               return rv;
+       }
+
+       for (size_t current = start_value;
+           current < size + start_value;
+           current += block_size) {
+               size_t read_size = MIN(block_size, size-current);
+               ssize_t received;
+               fill_block(block, read_size, current);
+               received = read(fd, read_block, read_size);
+               if (received != (ssize_t)read_size) {
+                       warn("Reading failed on block at 0x%x", current);
+                       break;
+               }
+               rv = memcmp(block, read_block, read_size);
+               if (short_output) {
+                       bool is_error = (rv != 0);
+                       if (last_was_error != is_error) {
+                               warnx("%s: 0x%x",
+                                   is_error ? "ERR" : "OK ",
+                                   current);
+                       }
+                       last_was_error = is_error;
+               } else if (rv != 0) {
+                       warnx("Pattern wrong in block at 0x%x", current);
+                       warnx("Expected:");
+                       print_block(block, read_size);
+                       warnx("Got:");
+                       print_block(read_block, read_size);
+                       ++errors;
+                       if (errors >= max_errors) {
+                               warnx("Too many errors. Refusing to continue.");
+                               break;
+                       }
+               }
+       }
+
+       free(read_block);
+       free(block);
+       close(fd);
+
+       return 0;
+}
+
+static int
+command_pattern(int argc, char *argv[])
+{
+       if (argc < 2) {
+               printf(usage);
+               return -1;
+       } else if (strcmp(argv[1], "fill") == 0) {
+               return command_pattern_fill(argc-1, &argv[1]);
+       } else if (strcmp(argv[1], "check") == 0) {
+               return command_pattern_check(argc-1, &argv[1]);
+       } else {
+               printf(usage);
+               return -1;
+       }
+}
+
+#ifdef __rtems__
+rtems_shell_cmd_t shell_PATTERN_Command = {
+       .name = "pattern",
+       .usage = usage,
+       .topic = "files",
+       .command = command_pattern,
+};
+#else /* __rtems__ */
+
+int
+main(int argc, char *argv[])
+{
+       return command_pattern(argc, argv);
+}
+#endif /* __rtems__ */
diff --git a/testsuite/media01/pattern-test.h b/testsuite/media01/pattern-test.h
new file mode 100644
index 000000000..5d89e16ca
--- /dev/null
+++ b/testsuite/media01/pattern-test.h
@@ -0,0 +1,44 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2020 embedded brains GmbH.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TESTSUITE_PATTERN_H
+#define TESTSUITE_PATTERN_H
+
+#include <rtems.h>
+#include <rtems/shell.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+extern rtems_shell_cmd_t shell_PATTERN_Command;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* TESTSUITE_PATTERN_H */
diff --git a/testsuite/media01/test_main.c b/testsuite/media01/test_main.c
index 9c05fc077..2a1c9aae7 100644
--- a/testsuite/media01/test_main.c
+++ b/testsuite/media01/test_main.c
@@ -53,6 +53,8 @@
 #include <rtems/shell.h>
 #include <rtems/telnetd.h>
 
+#include "pattern-test.h"
+
 #define TEST_NAME "LIBBSD MEDIA 1"
 #define TEST_STATE_USER_INPUT 1
 
@@ -241,7 +243,8 @@ early_initialization(void)
   &rtems_shell_SYSCTL_Command, \
   &rtems_shell_IFCONFIG_Command, \
   &rtems_shell_IFMCSTAT_Command, \
-  &rtems_shell_VMSTAT_Command
+  &rtems_shell_VMSTAT_Command, \
+  &shell_PATTERN_Command
 
 #define CONFIGURE_SHELL_COMMAND_CPUINFO
 #define CONFIGURE_SHELL_COMMAND_CPUUSE
-- 
2.26.2

_______________________________________________
devel mailing list
devel@rtems.org
http://lists.rtems.org/mailman/listinfo/devel

Reply via email to