1  /* Verify capture output from a subprocess.
       2     Copyright (C) 2017-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <stdbool.h>
      20  #include <stdio.h>
      21  #include <support/capture_subprocess.h>
      22  #include <support/check.h>
      23  #include <sys/wait.h>
      24  
      25  static void
      26  print_context (const char *context, bool *failed)
      27  {
      28    if (*failed)
      29      /* Do not duplicate message.  */
      30      return;
      31    support_record_failure ();
      32    printf ("error: subprocess failed: %s\n", context);
      33  }
      34  
      35  static void
      36  print_actual_status (struct support_capture_subprocess *proc)
      37  {
      38    if (WIFEXITED (proc->status))
      39      printf ("error:   actual exit status: %d [0x%x]\n",
      40              WEXITSTATUS (proc->status), proc->status);
      41    else if (WIFSIGNALED (proc->status))
      42      printf ("error:   actual termination signal: %d [0x%x]\n",
      43              WTERMSIG (proc->status), proc->status);
      44    else
      45      printf ("error:   actual undecoded exit status: [0x%x]\n", proc->status);
      46  }
      47  
      48  void
      49  support_capture_subprocess_check (struct support_capture_subprocess *proc,
      50                                    const char *context, int status_or_signal,
      51                                    int allowed)
      52  {
      53    TEST_VERIFY ((allowed & sc_allow_none)
      54                 || (allowed & sc_allow_stdout)
      55                 || (allowed & sc_allow_stderr));
      56    TEST_VERIFY (!((allowed & sc_allow_none)
      57                   && ((allowed & sc_allow_stdout)
      58                       || (allowed & sc_allow_stderr))));
      59  
      60    bool failed = false;
      61    if (status_or_signal >= 0)
      62      {
      63        /* Expect regular termination.  */
      64        if (!(WIFEXITED (proc->status)
      65              && WEXITSTATUS (proc->status) == status_or_signal))
      66          {
      67            print_context (context, &failed);
      68            printf ("error:   expected exit status: %d\n", status_or_signal);
      69            print_actual_status (proc);
      70          }
      71      }
      72    else
      73      {
      74        /* status_or_signal < 0.  Expect termination by signal.  */
      75        if (!(WIFSIGNALED (proc->status)
      76              && WTERMSIG (proc->status) == -status_or_signal))
      77          {
      78            print_context (context, &failed);
      79            printf ("error:   expected termination signal: %d\n",
      80                    -status_or_signal);
      81            print_actual_status (proc);
      82          }
      83      }
      84    if (!(allowed & sc_allow_stdout) && proc->out.length != 0)
      85      {
      86        print_context (context, &failed);
      87        printf ("error:   unexpected output from subprocess\n");
      88        fwrite (proc->out.buffer, proc->out.length, 1, stdout);
      89        puts ("\n");
      90      }
      91    if (!(allowed & sc_allow_stderr) && proc->err.length != 0)
      92      {
      93        print_context (context, &failed);
      94        printf ("error:   unexpected error output from subprocess\n");
      95        fwrite (proc->err.buffer, proc->err.length, 1, stdout);
      96        puts ("\n");
      97      }
      98  }