From 6600acc07a2af3b42495c846767ca1272b6d7254 Mon Sep 17 00:00:00 2001 From: Razvan Deaconescu <razvan.deaconescu@upb.ro> Date: Wed, 18 Oct 2023 19:34:02 +0300 Subject: [PATCH] Introduce samples/ directory These are sample programs to test the mini-libc implementation. Signed-off-by: Razvan Deaconescu <razvan.deaconescu@upb.ro> --- samples/.gitignore | 15 ++++ samples/Makefile | 29 +++++++ samples/fstat.c | 144 +++++++++++++++++++++++++++++++++++ samples/hello_world.c | 10 +++ samples/malloc.c | 41 ++++++++++ samples/memcmp.c | 33 ++++++++ samples/memmove.c | 30 ++++++++ samples/open_close.c | 40 ++++++++++ samples/read.c | 18 +++++ samples/self_test_mem_list.c | 51 +++++++++++++ samples/stat.c | 144 +++++++++++++++++++++++++++++++++++ samples/strcmp.c | 35 +++++++++ samples/strcpy_strcat.c | 48 ++++++++++++ samples/strstr_strrstr.c | 34 +++++++++ samples/truncate_ftruncate.c | 65 ++++++++++++++++ samples/write.c | 10 +++ 16 files changed, 747 insertions(+) create mode 100644 samples/.gitignore create mode 100644 samples/Makefile create mode 100644 samples/fstat.c create mode 100644 samples/hello_world.c create mode 100644 samples/malloc.c create mode 100644 samples/memcmp.c create mode 100644 samples/memmove.c create mode 100644 samples/open_close.c create mode 100644 samples/read.c create mode 100644 samples/self_test_mem_list.c create mode 100644 samples/stat.c create mode 100644 samples/strcmp.c create mode 100644 samples/strcpy_strcat.c create mode 100644 samples/strstr_strrstr.c create mode 100644 samples/truncate_ftruncate.c create mode 100644 samples/write.c diff --git a/samples/.gitignore b/samples/.gitignore new file mode 100644 index 0000000..d42edea --- /dev/null +++ b/samples/.gitignore @@ -0,0 +1,15 @@ +/hello_world +/malloc +/strcpy_strcat +/strcmp +/memcmp +/memmove +/strstr_strrstr +/open_close +/stat +/fstat +/truncate_ftruncate +/buffered_io +/read +/write +/self_test_mem_list diff --git a/samples/Makefile b/samples/Makefile new file mode 100644 index 0000000..c0e99a7 --- /dev/null +++ b/samples/Makefile @@ -0,0 +1,29 @@ +SRC_PATH ?= ../src +CPPFLAGS = -nostdinc -I. -I$(SRC_PATH)/include +CFLAGS = -Wall -Wextra -fno-PIC -fno-stack-protector -fno-builtin +# Remove the line below to disable debugging support. +CFLAGS += -g -O0 +LDFLAGS = -nostdlib -no-pie -L$(SRC_PATH) +LDLIBS = -lc + +SRCS = $(wildcard *.c) +OBJS = $(patsubst %.c,%.o,$(SRCS)) +EXECS = $(patsubst %.c,%,$(SRCS)) + + +.PHONY: all clean src + +all: $(EXECS) + +$(EXECS): %: %.o | src + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +$(OBJS): %.o:%.c + +src: + make -C $(SRC_PATH) + +clean: + -rm -f *~ + -rm -f $(OBJS) + -rm -f $(EXECS) diff --git a/samples/fstat.c b/samples/fstat.c new file mode 100644 index 0000000..d7bac17 --- /dev/null +++ b/samples/fstat.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <internal/types.h> + +#define FILENAME "./file" + +static char *itoa(long i, char *b) +{ + char const digit[] = "0123456789"; + char *p = b; + int shifter = i; + + do { + ++p; + shifter = shifter / 10; + } while (shifter); + + *p = '\0'; + do { + *--p = digit[i % 10]; + i = i / 10; + } while (i); + + return b; +} + +int main(void) +{ + int fd; + struct stat s; + char number[20]; + int r; + + memset(&s, 0, sizeof(s)); + + /* Create regular file with RW permissions for current user */ + fd = open(FILENAME, O_CREAT | O_RDWR, S_IRUSR); + if (fd < 0) { + write(1, "Something went wrong - create file.\n", strlen("Something went wrong - create file.\n")); + return -1; + } + + /* Call fstat and populate the stat structure */ + r = fstat(fd, &s); + if (r != 0) { + write(1, "Something went wrong - fstat.\n", strlen("Something went wrong - fstat.\n")); + return -1; + } + + /* Print file type */ + switch (s.st_mode & __S_IFMT) { + case __S_IFBLK: + write(1, "block device\n", strlen("block device\n")); + break; + case __S_IFCHR: + write(1, "character device\n", strlen("character device\n")); + break; + case __S_IFDIR: + write(1, "directory\n", strlen("directory\n")); + break; + case __S_IFIFO: + write(1, "FIFO/pipe\n", strlen("FIFO/pipe\n")); + break; + case __S_IFLNK: + write(1, "symlink\n", strlen("symlink\n")); + break; + case __S_IFREG: + write(1, "regular file\n", strlen("regular file\n")); + break; + case __S_IFSOCK: + write(1, "socket\n", strlen("socket\n")); + break; + default: + write(1, "unknown?\n", strlen("unknown?\n")); + break; + } + + /* Print inode number */ + itoa((long) (s.st_ino), number); + write(1, "INO: ", strlen("INO: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + + /* Print UID */ + memset(number, 0, sizeof(number)); + itoa((long) (s.st_uid), number); + write(1, "UID: ", strlen("UID: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + + /* Print GID */ + memset(number, 0, sizeof(number)); + itoa((long) (s.st_gid), number); + write(1, "GID: ", strlen("GID: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + + /* Print number of links */ + memset(number, 0, sizeof(number)); + itoa((long) (s.st_nlink), number); + write(1, "Number of links: ", strlen("Number of links: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + + /* Print block size */ + memset(number, 0, sizeof(number)); + itoa((long) (s.st_blksize), number); + write(1, "Block size: ", strlen("Block size: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + + /* Print number of blocks */ + memset(number, 0, sizeof(number)); + itoa((long) (s.st_blocks), number); + write(1, "Number of blocks: ", strlen("Number of blocks: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + + /* Print file size */ + memset(number, 0, sizeof(number)); + itoa((long) (s.st_size), number); + write(1, "File size: ", strlen("File size: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + + /* Print last modify time */ + memset(number, 0, sizeof(number)); + itoa((long) (s.st_mtime), number); + write(1, "Last modify time: ", strlen("Last modify time: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + write(1, "\n", 1); + + /* Close file */ + r = close(fd); + if (r < 0) + write(1, "Something went wrong - close.\n", strlen("Something went wrong - close.\n")); + + return 0; +} diff --git a/samples/hello_world.c b/samples/hello_world.c new file mode 100644 index 0000000..500c371 --- /dev/null +++ b/samples/hello_world.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include <unistd.h> + +int main(void) +{ + write(1, "Hello, World!\n", 14); + + return 0; +} diff --git a/samples/malloc.c b/samples/malloc.c new file mode 100644 index 0000000..f6cf430 --- /dev/null +++ b/samples/malloc.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +int main(void) +{ + int *p, *q, *r; + size_t i; + + p = malloc(10 * sizeof(*p)); + if (p == NULL) + exit(EXIT_FAILURE); + write(1, "Allocated p\n", 12); + + q = malloc(20 * sizeof(*q)); + if (q == NULL) + exit(EXIT_FAILURE); + write(1, "Allocated q\n", 12); + free(q); + write(1, "Freed q\n", 8); + + for (i = 0; i < 10; i++) + p[i] = 33; + + r = realloc(p, 100); + if (r == NULL) + exit(EXIT_FAILURE); + write(1, "Allocated r\n", 12); + + for (i = 0; i < 10; i++) + if (r[i] != 33) + write(2, "Not equal\n", 10); + write(1, "Realloc good\n", 13); + + free(r); + write(1, "Freed r\n", 8); + + return 0; +} diff --git a/samples/memcmp.c b/samples/memcmp.c new file mode 100644 index 0000000..d1f876f --- /dev/null +++ b/samples/memcmp.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include <unistd.h> +#include <string.h> + +void isEqual(int ret_code) +{ + if (ret_code == 0) + write(1, "Equal\n", 6); + else if (ret_code == -1) + write(1, "Lower\n", 6); + else if (ret_code == 1) + write(1, "Higher\n", 7); +} + +int main(void) +{ + int ret = 0; + + /* equal */ + ret = memcmp("abc", "abc", 3); + isEqual(ret); + + /* equal */ + ret = memcmp("abcd", "abca", 3); + isEqual(ret); + + /* higher */ + ret = memcmp("bca", "abc", 3); + isEqual(ret); + + return 0; +} diff --git a/samples/memmove.c b/samples/memmove.c new file mode 100644 index 0000000..611dc1d --- /dev/null +++ b/samples/memmove.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +int main(void) +{ + /* + * dst and src do not overlap. + * dst should be set to "Let's test memmove against simple string!\n". + */ + char src[] = "Let's test memmove against simple string!\n"; + char dst[100]; + char str2[] = "memmove can be very useful......\n"; + + memmove(dst, src, strlen(src)); + dst[strlen(src)] = '\0'; + + write(1, dst, strlen(dst)); + + /* + * dst and src overlap. + * dst should point to "memmove can be very useful.\n". + */ + memmove(str2 + 20, str2 + 15, 11); + write(1, str2, strlen(str2)); + + return 0; +} diff --git a/samples/open_close.c b/samples/open_close.c new file mode 100644 index 0000000..6601a43 --- /dev/null +++ b/samples/open_close.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +#define FILENAME "./file" + +int main(void) +{ + /* Try to open a file that doesn't exit. Open should return -1, and errno should be set to -ENOENT. */ + int fd; + int r; + + fd = open(FILENAME, 0, 0); + if (fd == -1 && errno == ENOENT) { + write(1, "Open returned error - trying to open file that doesn't exist.\n", + strlen("Open returned error - trying to open file that doesn't exist.\n")); + } else { + close(fd); + write(1, "Something went wrong - open.\n", strlen("Something went wrong - open.\n")); + } + + /* Try to open a file that doesn't exit, specify the O_CREAT flag. Open should succeed. */ + fd = open(FILENAME, O_CREAT, S_IRUSR); + if (fd >= 0) + write(1, "Open success - trying to open file that doesn't exist, O_CREAT was specified.\n", + strlen("Open success - trying to open file that doesn't exist, O_CREAT was specified.\n")); + else + write(1, "Something went wrong - open.\n", strlen("Something went wrong - open.\n")); + + /* Try to close the file descriptor. */ + r = close(fd); + if (r < 0) + write(1, "Something went wrong - close.\n", strlen("Something went wrong - close.\n")); + + return 0; +} diff --git a/samples/read.c b/samples/read.c new file mode 100644 index 0000000..df9705b --- /dev/null +++ b/samples/read.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include <stdlib.h> +#include <unistd.h> + +int main(void) +{ + char buffer[128]; + int n; + + n = read(0, buffer, 128); + if (n < 0) + exit(EXIT_FAILURE); + + write(1, buffer, n); + + return 0; +} diff --git a/samples/self_test_mem_list.c b/samples/self_test_mem_list.c new file mode 100644 index 0000000..949936d --- /dev/null +++ b/samples/self_test_mem_list.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include <internal/mm/mem_list.h> +#include <unistd.h> + +static const char msg_failed[] = "failed\n"; +static const char msg_passed[] = "passed\n"; + +static void test(const char *msg, size_t msglen, int condition) +{ + write(1, msg, msglen); + write(1, " .......... ", 12); + if (condition) + write(1, msg_passed, sizeof(msg_passed)-1); + else + write(1, msg_failed, sizeof(msg_failed)-1); +} + +int main(void) +{ + mem_list_init(); + test("num aftter init", 15, mem_list_num_items() == 0); + + mem_list_add((void *) 0x1000, 256); + test("add 0x1000", 10, mem_list_num_items() == 1); + + mem_list_add((void *) 0x2000, 1024); + test("add 0x2000", 10, mem_list_num_items() == 2); + + mem_list_add((void *) 0x3000, 2048); + test("add 0x3000", 10, mem_list_num_items() == 3); + + test("find 0x1000", 11, mem_list_find((void *) 0x1000) != NULL); + test("find 0x2000", 11, mem_list_find((void *) 0x2000) != NULL); + test("find 0x3000", 11, mem_list_find((void *) 0x3000) != NULL); + test("find 0x4000", 11, mem_list_find((void *) 0x4000) == NULL); + + test("find 0x2000 start", 17, mem_list_find((void *) 0x2000)->start == (void *) 0x2000); + test("find 0x2000 len", 15, mem_list_find((void *) 0x2000)->len == 1024); + + mem_list_del((void *) 0x1000); + test("num after del 0x1000", 20, mem_list_num_items() == 2); + + mem_list_del((void *) 0x3000); + test("num after del 0x3000", 20, mem_list_num_items() == 1); + + mem_list_cleanup(); + test("num after cleanup", 17, mem_list_num_items() == 0); + + return 0; +} diff --git a/samples/stat.c b/samples/stat.c new file mode 100644 index 0000000..759ae8e --- /dev/null +++ b/samples/stat.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <internal/types.h> + +#define FILENAME "./file" + +static char *itoa(long i, char *b) +{ + char const digit[] = "0123456789"; + char *p = b; + int shifter = i; + + do { + ++p; + shifter = shifter / 10; + } while (shifter); + + *p = '\0'; + do { + *--p = digit[i % 10]; + i = i / 10; + } while (i); + + return b; +} + +int main(void) +{ + struct stat s; + int fd; + int r; + char number[20]; + + memset(&s, 0, sizeof(s)); + + /* Create regular file with RW permissions for current user */ + fd = open(FILENAME, O_CREAT | O_RDWR, S_IRUSR); + if (fd < 0) { + write(1, "Something went wrong - create file.\n", strlen("Something went wrong - create file.\n")); + return -1; + } + + /* Call stat and populate the stat structure */ + r = stat(FILENAME, &s); + if (r != 0) { + write(1, "Something went wrong - stat.\n", strlen("Something went wrong - stat.\n")); + return -1; + } + + /* Print file type */ + switch (s.st_mode & __S_IFMT) { + case __S_IFBLK: + write(1, "block device\n", strlen("block device\n")); + break; + case __S_IFCHR: + write(1, "character device\n", strlen("character device\n")); + break; + case __S_IFDIR: + write(1, "directory\n", strlen("directory\n")); + break; + case __S_IFIFO: + write(1, "FIFO/pipe\n", strlen("FIFO/pipe\n")); + break; + case __S_IFLNK: + write(1, "symlink\n", strlen("symlink\n")); + break; + case __S_IFREG: + write(1, "regular file\n", strlen("regular file\n")); + break; + case __S_IFSOCK: + write(1, "socket\n", strlen("socket\n")); + break; + default: + write(1, "unknown?\n", strlen("unknown?\n")); + break; + } + + /* Print inode number */ + itoa((long)(s.st_ino), number); + write(1, "INO: ", strlen("INO: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + + /* Print UID */ + memset(number, 0, sizeof(number)); + itoa((long) (s.st_uid), number); + write(1, "UID: ", strlen("UID: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + + /* Print GID */ + memset(number, 0, sizeof(number)); + itoa((long) (s.st_gid), number); + write(1, "GID: ", strlen("GID: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + + /* Print number of links */ + memset(number, 0, sizeof(number)); + itoa((long) (s.st_nlink), number); + write(1, "Number of links: ", strlen("Number of links: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + + /* Print block size */ + memset(number, 0, sizeof(number)); + itoa((long) (s.st_blksize), number); + write(1, "Block size: ", strlen("Block size: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + + /* Print number of blocks */ + memset(number, 0, sizeof(number)); + itoa((long) (s.st_blocks), number); + write(1, "Number of blocks: ", strlen("Number of blocks: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + + /* Print file size */ + memset(number, 0, sizeof(number)); + itoa((long) (s.st_size), number); + write(1, "File size: ", strlen("File size: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + + /* Print last modify time */ + memset(number, 0, sizeof(number)); + itoa((long) (s.st_mtime), number); + write(1, "Last modify time: ", strlen("Last modify time: ")); + write(1, number, strlen(number)); + write(1, "\n", 1); + write(1, "\n", 1); + + /* Close file */ + r = close(fd); + if (r < 0) + write(1, "Something went wrong - close.\n", strlen("Something went wrong - close.\n")); + + return 0; +} diff --git a/samples/strcmp.c b/samples/strcmp.c new file mode 100644 index 0000000..192785e --- /dev/null +++ b/samples/strcmp.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include <unistd.h> +#include <string.h> + +void isEqual(int ret_code) +{ + if (ret_code == 0) + write(1, "Equal\n", 6); + else if (ret_code == -1) + write(1, "Lower\n", 6); + else if (ret_code == 1) + write(1, "Higher\n", 7); +} + +int main(void) +{ + int ret = 0; + char str1[] = "Hello, World"; + char str2[] = "Hello, World!"; + + /* string1 is lower than string2 */ + ret = strcmp(str1, str2); + isEqual(ret); + + /* string1 is lower than string2 */ + ret = strncmp(str1, str2, strlen(str2)); + isEqual(ret); + + /* strings are equal */ + ret = strncmp(str1, str2, strlen(str2) - 1); + isEqual(ret); + + return 0; +} diff --git a/samples/strcpy_strcat.c b/samples/strcpy_strcat.c new file mode 100644 index 0000000..2da2fe5 --- /dev/null +++ b/samples/strcpy_strcat.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include <unistd.h> +#include <string.h> + +int main(void) +{ + /* strcpy - dst is set to Hello, World!\n */ + char dst[20]; + char *src = "Hello, World!\n"; + char str1[] = "To be or not to be"; + char str2[40]; + char str3[40]; + char str4[80]; + char str5[20]; + char str6[20]; + + strcpy(dst, src); + write(1, dst, strlen(dst)); + + /* strncpy - str2 is set to str1 (To be or not to be) */ + strncpy(str2, str1, sizeof(str2)); + write(1, str2, strlen(str2)); + write(1, "\n", 1); + + /* strncpy - str3 is set to partial copy of str2 (To be) */ + strncpy(str3, str2, 5); + str3[5] = '\0'; + write(1, str3, strlen(str3)); + write(1, "\n", 1); + + /* strcat - concatenate */ + strcpy(str4, "These "); + strcat(str4, "strings "); + strcat(str4, "are "); + strcat(str4, "concatenated."); + write(1, str4, strlen(str4)); + write(1, "\n", 1); + + /* strncat - concatenate str5 with partial copy of str6 - (To be or not) */ + strcpy(str5, "To be "); + strcpy(str6, "or not to be"); + strncat(str5, str6, 6); + write(1, str5, strlen(str5)); + write(1, "\n", 1); + + return 0; +} diff --git a/samples/strstr_strrstr.c b/samples/strstr_strrstr.c new file mode 100644 index 0000000..ba85227 --- /dev/null +++ b/samples/strstr_strrstr.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include <unistd.h> +#include <string.h> + +int main(void) +{ + /* + * Search for the first index of "simple" in "This is a simple string". + * pch should point to "simple string". + */ + char str[] = "This is a simple string"; + char *pch; + char string[] = "This is a test string for testing"; + char *p; + + pch = strstr(str, "simple"); + if (pch != NULL) { + write(1, pch, strlen(pch)); + write(1, "\n", 1); + } + + /* + * Search for the last index of "test" in "This is a test string for testing". + * pch should point to "testing. + */ + p = strrstr(string, "test"); + if (p != NULL) { + write(1, p, strlen(p)); + write(1, "\n", 1); + } + + return 0; +} diff --git a/samples/truncate_ftruncate.c b/samples/truncate_ftruncate.c new file mode 100644 index 0000000..565e9b1 --- /dev/null +++ b/samples/truncate_ftruncate.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include <fcntl.h> +#include <unistd.h> +#include <string.h> + +#define SIZE1 5000 +#define SIZE2 10000 + +#define FILENAME1 "./file1" +#define FILENAME2 "./file2" + +int main(void) +{ + /* + * Try to open a file that doesn't exit, specify the O_CREAT flag. + * Open should succeed. + * Specify access mode as O_WRONLY and the user permissions as write to be able to truncate the file. + */ + int fd1, fd2; + int r; + + fd1 = open(FILENAME1, O_CREAT | O_WRONLY, S_IWUSR); + if (fd1 < 0) { + write(1, "Something went wrong - open.\n", strlen("Something went wrong - open.\n")); + return -1; + } + + /* + * Try to open a file that doesn't exit, specify the O_CREAT flag. + * Open should succeed. + * Specify access mode as O_WRONLY and the user permissions as write to be able to truncate the file. + */ + fd2 = open(FILENAME2, O_CREAT | O_WRONLY, S_IWUSR); + if (fd2 < 0) { + write(1, "Something went wrong - open.\n", strlen("Something went wrong - open.\n")); + return -1; + } + + /* Truncate FILENAME1 to SIZE1. */ + r = truncate(FILENAME1, SIZE1); + if (r < 0) { + write(1, "Something went wrong - truncate.\n", strlen("Something went wrong - truncate.\n")); + return -1; + } + + /* Truncate FILENAME2 to SIZE2. */ + r = ftruncate(fd2, SIZE2); + if (r < 0) { + write(1, "Something went wrong - ftruncate.\n", strlen("Something went wrong - ftruncate.\n")); + return -1; + } + + /* Try to close the file descriptor. */ + r = close(fd1); + if (r < 0) + write(1, "Something went wrong - close.\n", strlen("Something went wrong - close.\n")); + + /* Try to close the file descriptor. */ + r = close(fd2); + if (r < 0) + write(1, "Something went wrong - close.\n", strlen("Something went wrong - close.\n")); + + return 0; +} diff --git a/samples/write.c b/samples/write.c new file mode 100644 index 0000000..500c371 --- /dev/null +++ b/samples/write.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include <unistd.h> + +int main(void) +{ + write(1, "Hello, World!\n", 14); + + return 0; +} -- GitLab