/* Child program invoked by test-execute-main. Copyright (C) 2009-2021 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ /* If the user's config.h happens to include , let it include only the system's here. */ #define __need_system_sys_stat_h #include /* Get the original definition of fstat. It might be defined as a macro. Also, 'stat' might be defined as a macro. */ #include #include #undef __need_system_sys_stat_h /* Return non-zero if FD is opened to a device. */ static int is_device (int fd) { #if defined _WIN32 && ! defined __CYGWIN__ struct _stat st; return _fstat (fd, &st) >= 0 && !((st.st_mode & S_IFMT) == S_IFREG); #else struct stat st; return fstat (fd, &st) >= 0 && !S_ISREG (st.st_mode); #endif } /* Now include the other header files. */ #include #include #include #include #include #include #include #include #if defined _WIN32 && ! defined __CYGWIN__ /* Get declarations of the native Windows API functions. */ # define WIN32_LEAN_AND_MEAN # include /* Get _get_osfhandle, _isatty, _chdir, _getcwd. */ # include #endif /* In this file, we use only system functions, no overrides from gnulib. */ #undef atoi #undef close #undef fcntl #undef fflush #undef fgetc #undef fprintf #undef fputs #undef getcwd #undef isatty #undef open #undef raise #undef read #undef sprintf #undef strcasestr #undef strcmp #undef strlen #undef strstr #undef write #include "qemu.h" #if HAVE_MSVC_INVALID_PARAMETER_HANDLER static void __cdecl gl_msvc_invalid_parameter_handler (const wchar_t *expression, const wchar_t *function, const wchar_t *file, unsigned int line, uintptr_t dummy) { } #endif /* Return non-zero if FD is open. */ static int is_open (int fd) { #if defined _WIN32 && ! defined __CYGWIN__ /* On native Windows, the initial state of unassigned standard file descriptors is that they are open but point to an INVALID_HANDLE_VALUE, and there is no fcntl. */ return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE; #else # ifndef F_GETFL # error Please port fcntl to your platform # endif return 0 <= fcntl (fd, F_GETFL); #endif } int main (int argc, char *argv[]) { if (argc == 1) /* Check an invocation without arguments. Check the exit code. */ return 40; int test = atoi (argv[1]); switch (test) { case 2: /* Check argument passing. */ return !(argc == 12 && strcmp (argv[2], "abc def") == 0 && strcmp (argv[3], "abc\"def\"ghi") == 0 && strcmp (argv[4], "xyz\"") == 0 && strcmp (argv[5], "abc\\def\\ghi") == 0 && strcmp (argv[6], "xyz\\") == 0 && strcmp (argv[7], "???") == 0 && strcmp (argv[8], "***") == 0 && strcmp (argv[9], "") == 0 && strcmp (argv[10], "foo") == 0 && strcmp (argv[11], "") == 0); #if !(defined _WIN32 && !defined __CYGWIN__) case 3: /* Check SIGPIPE handling with ignore_sigpipe = false. */ case 4: /* Check SIGPIPE handling with ignore_sigpipe = true. */ raise (SIGPIPE); return 71; #endif case 5: /* Check other signal. */ raise (SIGINT); return 71; case 6: /* Check stdin is inherited. */ return !(fgetc (stdin) == 'F' && fgetc (stdin) == 'o'); case 7: /* Check null_stdin = true. */ return !(fgetc (stdin) == EOF); case 8: /* Check stdout is inherited, part 1 (regular file). */ return !(fputs ("bar", stdout) != EOF && fflush (stdout) == 0); case 9: /* Check stdout is inherited, part 2 (device). */ case 10: /* Check null_stdout = true. */ return !is_device (STDOUT_FILENO); case 11: /* Check stderr is inherited, part 1 (regular file). */ return !(fputs ("bar", stderr) != EOF && fflush (stderr) == 0); case 12: /* Check stderr is inherited, part 2 (device). */ case 13: /* Check null_stderr = true. */ return !is_device (STDERR_FILENO); case 14: case 15: /* Check file descriptors >= 3 can be inherited. */ case 16: /* Check file descriptors >= 3 with O_CLOEXEC bit are not inherited. */ #if HAVE_MSVC_INVALID_PARAMETER_HANDLER /* Avoid exceptions from within _get_osfhandle. */ _set_invalid_parameter_handler (gl_msvc_invalid_parameter_handler); #endif { /* QEMU 6.1 in user-mode passes an open fd = 3, that references /dev/urandom. We need to ignore this fd. */ bool is_qemu = is_running_under_qemu_user (); char buf[300]; buf[0] = '\0'; char *p = buf; int fd; for (fd = 0; fd < 20; fd++) if (is_open (fd) && !(is_qemu && fd == 3)) { sprintf (p, "%d ", fd); p += strlen (p); } const char *expected = (test < 16 ? "0 1 2 10 " : "0 1 2 "); if (strcmp (buf, expected) == 0) return 0; else { fprintf (stderr, "Test case %d: %s\n", test, buf); fflush (stderr); return 1; } } case 17: /* Check that file descriptors >= 3, open for reading, can be inherited, including the file position. */ { char buf[6]; int n = read (10, buf, sizeof (buf)); return !(n == 4 && memcmp (buf, "obar", 4) == 0); } case 18: /* Check that file descriptors >= 3, open for writing, can be inherited, including the file position. */ { int n = write (10, "bar", 3); return !(n == 3); } case 19: /* Check that file descriptors >= 3, when inherited, preserve their isatty() property, part 1 (regular file). */ case 20: /* Check that file descriptors >= 3, when inherited, preserve their isatty() property, part 2 (character devices). */ { #if defined _WIN32 && ! defined __CYGWIN__ return 4 + 2 * (_isatty (10) != 0) + (_isatty (11) != 0); #else return 4 + 2 * (isatty (10) != 0) + (isatty (11) != 0); #endif } case 21: /* Check execution in a different directory. */ { char cwd[1024]; #if defined _WIN32 && ! defined __CYGWIN__ if (_chdir ("..") != 0) return 1; if (_getcwd (cwd, sizeof (cwd)) == NULL) return 2; #else if (chdir ("..") != 0) return 1; if (getcwd (cwd, sizeof (cwd)) == NULL) return 2; #endif return (argc == 3 && strcmp (argv[2], cwd) == 0 ? 0 : 3); } default: abort (); } }