root/maint/gnulib/tests/test-execute-main.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. main

   1 /* Test of execute.
   2    Copyright (C) 2020-2021 Free Software Foundation, Inc.
   3 
   4    This program is free software; you can redistribute it and/or modify
   5    it under the terms of the GNU General Public License as published by
   6    the Free Software Foundation; either version 3, or (at your option)
   7    any later version.
   8 
   9    This program is distributed in the hope that it will be useful,
  10    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12    GNU General Public License for more details.
  13 
  14    You should have received a copy of the GNU General Public License
  15    along with this program; if not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 #include <config.h>
  18 
  19 #include "execute.h"
  20 
  21 #include <errno.h>
  22 #include <fcntl.h>
  23 #include <signal.h>
  24 #include <stdbool.h>
  25 #include <stdio.h>
  26 #include <stdlib.h>
  27 #include <string.h>
  28 #include <unistd.h>
  29 #include <sys/stat.h>
  30 
  31 #if defined _WIN32 && ! defined __CYGWIN__
  32 /* Get _isatty, _getcwd.  */
  33 # include <io.h>
  34 #endif
  35 
  36 #include "read-file.h"
  37 #include "macros.h"
  38 
  39 /* The name of the "always silent" device.  */
  40 #if defined _WIN32 && ! defined __CYGWIN__
  41 /* Native Windows API.  */
  42 # define DEV_NULL "NUL"
  43 #else
  44 /* Unix API.  */
  45 # define DEV_NULL "/dev/null"
  46 #endif
  47 
  48 #define BASE "test-execute"
  49 
  50 int
  51 main (int argc, char *argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
  52 {
  53   if (argc != 3)
  54     {
  55       fprintf (stderr, "%s: need 2 arguments\n", argv[0]);
  56       return 2;
  57     }
  58   char *prog_path = argv[1];
  59   const char *progname = "test-execute-child";
  60   int test = atoi (argv[2]);
  61 
  62   switch (test)
  63     {
  64     case 14:
  65     case 15:
  66     case 16:
  67       /* Close file descriptors that have been inherited from the parent
  68          process and that would cause failures in test-execute-child.c.
  69          Such file descriptors have been seen:
  70            - with GNU make, when invoked as 'make -j N' with j > 1,
  71            - in some versions of the KDE desktop environment,
  72            - on NetBSD,
  73            - in MacPorts with the "trace mode" enabled.
  74        */
  75       #if HAVE_CLOSE_RANGE
  76       if (close_range (3, 20 - 1, 0) < 0)
  77       #endif
  78         {
  79           int fd;
  80           for (fd = 3; fd < 20; fd++)
  81             close (fd);
  82         }
  83     default:
  84       break;
  85     }
  86 
  87   switch (test)
  88     {
  89     case 0:
  90       {
  91         /* Check an invocation without arguments.  Check the exit code.  */
  92         const char *prog_argv[2] = { prog_path, NULL };
  93         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
  94                            false, false, false, false, true, false, NULL);
  95         ASSERT (ret == 40);
  96       }
  97       break;
  98     case 1:
  99       {
 100         /* Check an invocation of a non-existent program.  */
 101         const char *prog_argv[3] = { "./non-existent", NULL };
 102         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 103                            false, false, false, false, true, false, NULL);
 104         ASSERT (ret == 127);
 105       }
 106       break;
 107     case 2:
 108       {
 109         /* Check argument passing.  */
 110         const char *prog_argv[13] =
 111           {
 112             prog_path,
 113             "2",
 114             "abc def",
 115             "abc\"def\"ghi",
 116             "xyz\"",
 117             "abc\\def\\ghi",
 118             "xyz\\",
 119             "???",
 120             "***",
 121             "",
 122             "foo",
 123             "",
 124             NULL
 125           };
 126         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 127                            false, false, false, false, true, false, NULL);
 128         ASSERT (ret == 0);
 129       }
 130       break;
 131     case 3:
 132       #if !(defined _WIN32 && !defined __CYGWIN__)
 133       {
 134         /* Check SIGPIPE handling with ignore_sigpipe = false.  */
 135         const char *prog_argv[3] = { prog_path, "3", NULL };
 136         int termsig = 0x7DEADBEE;
 137         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 138                            false, false, false, false, true, false, &termsig);
 139         ASSERT (ret == 127);
 140         ASSERT (termsig == SIGPIPE);
 141       }
 142       #endif
 143       break;
 144     case 4:
 145       #if !(defined _WIN32 && !defined __CYGWIN__)
 146       {
 147         /* Check SIGPIPE handling with ignore_sigpipe = true.  */
 148         const char *prog_argv[3] = { prog_path, "4", NULL };
 149         int termsig = 0x7DEADBEE;
 150         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 151                            true, false, false, false, true, false, &termsig);
 152         ASSERT (ret == 0);
 153         ASSERT (termsig == SIGPIPE);
 154       }
 155       #endif
 156       break;
 157     case 5:
 158       {
 159         /* Check other signal.  */
 160         const char *prog_argv[3] = { prog_path, "5", NULL };
 161         int termsig = 0x7DEADBEE;
 162         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 163                            false, false, false, false, true, false, &termsig);
 164         ASSERT (ret == 127);
 165         #if defined _WIN32 && !defined __CYGWIN__
 166         ASSERT (termsig == SIGTERM); /* dummy, from WTERMSIG in <sys/wait.h> */
 167         #else
 168         ASSERT (termsig == SIGINT);
 169         #endif
 170       }
 171       break;
 172     case 6:
 173       {
 174         /* Check stdin is inherited.  */
 175         FILE *fp = fopen (BASE ".tmp", "w");
 176         fputs ("Foo", fp);
 177         ASSERT (fclose (fp) == 0);
 178 
 179         fp = freopen (BASE ".tmp", "r", stdin);
 180         ASSERT (fp != NULL);
 181 
 182         const char *prog_argv[3] = { prog_path, "6", NULL };
 183         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 184                            false, false, false, false, true, false, NULL);
 185         ASSERT (ret == 0);
 186 
 187         ASSERT (fclose (stdin) == 0);
 188         ASSERT (remove (BASE ".tmp") == 0);
 189       }
 190       break;
 191     case 7:
 192       {
 193         /* Check null_stdin = true.  */
 194         FILE *fp = fopen (BASE ".tmp", "w");
 195         fputs ("Foo", fp);
 196         ASSERT (fclose (fp) == 0);
 197 
 198         fp = freopen (BASE ".tmp", "r", stdin);
 199         ASSERT (fp != NULL);
 200 
 201         const char *prog_argv[3] = { prog_path, "7", NULL };
 202         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 203                            false, true, false, false, true, false, NULL);
 204         ASSERT (ret == 0);
 205 
 206         ASSERT (fclose (stdin) == 0);
 207         ASSERT (remove (BASE ".tmp") == 0);
 208       }
 209       break;
 210     case 8:
 211       {
 212         /* Check stdout is inherited, part 1 (regular file).  */
 213         FILE *fp = freopen (BASE ".tmp", "w", stdout);
 214         ASSERT (fp != NULL);
 215 
 216         const char *prog_argv[3] = { prog_path, "8", NULL };
 217         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 218                            false, false, false, false, true, false, NULL);
 219         ASSERT (ret == 0);
 220 
 221         ASSERT (fclose (stdout) == 0);
 222 
 223         size_t length;
 224         char *contents = read_file (BASE ".tmp", 0, &length);
 225         ASSERT (length == 3 && memcmp (contents, "bar", 3) == 0);
 226 
 227         ASSERT (remove (BASE ".tmp") == 0);
 228       }
 229       break;
 230     case 9:
 231       {
 232         /* Check stdout is inherited, part 2 (device).  */
 233         FILE *fp = freopen (DEV_NULL, "w", stdout);
 234         ASSERT (fp != NULL);
 235 
 236         const char *prog_argv[3] = { prog_path, "9", NULL };
 237         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 238                            false, false, false, false, true, false, NULL);
 239         ASSERT (ret == 0);
 240       }
 241       break;
 242     case 10:
 243       {
 244         /* Check null_stdout = true.  */
 245         FILE *fp = freopen (BASE ".tmp", "w", stdout);
 246         ASSERT (fp != NULL);
 247 
 248         const char *prog_argv[3] = { prog_path, "10", NULL };
 249         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 250                            false, false, true, false, true, false, NULL);
 251         ASSERT (ret == 0);
 252 
 253         ASSERT (fclose (stdout) == 0);
 254 
 255         size_t length;
 256         (void) read_file (BASE ".tmp", 0, &length);
 257         ASSERT (length == 0);
 258 
 259         ASSERT (remove (BASE ".tmp") == 0);
 260       }
 261       break;
 262     case 11:
 263       {
 264         /* Check stderr is inherited, part 1 (regular file).  */
 265         FILE *fp = freopen (BASE ".tmp", "w", stderr);
 266         ASSERT (fp != NULL);
 267 
 268         const char *prog_argv[3] = { prog_path, "11", NULL };
 269         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 270                            false, false, false, false, true, false, NULL);
 271         ASSERT (ret == 0);
 272 
 273         ASSERT (fclose (stderr) == 0);
 274 
 275         size_t length;
 276         char *contents = read_file (BASE ".tmp", 0, &length);
 277         ASSERT (length == 3 && memcmp (contents, "bar", 3) == 0);
 278 
 279         ASSERT (remove (BASE ".tmp") == 0);
 280       }
 281       break;
 282     case 12:
 283       {
 284         /* Check stderr is inherited, part 2 (device).  */
 285         FILE *fp = freopen (DEV_NULL, "w", stderr);
 286         ASSERT (fp != NULL);
 287 
 288         const char *prog_argv[3] = { prog_path, "12", NULL };
 289         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 290                            false, false, false, false, true, false, NULL);
 291         ASSERT (ret == 0);
 292       }
 293       break;
 294     case 13:
 295       {
 296         /* Check null_stderr = true.  */
 297         FILE *fp = freopen (BASE ".tmp", "w", stderr);
 298         ASSERT (fp != NULL);
 299 
 300         const char *prog_argv[3] = { prog_path, "13", NULL };
 301         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 302                            false, false, false, true, true, false, NULL);
 303         ASSERT (ret == 0);
 304 
 305         ASSERT (fclose (stderr) == 0);
 306 
 307         size_t length;
 308         (void) read_file (BASE ".tmp", 0, &length);
 309         ASSERT (length == 0);
 310 
 311         ASSERT (remove (BASE ".tmp") == 0);
 312       }
 313       break;
 314     case 14:
 315       {
 316         /* Check file descriptors >= 3 can be inherited.  */
 317         ASSERT (dup2 (STDOUT_FILENO, 10) >= 0);
 318         const char *prog_argv[3] = { prog_path, "14", NULL };
 319         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 320                            true, false, false, false, true, false, NULL);
 321         ASSERT (ret == 0);
 322       }
 323       break;
 324     case 15:
 325       {
 326         /* Check file descriptors >= 3 can be inherited.  */
 327         ASSERT (fcntl (STDOUT_FILENO, F_DUPFD, 10) >= 0);
 328         const char *prog_argv[3] = { prog_path, "15", NULL };
 329         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 330                            true, false, false, false, true, false, NULL);
 331         ASSERT (ret == 0);
 332       }
 333       break;
 334     case 16:
 335       {
 336         /* Check file descriptors >= 3 with O_CLOEXEC bit are not inherited.  */
 337         ASSERT (fcntl (STDOUT_FILENO, F_DUPFD_CLOEXEC, 10) >= 0);
 338         const char *prog_argv[3] = { prog_path, "16", NULL };
 339         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 340                            true, false, false, false, true, false, NULL);
 341         ASSERT (ret == 0);
 342       }
 343       break;
 344     case 17:
 345       {
 346         /* Check that file descriptors >= 3, open for reading, can be inherited,
 347            including the file position.  */
 348         FILE *fp = fopen (BASE ".tmp", "w");
 349         fputs ("Foobar", fp);
 350         ASSERT (fclose (fp) == 0);
 351 
 352         int fd = open (BASE ".tmp", O_RDONLY);
 353         ASSERT (fd >= 0 && fd < 10);
 354 
 355         ASSERT (dup2 (fd, 10) >= 0);
 356         close (fd);
 357         fd = 10;
 358 
 359         char buf[2];
 360         ASSERT (read (fd, buf, sizeof (buf)) == sizeof (buf));
 361         /* The file position is now 2.  */
 362 
 363         const char *prog_argv[3] = { prog_path, "17", NULL };
 364         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 365                            false, false, false, false, true, false, NULL);
 366         ASSERT (ret == 0);
 367 
 368         close (fd);
 369         ASSERT (remove (BASE ".tmp") == 0);
 370       }
 371       break;
 372     case 18:
 373       {
 374         /* Check that file descriptors >= 3, open for writing, can be inherited,
 375            including the file position.  */
 376         remove (BASE ".tmp");
 377         int fd = open (BASE ".tmp", O_RDWR | O_CREAT | O_TRUNC, 0600);
 378         ASSERT (fd >= 0 && fd < 10);
 379 
 380         ASSERT (dup2 (fd, 10) >= 0);
 381         close (fd);
 382         fd = 10;
 383 
 384         ASSERT (write (fd, "Foo", 3) == 3);
 385         /* The file position is now 3.  */
 386 
 387         const char *prog_argv[3] = { prog_path, "18", NULL };
 388         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 389                            false, false, false, false, true, false, NULL);
 390         ASSERT (ret == 0);
 391 
 392         close (fd);
 393 
 394         size_t length;
 395         char *contents = read_file (BASE ".tmp", 0, &length);
 396         ASSERT (length == 6 && memcmp (contents, "Foobar", 6) == 0);
 397 
 398         ASSERT (remove (BASE ".tmp") == 0);
 399       }
 400       break;
 401     case 19:
 402       {
 403         /* Check that file descriptors >= 3, when inherited, preserve their
 404            isatty() property, part 1 (regular file).  */
 405         FILE *fp = fopen (BASE ".tmp", "w");
 406         fputs ("Foo", fp);
 407         ASSERT (fclose (fp) == 0);
 408 
 409         int fd_in = open (BASE ".tmp", O_RDONLY);
 410         ASSERT (fd_in >= 0 && fd_in < 10);
 411 
 412         int fd_out = open (BASE ".tmp", O_WRONLY | O_APPEND);
 413         ASSERT (fd_out >= 0 && fd_out < 10);
 414 
 415         ASSERT (dup2 (fd_in, 10) >= 0);
 416         close (fd_in);
 417         fd_in = 10;
 418 
 419         ASSERT (dup2 (fd_out, 11) >= 0);
 420         close (fd_out);
 421         fd_out = 11;
 422 
 423         const char *prog_argv[3] = { prog_path, "19", NULL };
 424         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 425                            false, false, false, false, true, false, NULL);
 426         #if defined _WIN32 && ! defined __CYGWIN__
 427         ASSERT (ret == 4 + 2 * (_isatty (10) != 0) + (_isatty (11) != 0));
 428         #else
 429         ASSERT (ret == 4 + 2 * (isatty (10) != 0) + (isatty (11) != 0));
 430         #endif
 431 
 432         close (fd_in);
 433         close (fd_out);
 434         ASSERT (remove (BASE ".tmp") == 0);
 435       }
 436       break;
 437     case 20:
 438       {
 439         /* Check that file descriptors >= 3, when inherited, preserve their
 440            isatty() property, part 2 (character devices).  */
 441         ASSERT (dup2 (STDIN_FILENO, 10) >= 0);
 442         int fd_in = 10;
 443 
 444         ASSERT (dup2 (STDOUT_FILENO, 11) >= 0);
 445         int fd_out = 11;
 446 
 447         const char *prog_argv[3] = { prog_path, "20", NULL };
 448         int ret = execute (progname, prog_argv[0], prog_argv, NULL,
 449                            false, false, false, false, true, false, NULL);
 450         #if defined _WIN32 && ! defined __CYGWIN__
 451         ASSERT (ret == 4 + 2 * (_isatty (10) != 0) + (_isatty (11) != 0));
 452         #else
 453         ASSERT (ret == 4 + 2 * (isatty (10) != 0) + (isatty (11) != 0));
 454         #endif
 455 
 456         close (fd_in);
 457         close (fd_out);
 458       }
 459       break;
 460     case 21:
 461       {
 462         /* Check execution in a different directory.  */
 463         rmdir (BASE ".sub");
 464         ASSERT (mkdir (BASE ".sub", 0700) == 0);
 465 
 466         char cwd[1024];
 467         #if defined _WIN32 && ! defined __CYGWIN__
 468         ASSERT (_getcwd (cwd, sizeof (cwd)) != NULL);
 469         #else
 470         ASSERT (getcwd (cwd, sizeof (cwd)) != NULL);
 471         #endif
 472 
 473         const char *prog_argv[4] = { prog_path, "21", cwd, NULL };
 474         int ret = execute (progname, prog_argv[0], prog_argv, BASE ".sub",
 475                            false, false, false, false, true, false, NULL);
 476         ASSERT (ret == 0);
 477 
 478         ASSERT (rmdir (BASE ".sub") == 0);
 479       }
 480       break;
 481     default:
 482       ASSERT (false);
 483     }
 484   return 0;
 485 }

/* [previous][next][first][last][top][bottom][index][help] */