1 /* 2 * Copyright (c) International Business Machines Corp., 2002 3 * Ported by Paul Larson 4 * Copyright (c) 2013 Cyril Hrubis <chrubis (at) suse.cz> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 14 * the GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21 /* 22 * Test the ability of pipe to open the maximum even number of file 23 * descriptors permitted (or (maxfds - 3)/2 pipes) 24 * 25 * ALGORITHM 26 * 1. record file descriptors open prior to test run 27 * 2. open pipes until EMFILE is returned 28 * 3. check to see that the number of pipes opened is (maxfds - 3) / 2 29 * 4. close all fds in range 0, maximal fd that were not open prior to 30 * the test execution 31 */ 32 #include <unistd.h> 33 #include <fcntl.h> 34 #include <errno.h> 35 #include <stdlib.h> 36 #include <stdio.h> 37 #include <string.h> 38 #include <dirent.h> 39 40 #include "test.h" 41 #include "safe_macros.h" 42 43 char *TCID = "pipe07"; 44 int TST_TOTAL = 1; 45 46 /* used to record file descriptors open at the test start */ 47 static int rec_fds[128]; 48 static int rec_fds_max; 49 static void record_open_fds(void); 50 static void close_test_fds(int max_fd); 51 52 static void setup(void); 53 static void cleanup(void); 54 55 int main(int ac, char **av) 56 { 57 int lc; 58 int min, ret; 59 int npipes; 60 int pipes[2], max_fd = 0; 61 62 tst_parse_opts(ac, av, NULL, NULL); 63 64 setup(); 65 66 min = getdtablesize() - rec_fds_max; 67 68 for (lc = 0; TEST_LOOPING(lc); lc++) { 69 tst_count = 0; 70 71 for (npipes = 0;; npipes++) { 72 ret = pipe(pipes); 73 if (ret < 0) { 74 if (errno != EMFILE) { 75 tst_brkm(TFAIL, cleanup, 76 "got unexpected error - %d", 77 errno); 78 } 79 break; 80 } 81 82 max_fd = MAX(pipes[0], max_fd); 83 max_fd = MAX(pipes[1], max_fd); 84 } 85 86 if (npipes == (min / 2)) 87 tst_resm(TPASS, "Opened %d pipes", npipes); 88 else 89 tst_resm(TFAIL, "Unable to open maxfds/2 pipes"); 90 91 close_test_fds(max_fd); 92 max_fd = 0; 93 } 94 95 cleanup(); 96 tst_exit(); 97 } 98 99 static void setup(void) 100 { 101 tst_sig(FORK, DEF_HANDLER, cleanup); 102 TEST_PAUSE; 103 104 record_open_fds(); 105 } 106 107 static void record_open_fds(void) 108 { 109 DIR *dir = opendir("/proc/self/fd"); 110 int dir_fd, fd; 111 struct dirent *file; 112 113 if (dir == NULL) 114 tst_brkm(TBROK | TERRNO, cleanup, "opendir()"); 115 116 dir_fd = dirfd(dir); 117 118 if (dir_fd == -1) 119 tst_brkm(TBROK | TERRNO, cleanup, "dirfd()"); 120 121 errno = 0; 122 123 while ((file = readdir(dir))) { 124 if (!strcmp(file->d_name, ".") || !strcmp(file->d_name, "..")) 125 continue; 126 127 fd = atoi(file->d_name); 128 129 if (fd == dir_fd) 130 continue; 131 132 if (rec_fds_max >= (int)ARRAY_SIZE(rec_fds)) { 133 tst_brkm(TBROK, cleanup, 134 "Too much file descriptors open"); 135 } 136 137 rec_fds[rec_fds_max++] = fd; 138 } 139 140 if (errno) 141 tst_brkm(TBROK | TERRNO, cleanup, "readdir()"); 142 143 closedir(dir); 144 145 tst_resm(TINFO, "Found %u files open", rec_fds_max); 146 } 147 148 static int not_recorded(int fd) 149 { 150 int i; 151 152 for (i = 0; i < rec_fds_max; i++) 153 if (fd == rec_fds[i]) 154 return 0; 155 156 return 1; 157 } 158 159 static void close_test_fds(int max_fd) 160 { 161 int i; 162 163 for (i = 0; i <= max_fd; i++) { 164 if (not_recorded(i)) { 165 if (close(i)) { 166 if (errno == EBADF) 167 continue; 168 tst_resm(TWARN | TERRNO, "close(%i)", i); 169 } 170 } 171 } 172 } 173 174 static void cleanup(void) 175 { 176 } 177