1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2020 Francis Laniel. All rights reserved. 4f08c3bdfSopenharmony_ci * Author: Francis Laniel <laniel_francis@privacyrequired.com> 5f08c3bdfSopenharmony_ci * 6f08c3bdfSopenharmony_ci * Test Description: 7f08c3bdfSopenharmony_ci * This Program tests getting and setting the pipe size. 8f08c3bdfSopenharmony_ci * It also tests what happen when you write to a full pipe depending on whether 9f08c3bdfSopenharmony_ci * O_NONBLOCK is set or not. 10f08c3bdfSopenharmony_ci */ 11f08c3bdfSopenharmony_ci#define _GNU_SOURCE 12f08c3bdfSopenharmony_ci#include <stdlib.h> 13f08c3bdfSopenharmony_ci#include <features.h> 14f08c3bdfSopenharmony_ci#include <unistd.h> 15f08c3bdfSopenharmony_ci#include <stdio.h> 16f08c3bdfSopenharmony_ci#include "lapi/fcntl.h" 17f08c3bdfSopenharmony_ci#include "tst_test.h" 18f08c3bdfSopenharmony_ci 19f08c3bdfSopenharmony_cistatic int fds[2]; 20f08c3bdfSopenharmony_cistatic int flags; 21f08c3bdfSopenharmony_ci 22f08c3bdfSopenharmony_cistatic void test_pipe2(void) 23f08c3bdfSopenharmony_ci{ 24f08c3bdfSopenharmony_ci int ret; 25f08c3bdfSopenharmony_ci pid_t pid; 26f08c3bdfSopenharmony_ci 27f08c3bdfSopenharmony_ci /* 28f08c3bdfSopenharmony_ci * This ensures parent process is still in non-block mode when 29f08c3bdfSopenharmony_ci * using -i parameter. Subquent writes hould return -1 and errno 30f08c3bdfSopenharmony_ci * set to either EAGAIN or EWOULDBLOCK because pipe is already full. 31f08c3bdfSopenharmony_ci */ 32f08c3bdfSopenharmony_ci SAFE_FCNTL(fds[1], F_SETFL, flags | O_NONBLOCK); 33f08c3bdfSopenharmony_ci ret = write(fds[1], "x", 1); 34f08c3bdfSopenharmony_ci if (ret == -1) { 35f08c3bdfSopenharmony_ci if (errno == EAGAIN) 36f08c3bdfSopenharmony_ci tst_res(TPASS | TERRNO, "write failed as expected"); 37f08c3bdfSopenharmony_ci else 38f08c3bdfSopenharmony_ci tst_brk(TFAIL | TERRNO, "write failed expected EAGAIN but got"); 39f08c3bdfSopenharmony_ci } else { 40f08c3bdfSopenharmony_ci tst_res(TFAIL, "write() succeeded unexpectedly"); 41f08c3bdfSopenharmony_ci } 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_ci pid = SAFE_FORK(); 44f08c3bdfSopenharmony_ci if (!pid) { 45f08c3bdfSopenharmony_ci SAFE_FCNTL(fds[1], F_SETFL, flags & ~O_NONBLOCK); 46f08c3bdfSopenharmony_ci SAFE_WRITE(SAFE_WRITE_ALL, fds[1], "x", 1); 47f08c3bdfSopenharmony_ci } 48f08c3bdfSopenharmony_ci 49f08c3bdfSopenharmony_ci if (TST_PROCESS_STATE_WAIT(pid, 'S', 1000) < 0) 50f08c3bdfSopenharmony_ci tst_res(TFAIL, "Child process is not blocked"); 51f08c3bdfSopenharmony_ci else 52f08c3bdfSopenharmony_ci tst_res(TPASS, "Child process is blocked"); 53f08c3bdfSopenharmony_ci 54f08c3bdfSopenharmony_ci SAFE_KILL(pid, SIGKILL); 55f08c3bdfSopenharmony_ci SAFE_WAIT(NULL); 56f08c3bdfSopenharmony_ci} 57f08c3bdfSopenharmony_ci 58f08c3bdfSopenharmony_cistatic void setup(void) 59f08c3bdfSopenharmony_ci{ 60f08c3bdfSopenharmony_ci int page_size, pipe_size; 61f08c3bdfSopenharmony_ci char *write_buffer; 62f08c3bdfSopenharmony_ci 63f08c3bdfSopenharmony_ci SAFE_PIPE2(fds, O_NONBLOCK); 64f08c3bdfSopenharmony_ci page_size = SAFE_SYSCONF(_SC_PAGESIZE); 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_ci flags = SAFE_FCNTL(fds[1], F_GETFL); 67f08c3bdfSopenharmony_ci if (!(flags & O_NONBLOCK)) 68f08c3bdfSopenharmony_ci tst_brk(TCONF, "O_NONBLOCK flag must be set"); 69f08c3bdfSopenharmony_ci /* 70f08c3bdfSopenharmony_ci * A pipe has two file descriptors. 71f08c3bdfSopenharmony_ci * But in the kernel these two file descriptors point to the same pipe. 72f08c3bdfSopenharmony_ci * So setting size from first file handle set size for the pipe. 73f08c3bdfSopenharmony_ci */ 74f08c3bdfSopenharmony_ci SAFE_FCNTL(fds[0], F_SETPIPE_SZ, 0); 75f08c3bdfSopenharmony_ci 76f08c3bdfSopenharmony_ci /* 77f08c3bdfSopenharmony_ci * So getting size from the second file descriptor return the size of 78f08c3bdfSopenharmony_ci * the pipe which was changed before with first file descriptor. 79f08c3bdfSopenharmony_ci */ 80f08c3bdfSopenharmony_ci pipe_size = SAFE_FCNTL(fds[1], F_GETPIPE_SZ); 81f08c3bdfSopenharmony_ci if (pipe_size != page_size) 82f08c3bdfSopenharmony_ci tst_res(TFAIL, "Pipe size (%d) must be page size (%d)", 83f08c3bdfSopenharmony_ci pipe_size, page_size); 84f08c3bdfSopenharmony_ci 85f08c3bdfSopenharmony_ci write_buffer = SAFE_MALLOC(pipe_size); 86f08c3bdfSopenharmony_ci memset(write_buffer, 'x', pipe_size); 87f08c3bdfSopenharmony_ci SAFE_WRITE(SAFE_WRITE_ALL, fds[1], write_buffer, pipe_size); 88f08c3bdfSopenharmony_ci free(write_buffer); 89f08c3bdfSopenharmony_ci} 90f08c3bdfSopenharmony_ci 91f08c3bdfSopenharmony_cistatic void cleanup(void) 92f08c3bdfSopenharmony_ci{ 93f08c3bdfSopenharmony_ci if (fds[0] > 0) 94f08c3bdfSopenharmony_ci SAFE_CLOSE(fds[0]); 95f08c3bdfSopenharmony_ci if (fds[1] > 0) 96f08c3bdfSopenharmony_ci SAFE_CLOSE(fds[1]); 97f08c3bdfSopenharmony_ci} 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_cistatic struct tst_test test = { 100f08c3bdfSopenharmony_ci .test_all = test_pipe2, 101f08c3bdfSopenharmony_ci .setup = setup, 102f08c3bdfSopenharmony_ci .cleanup = cleanup, 103f08c3bdfSopenharmony_ci .forks_child = 1, 104f08c3bdfSopenharmony_ci}; 105