gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/images/basic/integrationtest/host_fd.c (about)

     1  // Copyright 2021 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include <err.h>
    16  #include <errno.h>
    17  #include <getopt.h>
    18  #include <stddef.h>
    19  #include <stdio.h>
    20  #include <sys/epoll.h>
    21  #include <sys/ioctl.h>
    22  #include <sys/select.h>
    23  #include <unistd.h>
    24  
    25  // Flag to indicate that TTY is being used in the container.
    26  static int tty = 0;
    27  
    28  // Tests that FIONREAD is supported with host FD.
    29  void testFionread() {
    30    int size = 0;
    31    if (ioctl(STDOUT_FILENO, FIONREAD, &size) < 0) {
    32      err(1, "ioctl(stdin, FIONREAD)");
    33    }
    34    if (size != 0) {
    35      err(1, "FIONREAD wrong size, want: 0, got: %d", size);
    36    }
    37  }
    38  
    39  // Docker maps stdin to /dev/null which doesn't support epoll. Check that error
    40  // is correctly propagated.
    41  void testEpoll() {
    42    if (tty) {
    43      // stdin is not /dev/null when TTY is used for the container.
    44      return;
    45    }
    46    int fd = epoll_create(1);
    47    if (fd < 0) {
    48      err(1, "epoll_create");
    49    }
    50  
    51    struct epoll_event event;
    52    event.events = EPOLLIN;
    53    event.data.u64 = 123;
    54    int res = epoll_ctl(fd, EPOLL_CTL_ADD, 0, &event);
    55    if (res != -1) {
    56      err(1, "epoll_ctl(EPOLL_CTL_ADD, stdin) should have failed");
    57    }
    58    if (errno != EPERM) {
    59      err(1, "epoll_ctl(EPOLL_CTL_ADD, stdin) should have returned EPERM");
    60    }
    61  }
    62  
    63  // Docker maps stdin to /dev/null. Check that select(2) works with stdin.
    64  void testSelect() {
    65    fd_set rfds;
    66    struct timeval tv;
    67    int res;
    68    FD_ZERO(&rfds);
    69    FD_SET(0, &rfds);
    70    tv.tv_sec = 0;
    71    tv.tv_usec = 1;
    72    res = select(1, &rfds, NULL, NULL, &tv);
    73    if (res == -1) {
    74      err(1, "select(1, [STDIN], NULL, NULL) returned error");
    75    }
    76  }
    77  
    78  int main(int argc, char** argv) {
    79    int opt;
    80    while ((opt = getopt(argc, argv, "t")) != -1) {
    81      switch (opt) {
    82        case 't':
    83          tty = 1;
    84          break;
    85        default:
    86          fprintf(stderr, "Usage: %s [-t]\n", argv[0]);
    87          return 1;
    88      }
    89    }
    90  
    91    testFionread();
    92    testEpoll();
    93    testSelect();
    94    return 0;
    95  }